tempest-react-sdk 0.73.0 → 0.75.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 (246) hide show
  1. package/README.md +6 -4
  2. package/dist/br/BrazilMap.module.cjs.map +1 -1
  3. package/dist/br/BrazilMap.module.js.map +1 -1
  4. package/dist/br/MapMarkers.cjs +1 -1
  5. package/dist/br/MapMarkers.cjs.map +1 -1
  6. package/dist/br/MapMarkers.js +19 -22
  7. package/dist/br/MapMarkers.js.map +1 -1
  8. package/dist/br/MunicipalitySearch.cjs +1 -1
  9. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  10. package/dist/br/MunicipalitySearch.js +66 -48
  11. package/dist/br/MunicipalitySearch.js.map +1 -1
  12. package/dist/br/MunicipalitySearch.module.cjs +1 -1
  13. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  14. package/dist/br/MunicipalitySearch.module.js +4 -3
  15. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  16. package/dist/br.d.ts +12 -0
  17. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  18. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  19. package/dist/components/AIChat/AIChatTurn.cjs +1 -1
  20. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  21. package/dist/components/AIChat/AIChatTurn.js +1 -1
  22. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  23. package/dist/components/AppBar/AppBar.cjs +1 -1
  24. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  25. package/dist/components/AppBar/AppBar.js +1 -0
  26. package/dist/components/AppBar/AppBar.js.map +1 -1
  27. package/dist/components/AppBar/AppBar.module.cjs +1 -1
  28. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  29. package/dist/components/AppBar/AppBar.module.js +12 -11
  30. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  31. package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
  32. package/dist/components/AppShell/AppShell.module.js.map +1 -1
  33. package/dist/components/Button/Button.cjs +1 -1
  34. package/dist/components/Button/Button.cjs.map +1 -1
  35. package/dist/components/Button/Button.js +41 -36
  36. package/dist/components/Button/Button.js.map +1 -1
  37. package/dist/components/Button/Button.module.cjs.map +1 -1
  38. package/dist/components/Button/Button.module.js.map +1 -1
  39. package/dist/components/Button/ButtonContent.cjs +2 -0
  40. package/dist/components/Button/ButtonContent.cjs.map +1 -0
  41. package/dist/components/Button/ButtonContent.js +34 -0
  42. package/dist/components/Button/ButtonContent.js.map +1 -0
  43. package/dist/components/Button/ButtonSlot.cjs +2 -0
  44. package/dist/components/Button/ButtonSlot.cjs.map +1 -0
  45. package/dist/components/Button/ButtonSlot.js +36 -0
  46. package/dist/components/Button/ButtonSlot.js.map +1 -0
  47. package/dist/components/Button/button-class.cjs +2 -0
  48. package/dist/components/Button/button-class.cjs.map +1 -0
  49. package/dist/components/Button/button-class.js +13 -0
  50. package/dist/components/Button/button-class.js.map +1 -0
  51. package/dist/components/Button/link-rel.cjs +2 -0
  52. package/dist/components/Button/link-rel.cjs.map +1 -0
  53. package/dist/components/Button/link-rel.js +11 -0
  54. package/dist/components/Button/link-rel.js.map +1 -0
  55. package/dist/components/Button/slot.cjs +2 -0
  56. package/dist/components/Button/slot.cjs.map +1 -0
  57. package/dist/components/Button/slot.js +41 -0
  58. package/dist/components/Button/slot.js.map +1 -0
  59. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  60. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  61. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  62. package/dist/components/Chat/Chat.module.js.map +1 -1
  63. package/dist/components/Collapsible/Collapsible.cjs +1 -1
  64. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  65. package/dist/components/Collapsible/Collapsible.js +1 -1
  66. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  67. package/dist/components/Combobox/Combobox.cjs +1 -1
  68. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  69. package/dist/components/Combobox/Combobox.js +18 -23
  70. package/dist/components/Combobox/Combobox.js.map +1 -1
  71. package/dist/components/Combobox/use-listbox-dismiss.cjs +2 -0
  72. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -0
  73. package/dist/components/Combobox/use-listbox-dismiss.js +34 -0
  74. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -0
  75. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  76. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  77. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  78. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  79. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  80. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  81. package/dist/components/Form/Form.cjs.map +1 -1
  82. package/dist/components/Form/Form.js.map +1 -1
  83. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  84. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  85. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  86. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  87. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  88. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  89. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  90. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  91. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  92. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  93. package/dist/components/Modal/Modal.cjs +1 -1
  94. package/dist/components/Modal/Modal.cjs.map +1 -1
  95. package/dist/components/Modal/Modal.js +1 -1
  96. package/dist/components/Modal/Modal.js.map +1 -1
  97. package/dist/components/Modal/Modal.module.cjs +1 -1
  98. package/dist/components/Modal/Modal.module.cjs.map +1 -1
  99. package/dist/components/Modal/Modal.module.js +1 -1
  100. package/dist/components/Modal/Modal.module.js.map +1 -1
  101. package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
  102. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  103. package/dist/components/MultiSelect/MultiSelect.js +55 -54
  104. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  105. package/dist/components/Navbar/Navbar.cjs +1 -1
  106. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  107. package/dist/components/Navbar/Navbar.js +1 -0
  108. package/dist/components/Navbar/Navbar.js.map +1 -1
  109. package/dist/components/Navbar/Navbar.module.cjs +1 -1
  110. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  111. package/dist/components/Navbar/Navbar.module.js +9 -8
  112. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  113. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  114. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  115. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  116. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  117. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  118. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  119. package/dist/components/Page/Page.cjs +1 -1
  120. package/dist/components/Page/Page.cjs.map +1 -1
  121. package/dist/components/Page/Page.js +23 -39
  122. package/dist/components/Page/Page.js.map +1 -1
  123. package/dist/components/Page/Page.module.cjs +1 -1
  124. package/dist/components/Page/Page.module.cjs.map +1 -1
  125. package/dist/components/Page/Page.module.js +5 -11
  126. package/dist/components/Page/Page.module.js.map +1 -1
  127. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  128. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  129. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  130. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  131. package/dist/components/Reveal/Reveal.cjs +2 -0
  132. package/dist/components/Reveal/Reveal.cjs.map +1 -0
  133. package/dist/components/Reveal/Reveal.js +56 -0
  134. package/dist/components/Reveal/Reveal.js.map +1 -0
  135. package/dist/components/Reveal/Reveal.module.cjs +3 -0
  136. package/dist/components/Reveal/Reveal.module.cjs.map +1 -0
  137. package/dist/components/Reveal/Reveal.module.js +7 -0
  138. package/dist/components/Reveal/Reveal.module.js.map +1 -0
  139. package/dist/components/Reveal/reveal-threshold.cjs +2 -0
  140. package/dist/components/Reveal/reveal-threshold.cjs.map +1 -0
  141. package/dist/components/Reveal/reveal-threshold.js +13 -0
  142. package/dist/components/Reveal/reveal-threshold.js.map +1 -0
  143. package/dist/components/SectionHeader/SectionHeader.cjs +2 -0
  144. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -0
  145. package/dist/components/SectionHeader/SectionHeader.js +66 -0
  146. package/dist/components/SectionHeader/SectionHeader.js.map +1 -0
  147. package/dist/components/SectionHeader/SectionHeader.module.cjs +3 -0
  148. package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -0
  149. package/dist/components/SectionHeader/SectionHeader.module.js +15 -0
  150. package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -0
  151. package/dist/components/Timeline/Timeline.cjs +1 -1
  152. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  153. package/dist/components/Timeline/Timeline.js +22 -15
  154. package/dist/components/Timeline/Timeline.js.map +1 -1
  155. package/dist/components/Timeline/Timeline.module.cjs +1 -1
  156. package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
  157. package/dist/components/Timeline/Timeline.module.js +1 -1
  158. package/dist/components/Timeline/Timeline.module.js.map +1 -1
  159. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  160. package/dist/components/Tour/Tour.module.js.map +1 -1
  161. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  162. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  163. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  164. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  165. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  166. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  167. package/dist/icons/IconPicker.module.cjs.map +1 -1
  168. package/dist/icons/IconPicker.module.js.map +1 -1
  169. package/dist/styles/Reveal.css +2 -0
  170. package/dist/styles/SectionHeader.css +2 -0
  171. package/dist/styles/actions.css +26 -24
  172. package/dist/styles/base.css +3 -1
  173. package/dist/styles/br.css +3 -3
  174. package/dist/styles/chat.css +5 -5
  175. package/dist/styles/component/AIChat.css +3 -3
  176. package/dist/styles/component/AppBar.css +1 -0
  177. package/dist/styles/component/AppShell.css +1 -1
  178. package/dist/styles/component/BrazilMap.css +2 -2
  179. package/dist/styles/component/Button.css +25 -23
  180. package/dist/styles/component/Carousel.css +3 -3
  181. package/dist/styles/component/Chat.css +2 -2
  182. package/dist/styles/component/Dropzone.css +2 -1
  183. package/dist/styles/component/FilterBar.css +2 -2
  184. package/dist/styles/component/FloatingActionButton.css +1 -1
  185. package/dist/styles/component/IconPicker.css +1 -1
  186. package/dist/styles/component/ImageCropper.css +2 -2
  187. package/dist/styles/component/ListTile.css +1 -1
  188. package/dist/styles/component/Markdown.css +1 -1
  189. package/dist/styles/component/Menubar.css +1 -1
  190. package/dist/styles/component/Modal.css +2 -2
  191. package/dist/styles/component/MunicipalitySearch.css +1 -1
  192. package/dist/styles/component/Navbar.css +1 -0
  193. package/dist/styles/component/NavigationMenu.css +1 -1
  194. package/dist/styles/component/NavigationRail.css +1 -1
  195. package/dist/styles/component/NotificationCenter.css +3 -3
  196. package/dist/styles/component/Page.css +0 -6
  197. package/dist/styles/component/PasswordInput.css +1 -1
  198. package/dist/styles/component/PinInput.css +1 -1
  199. package/dist/styles/component/Reveal.css +9 -0
  200. package/dist/styles/component/SectionHeader.css +9 -0
  201. package/dist/styles/component/Timeline.css +5 -5
  202. package/dist/styles/component/Tour.css +2 -2
  203. package/dist/styles/component/TrajectoryMap.css +1 -1
  204. package/dist/styles/component/Transfer.css +2 -2
  205. package/dist/styles/component/VirtualTable.css +2 -2
  206. package/dist/styles/core.css +3 -1
  207. package/dist/styles/data.css +15 -15
  208. package/dist/styles/feedback.css +3 -3
  209. package/dist/styles/forms.css +6 -5
  210. package/dist/styles/geo.css +1 -1
  211. package/dist/styles/icons.css +1 -1
  212. package/dist/styles/inverse.css +372 -0
  213. package/dist/styles/layout.css +9 -7
  214. package/dist/styles/manifest.json +14 -1
  215. package/dist/styles/navigation.css +8 -6
  216. package/dist/styles/overlay.css +2 -2
  217. package/dist/styles/utility.css +8 -0
  218. package/dist/styles.css +1 -1
  219. package/dist/tempest-react-sdk.cjs +1 -1
  220. package/dist/tempest-react-sdk.d.ts +473 -11
  221. package/dist/tempest-react-sdk.js +350 -346
  222. package/dist/theme/create-theme.cjs +3 -3
  223. package/dist/theme/create-theme.cjs.map +1 -1
  224. package/dist/theme/create-theme.js +72 -55
  225. package/dist/theme/create-theme.js.map +1 -1
  226. package/dist/theme/inverse-render.cjs +3 -0
  227. package/dist/theme/inverse-render.cjs.map +1 -0
  228. package/dist/theme/inverse-render.js +10 -0
  229. package/dist/theme/inverse-render.js.map +1 -0
  230. package/dist/theme/inverse-restore.cjs +5 -0
  231. package/dist/theme/inverse-restore.cjs.map +1 -0
  232. package/dist/theme/inverse-restore.js +30 -0
  233. package/dist/theme/inverse-restore.js.map +1 -0
  234. package/dist/theme/inverse-surface.cjs +2 -0
  235. package/dist/theme/inverse-surface.cjs.map +1 -0
  236. package/dist/theme/inverse-surface.js +255 -0
  237. package/dist/theme/inverse-surface.js.map +1 -0
  238. package/dist/theme/status-tokens.cjs +2 -0
  239. package/dist/theme/status-tokens.cjs.map +1 -0
  240. package/dist/theme/status-tokens.js +15 -0
  241. package/dist/theme/status-tokens.js.map +1 -0
  242. package/dist/vite/create-vite-config.cjs +1 -1
  243. package/dist/vite/create-vite-config.cjs.map +1 -1
  244. package/dist/vite/create-vite-config.js +6 -4
  245. package/dist/vite/create-vite-config.js.map +1 -1
  246. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Dropzone.module.js","names":[],"sources":["../../../src/components/Dropzone/Dropzone.module.css"],"sourcesContent":[".zone {\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n min-height: 120px;\n padding: var(--tempest-space-6, 24px);\n border: 2px dashed var(--tempest-border);\n border-radius: var(--tempest-radius-lg, 12px);\n background: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n transition:\n border-color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.zone:hover,\n.zone:focus-visible {\n border-color: var(--tempest-primary);\n color: var(--tempest-text);\n outline: none;\n}\n\n.dragging {\n border-color: var(--tempest-primary);\n background: var(--tempest-primary-soft);\n color: var(--tempest-text);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.input {\n display: none;\n}\n\n.prompt {\n line-height: 1.4;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Dropzone.module.js","names":[],"sources":["../../../src/components/Dropzone/Dropzone.module.css"],"sourcesContent":[".zone {\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n min-height: 120px;\n padding: var(--tempest-space-6, 24px);\n border: 2px dashed var(--tempest-border);\n border-radius: var(--tempest-radius-lg, 12px);\n background: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n transition:\n border-color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.zone:hover,\n.zone:focus-visible {\n border-color: var(--tempest-primary);\n color: var(--tempest-text);\n}\n\n.zone:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.dragging {\n border-color: var(--tempest-primary);\n background: var(--tempest-primary-soft);\n color: var(--tempest-text);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.input {\n display: none;\n}\n\n.prompt {\n line-height: 1.4;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterBar.module.cjs","names":[],"sources":["../../../src/components/FilterBar/FilterBar.module.css"],"sourcesContent":[".bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-1) var(--tempest-space-1) var(--tempest-space-1)\n var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.empty {\n color: var(--tempest-text-muted);\n}\n\n.remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\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.remove:hover {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text);\n}\n\n/*\n * The editor wraps as a whole on a narrow screen: field, condition and value each\n * keep a usable width instead of shrinking into three unreadable boxes.\n */\n.editor {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n.control {\n display: inline-flex;\n min-width: 0;\n}\n\n.select,\n.input {\n min-width: 7rem;\n max-width: 14rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n}\n\n.select:focus-visible,\n.input:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -1px;\n}\n\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.primary,\n.secondary,\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border-radius: var(--tempest-radius-md);\n font: inherit;\n cursor: pointer;\n}\n\n.primary {\n border: none;\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.secondary {\n border: 1px dashed var(--tempest-border-strong);\n background-color: transparent;\n color: var(--tempest-text);\n}\n\n.secondary:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.ghost {\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n text-decoration: underline;\n}\n\n.primary:focus-visible,\n.secondary:focus-visible,\n.ghost:focus-visible,\n.remove:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 1px;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"FilterBar.module.cjs","names":[],"sources":["../../../src/components/FilterBar/FilterBar.module.css"],"sourcesContent":[".bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-1) var(--tempest-space-1) var(--tempest-space-1)\n var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.empty {\n color: var(--tempest-text-muted);\n}\n\n.remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\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.remove:hover {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text);\n}\n\n/*\n * The editor wraps as a whole on a narrow screen: field, condition and value each\n * keep a usable width instead of shrinking into three unreadable boxes.\n */\n.editor {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n.control {\n display: inline-flex;\n min-width: 0;\n}\n\n.select,\n.input {\n min-width: 7rem;\n max-width: 14rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n}\n\n.select:focus-visible,\n.input:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.primary,\n.secondary,\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border-radius: var(--tempest-radius-md);\n font: inherit;\n cursor: pointer;\n}\n\n.primary {\n border: none;\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.secondary {\n border: 1px dashed var(--tempest-border-strong);\n background-color: transparent;\n color: var(--tempest-text);\n}\n\n.secondary:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.ghost {\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n text-decoration: underline;\n}\n\n.primary:focus-visible,\n.secondary:focus-visible,\n.ghost:focus-visible,\n.remove:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 1px;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterBar.module.js","names":[],"sources":["../../../src/components/FilterBar/FilterBar.module.css"],"sourcesContent":[".bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-1) var(--tempest-space-1) var(--tempest-space-1)\n var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.empty {\n color: var(--tempest-text-muted);\n}\n\n.remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\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.remove:hover {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text);\n}\n\n/*\n * The editor wraps as a whole on a narrow screen: field, condition and value each\n * keep a usable width instead of shrinking into three unreadable boxes.\n */\n.editor {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n.control {\n display: inline-flex;\n min-width: 0;\n}\n\n.select,\n.input {\n min-width: 7rem;\n max-width: 14rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n}\n\n.select:focus-visible,\n.input:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -1px;\n}\n\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.primary,\n.secondary,\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border-radius: var(--tempest-radius-md);\n font: inherit;\n cursor: pointer;\n}\n\n.primary {\n border: none;\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.secondary {\n border: 1px dashed var(--tempest-border-strong);\n background-color: transparent;\n color: var(--tempest-text);\n}\n\n.secondary:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.ghost {\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n text-decoration: underline;\n}\n\n.primary:focus-visible,\n.secondary:focus-visible,\n.ghost:focus-visible,\n.remove:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 1px;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"FilterBar.module.js","names":[],"sources":["../../../src/components/FilterBar/FilterBar.module.css"],"sourcesContent":[".bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-1) var(--tempest-space-1) var(--tempest-space-1)\n var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.empty {\n color: var(--tempest-text-muted);\n}\n\n.remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\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.remove:hover {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text);\n}\n\n/*\n * The editor wraps as a whole on a narrow screen: field, condition and value each\n * keep a usable width instead of shrinking into three unreadable boxes.\n */\n.editor {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n.control {\n display: inline-flex;\n min-width: 0;\n}\n\n.select,\n.input {\n min-width: 7rem;\n max-width: 14rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n}\n\n.select:focus-visible,\n.input:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.primary,\n.secondary,\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border-radius: var(--tempest-radius-md);\n font: inherit;\n cursor: pointer;\n}\n\n.primary {\n border: none;\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.secondary {\n border: 1px dashed var(--tempest-border-strong);\n background-color: transparent;\n color: var(--tempest-text);\n}\n\n.secondary:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.ghost {\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n text-decoration: underline;\n}\n\n.primary:focus-visible,\n.secondary:focus-visible,\n.ghost:focus-visible,\n.remove:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 1px;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingActionButton.module.cjs","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.module.css"],"sourcesContent":[".fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n border: 0;\n cursor: pointer;\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n box-shadow: var(--tempest-shadow-lg);\n transition:\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n box-shadow var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n transform var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.fab:active {\n transform: scale(0.96);\n}\n\n.fab:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, var(--tempest-primary));\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.fab:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n box-shadow: var(--tempest-shadow-sm);\n}\n\n/* Variants */\n.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:hover:not(:disabled) {\n background: var(--tempest-primary-active, var(--tempest-primary));\n}\n\n.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.surface:hover:not(:disabled) {\n background: var(--tempest-surface-2);\n}\n\n/* Round (icon-only) sizing */\n.round.sm {\n width: 40px;\n height: 40px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.md {\n width: 56px;\n height: 56px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.lg {\n width: 72px;\n height: 72px;\n border-radius: var(--tempest-radius-xl);\n}\n\n/* Extended (pill) sizing */\n.extended {\n border-radius: var(--tempest-radius-full);\n}\n\n.extended.sm {\n height: 40px;\n padding: 0 var(--tempest-space-4);\n font-size: var(--tempest-text-sm);\n}\n\n.extended.md {\n height: 56px;\n padding: 0 var(--tempest-space-5);\n font-size: var(--tempest-text-md);\n}\n\n.extended.lg {\n height: 72px;\n padding: 0 var(--tempest-space-6);\n font-size: var(--tempest-text-lg);\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 24px;\n}\n\n.round.sm .icon {\n font-size: 20px;\n}\n\n.round.lg .icon {\n font-size: 32px;\n}\n\n.label {\n line-height: 1;\n}\n\n/* Positioning */\n.fixed {\n position: fixed;\n z-index: var(--tempest-z-dropdown, 1000);\n}\n\n.bottomRight {\n right: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n\n.bottomLeft {\n left: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"FloatingActionButton.module.cjs","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.module.css"],"sourcesContent":[".fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n border: 0;\n cursor: pointer;\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n box-shadow: var(--tempest-shadow-lg);\n transition:\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n box-shadow var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n transform var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.fab:active {\n transform: scale(0.96);\n}\n\n.fab:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, currentColor);\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.fab:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n box-shadow: var(--tempest-shadow-sm);\n}\n\n/* Variants */\n.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:hover:not(:disabled) {\n background: var(--tempest-primary-active, var(--tempest-primary));\n}\n\n.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.surface:hover:not(:disabled) {\n background: var(--tempest-surface-2);\n}\n\n/* Round (icon-only) sizing */\n.round.sm {\n width: 40px;\n height: 40px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.md {\n width: 56px;\n height: 56px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.lg {\n width: 72px;\n height: 72px;\n border-radius: var(--tempest-radius-xl);\n}\n\n/* Extended (pill) sizing */\n.extended {\n border-radius: var(--tempest-radius-full);\n}\n\n.extended.sm {\n height: 40px;\n padding: 0 var(--tempest-space-4);\n font-size: var(--tempest-text-sm);\n}\n\n.extended.md {\n height: 56px;\n padding: 0 var(--tempest-space-5);\n font-size: var(--tempest-text-md);\n}\n\n.extended.lg {\n height: 72px;\n padding: 0 var(--tempest-space-6);\n font-size: var(--tempest-text-lg);\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 24px;\n}\n\n.round.sm .icon {\n font-size: 20px;\n}\n\n.round.lg .icon {\n font-size: 32px;\n}\n\n.label {\n line-height: 1;\n}\n\n/* Positioning */\n.fixed {\n position: fixed;\n z-index: var(--tempest-z-dropdown, 1000);\n}\n\n.bottomRight {\n right: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n\n.bottomLeft {\n left: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingActionButton.module.js","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.module.css"],"sourcesContent":[".fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n border: 0;\n cursor: pointer;\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n box-shadow: var(--tempest-shadow-lg);\n transition:\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n box-shadow var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n transform var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.fab:active {\n transform: scale(0.96);\n}\n\n.fab:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, var(--tempest-primary));\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.fab:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n box-shadow: var(--tempest-shadow-sm);\n}\n\n/* Variants */\n.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:hover:not(:disabled) {\n background: var(--tempest-primary-active, var(--tempest-primary));\n}\n\n.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.surface:hover:not(:disabled) {\n background: var(--tempest-surface-2);\n}\n\n/* Round (icon-only) sizing */\n.round.sm {\n width: 40px;\n height: 40px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.md {\n width: 56px;\n height: 56px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.lg {\n width: 72px;\n height: 72px;\n border-radius: var(--tempest-radius-xl);\n}\n\n/* Extended (pill) sizing */\n.extended {\n border-radius: var(--tempest-radius-full);\n}\n\n.extended.sm {\n height: 40px;\n padding: 0 var(--tempest-space-4);\n font-size: var(--tempest-text-sm);\n}\n\n.extended.md {\n height: 56px;\n padding: 0 var(--tempest-space-5);\n font-size: var(--tempest-text-md);\n}\n\n.extended.lg {\n height: 72px;\n padding: 0 var(--tempest-space-6);\n font-size: var(--tempest-text-lg);\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 24px;\n}\n\n.round.sm .icon {\n font-size: 20px;\n}\n\n.round.lg .icon {\n font-size: 32px;\n}\n\n.label {\n line-height: 1;\n}\n\n/* Positioning */\n.fixed {\n position: fixed;\n z-index: var(--tempest-z-dropdown, 1000);\n}\n\n.bottomRight {\n right: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n\n.bottomLeft {\n left: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"FloatingActionButton.module.js","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.module.css"],"sourcesContent":[".fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n border: 0;\n cursor: pointer;\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n box-shadow: var(--tempest-shadow-lg);\n transition:\n background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n box-shadow var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out),\n transform var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.fab:active {\n transform: scale(0.96);\n}\n\n.fab:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, currentColor);\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.fab:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n box-shadow: var(--tempest-shadow-sm);\n}\n\n/* Variants */\n.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.primary:hover:not(:disabled) {\n background: var(--tempest-primary-active, var(--tempest-primary));\n}\n\n.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.surface:hover:not(:disabled) {\n background: var(--tempest-surface-2);\n}\n\n/* Round (icon-only) sizing */\n.round.sm {\n width: 40px;\n height: 40px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.md {\n width: 56px;\n height: 56px;\n border-radius: var(--tempest-radius-lg);\n}\n\n.round.lg {\n width: 72px;\n height: 72px;\n border-radius: var(--tempest-radius-xl);\n}\n\n/* Extended (pill) sizing */\n.extended {\n border-radius: var(--tempest-radius-full);\n}\n\n.extended.sm {\n height: 40px;\n padding: 0 var(--tempest-space-4);\n font-size: var(--tempest-text-sm);\n}\n\n.extended.md {\n height: 56px;\n padding: 0 var(--tempest-space-5);\n font-size: var(--tempest-text-md);\n}\n\n.extended.lg {\n height: 72px;\n padding: 0 var(--tempest-space-6);\n font-size: var(--tempest-text-lg);\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 24px;\n}\n\n.round.sm .icon {\n font-size: 20px;\n}\n\n.round.lg .icon {\n font-size: 32px;\n}\n\n.label {\n line-height: 1;\n}\n\n/* Positioning */\n.fixed {\n position: fixed;\n z-index: var(--tempest-z-dropdown, 1000);\n}\n\n.bottomRight {\n right: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n\n.bottomLeft {\n left: var(--tempest-space-4);\n bottom: calc(var(--tempest-space-4) + env(safe-area-inset-bottom, 0));\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.cjs","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":"2HAiBA,SAAS,EAAW,EAAkC,EAA0B,CAE5E,OADI,IAAQ,IAAA,GAAkB,GAAG,EAAW,EAAE,IACvC,OAAO,GAAQ,SAAW,GAAG,EAAM,EAAE,IAAM,CACtD,CAEA,SAAS,EAAe,EAA8C,CAElE,OADI,IAAY,IAAA,GAAkB,4BAC3B,OAAO,GAAY,SAAW,UAAU,EAAQ,mBAAqB,CAChF,CAkBA,IAAa,GAAA,EAAO,EAAA,WAAA,CAAuC,SACvD,CAAE,SAAS,QAAS,UAAS,MAAK,YAAW,QAAO,WAAU,GAAG,GACjE,EACF,CACE,IAAM,EAA4B,CAC9B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,KAC3E,GAAG,CACP,EACA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACS,MACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAS,CAAS,EACpD,MAAO,EACP,GAAI,EAEH,UACC,CAAA,CAEd,CAAC,EAmBD,SAAgB,EAAY,CACxB,QACA,cACA,SAAS,QACT,UACA,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA2B,CAC7B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,IAC/E,EACA,OACI,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAU,QAAO,GAAI,EAArE,SAAA,EACM,GAAS,KACP,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,cAA1B,SAAA,CACK,IAAS,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,aAAe,SAAA,CAAU,CAAA,EACxD,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,mBAAqB,SAAA,CAAe,CAAA,CACrE,CAEZ,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,EAAA,QAAO,EAAO,EAAG,MAAO,EAC1D,UACA,CAAA,CACA,GAEjB,CAqBA,SAAgB,EAAQ,CAAE,MAAK,YAAW,QAAO,WAAU,GAAG,GAAuB,CACjF,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAAG,MAAO,EAAY,GAAI,EAC7D,UACA,CAAA,CAEb,CAkBA,SAAgB,EAAY,CACxB,QAAQ,MACR,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAQ,CAAS,EAAG,MAAO,EAAY,GAAI,EAChF,UACA,CAAA,CAEb"}
1
+ {"version":3,"file":"Form.cjs","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * The header is deliberately not a `SectionHeader`: a field group sits one step\n * below a page section, and its title is `text-lg` / semibold / `leading-snug`\n * with `space-3` below, against `text-2xl` / bold / `leading-tight` with\n * `space-5` for `SectionHeader`. Sharing the component would either grow every\n * form group to page-section size or add a size switch to `SectionHeader` that\n * only this caller uses.\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":"2HAiBA,SAAS,EAAW,EAAkC,EAA0B,CAE5E,OADI,IAAQ,IAAA,GAAkB,GAAG,EAAW,EAAE,IACvC,OAAO,GAAQ,SAAW,GAAG,EAAM,EAAE,IAAM,CACtD,CAEA,SAAS,EAAe,EAA8C,CAElE,OADI,IAAY,IAAA,GAAkB,4BAC3B,OAAO,GAAY,SAAW,UAAU,EAAQ,mBAAqB,CAChF,CAkBA,IAAa,GAAA,EAAO,EAAA,WAAA,CAAuC,SACvD,CAAE,SAAS,QAAS,UAAS,MAAK,YAAW,QAAO,WAAU,GAAG,GACjE,EACF,CACE,IAAM,EAA4B,CAC9B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,KAC3E,GAAG,CACP,EACA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACS,MACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAS,CAAS,EACpD,MAAO,EACP,GAAI,EAEH,UACC,CAAA,CAEd,CAAC,EA0BD,SAAgB,EAAY,CACxB,QACA,cACA,SAAS,QACT,UACA,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA2B,CAC7B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,IAC/E,EACA,OACI,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAU,QAAO,GAAI,EAArE,SAAA,EACM,GAAS,KACP,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,cAA1B,SAAA,CACK,IAAS,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,aAAe,SAAA,CAAU,CAAA,EACxD,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,mBAAqB,SAAA,CAAe,CAAA,CACrE,CAEZ,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,EAAA,QAAO,EAAO,EAAG,MAAO,EAC1D,UACA,CAAA,CACA,GAEjB,CAqBA,SAAgB,EAAQ,CAAE,MAAK,YAAW,QAAO,WAAU,GAAG,GAAuB,CACjF,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAAG,MAAO,EAAY,GAAI,EAC7D,UACA,CAAA,CAEb,CAkBA,SAAgB,EAAY,CACxB,QAAQ,MACR,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAQ,CAAS,EAAG,MAAO,EAAY,GAAI,EAChF,UACA,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAS,EAAW,GAAkC,GAA0B;CAE5E,OADI,MAAQ,KAAA,IAAkB,GAAG,IAAW,EAAE,MACvC,OAAO,KAAQ,WAAW,GAAG,IAAM,EAAE,MAAM;AACtD;AAEA,SAAS,EAAe,GAA8C;CAElE,OADI,MAAY,KAAA,IAAkB,8BAC3B,OAAO,KAAY,WAAW,UAAU,EAAQ,qBAAqB;AAChF;AAkBA,IAAa,IAAO,EAAuC,SACvD,EAAE,YAAS,SAAS,YAAS,QAAK,cAAW,UAAO,aAAU,GAAG,KACjE,GACF;CACE,IAAM,IAA4B;EAC9B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;EAC3E,GAAG;CACP;CACA,OACI,kBAAC,QAAD;EACS;EACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAS,CAAS;EACpD,OAAO;EACP,GAAI;EAEH;CACC,CAAA;AAEd,CAAC;AAmBD,SAAgB,EAAY,EACxB,UACA,gBACA,YAAS,SACT,YACA,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA2B;EAC7B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;CAC/E;CACA,OACI,kBAAC,WAAD;EAAS,WAAW,EAAG,EAAO,SAAS,CAAS;EAAU;EAAO,GAAI;EAArE,UAAA,EACM,KAAS,MACP,kBAAC,UAAD;GAAQ,WAAW,EAAO;GAA1B,UAAA,CACK,KAAS,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAe,UAAA;GAAU,CAAA,GACxD,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;IAAqB,UAAA;GAAe,CAAA,CACrE;EAEZ,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,aAAa,EAAO,EAAO;GAAG,OAAO;GAC1D;EACA,CAAA,CACA;;AAEjB;AAqBA,SAAgB,EAAQ,EAAE,QAAK,cAAW,UAAO,aAAU,GAAG,KAAuB;CACjF,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,OAAO;EAAY,GAAI;EAC7D;CACA,CAAA;AAEb;AAkBA,SAAgB,EAAY,EACxB,WAAQ,OACR,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAQ,CAAS;EAAG,OAAO;EAAY,GAAI;EAChF;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * The header is deliberately not a `SectionHeader`: a field group sits one step\n * below a page section, and its title is `text-lg` / semibold / `leading-snug`\n * with `space-3` below, against `text-2xl` / bold / `leading-tight` with\n * `space-5` for `SectionHeader`. Sharing the component would either grow every\n * form group to page-section size or add a size switch to `SectionHeader` that\n * only this caller uses.\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAS,EAAW,GAAkC,GAA0B;CAE5E,OADI,MAAQ,KAAA,IAAkB,GAAG,IAAW,EAAE,MACvC,OAAO,KAAQ,WAAW,GAAG,IAAM,EAAE,MAAM;AACtD;AAEA,SAAS,EAAe,GAA8C;CAElE,OADI,MAAY,KAAA,IAAkB,8BAC3B,OAAO,KAAY,WAAW,UAAU,EAAQ,qBAAqB;AAChF;AAkBA,IAAa,IAAO,EAAuC,SACvD,EAAE,YAAS,SAAS,YAAS,QAAK,cAAW,UAAO,aAAU,GAAG,KACjE,GACF;CACE,IAAM,IAA4B;EAC9B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;EAC3E,GAAG;CACP;CACA,OACI,kBAAC,QAAD;EACS;EACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAS,CAAS;EACpD,OAAO;EACP,GAAI;EAEH;CACC,CAAA;AAEd,CAAC;AA0BD,SAAgB,EAAY,EACxB,UACA,gBACA,YAAS,SACT,YACA,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA2B;EAC7B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;CAC/E;CACA,OACI,kBAAC,WAAD;EAAS,WAAW,EAAG,EAAO,SAAS,CAAS;EAAU;EAAO,GAAI;EAArE,UAAA,EACM,KAAS,MACP,kBAAC,UAAD;GAAQ,WAAW,EAAO;GAA1B,UAAA,CACK,KAAS,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAe,UAAA;GAAU,CAAA,GACxD,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;IAAqB,UAAA;GAAe,CAAA,CACrE;EAEZ,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,aAAa,EAAO,EAAO;GAAG,OAAO;GAC1D;EACA,CAAA,CACA;;AAEjB;AAqBA,SAAgB,EAAQ,EAAE,QAAK,cAAW,UAAO,aAAU,GAAG,KAAuB;CACjF,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,OAAO;EAAY,GAAI;EAC7D;CACA,CAAA;AAEb;AAkBA,SAAgB,EAAY,EACxB,WAAQ,OACR,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAQ,CAAS;EAAG,OAAO;EAAY,GAAI;EAChF;CACA,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageCropper.module.cjs","names":[],"sources":["../../../src/components/ImageCropper/ImageCropper.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n max-width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.frame {\n position: relative;\n width: 100%;\n overflow: hidden;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n /*\n * `grab` rather than `move`: nothing is being moved to a destination, the\n * image is being dragged under a fixed frame.\n */\n cursor: grab;\n /*\n * The frame owns dragging on touch, so the browser must not also scroll the\n * page from the same gesture.\n */\n touch-action: none;\n user-select: none;\n}\n\n.frame:active {\n cursor: grabbing;\n}\n\n.frame:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.circle {\n border-radius: var(--tempest-radius-full);\n}\n\n.image {\n position: absolute;\n top: 50%;\n left: 50%;\n /*\n * Both `max-*`, not just the width. The size is set inline from the zoom, so\n * either cap silently overrides it — and an app reset carrying\n * `img { max-height: 100% }` is enough, since a 0-0-1 element rule meets no\n * competition here. The failure is worse than it looks: `crop()` builds its\n * rectangle from `computeCropRect({ image: natural, ... })` and never reads the\n * rendered element, so the export stays correct while the preview is squashed\n * on one axis. The user drags against a distorted image and gets a framing they\n * never saw. A component that sizes itself inline owns neutralising both caps.\n */\n max-width: none;\n max-height: none;\n pointer-events: none;\n /*\n * Centring lives in `translate` and the pan in the inline `transform`, which\n * are separate CSS properties applied in that order. Keeping them apart means\n * a pan is just `transform: translate(x, y)` — it never has to re-derive the\n * `-50% -50%` centring, and the two cannot overwrite each other.\n */\n translate: -50% -50%;\n}\n\n.controls {\n display: flex;\n /*\n * Wraps rather than squeezing. The zoom slider is the flexible item, so on a\n * narrow row it is the one that gives — and a range input has no useful floor\n * of its own, so it gave all the way to `width: 0`, leaving the thumb alone and\n * no visible focus ring while the button beside it kept both. Measured at 390px\n * with a crowded row. Wrapping moves the slider to its own line instead.\n */\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.zoom {\n /*\n * `min-width: 0` is what let it collapse to nothing: it exists to let a flex\n * item shrink past its min-content size, which for a range input is the whole\n * control. A real floor keeps the slider draggable and its focus ring visible;\n * the wrap on `.controls` is what absorbs the width this refuses to give up.\n */\n flex: 1 1 6rem;\n min-width: 6rem;\n accent-color: var(--tempest-primary);\n}\n\n.zoom:disabled {\n opacity: 0.5;\n}\n\n.reset {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .reset:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.reset:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.reset:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.hint {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.hint kbd {\n padding: 0 var(--tempest-space-1);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface);\n font-family: var(--tempest-font-mono, monospace);\n font-size: inherit;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"ImageCropper.module.cjs","names":[],"sources":["../../../src/components/ImageCropper/ImageCropper.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n max-width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.frame {\n position: relative;\n width: 100%;\n overflow: hidden;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n /*\n * `grab` rather than `move`: nothing is being moved to a destination, the\n * image is being dragged under a fixed frame.\n */\n cursor: grab;\n /*\n * The frame owns dragging on touch, so the browser must not also scroll the\n * page from the same gesture.\n */\n touch-action: none;\n user-select: none;\n}\n\n.frame:active {\n cursor: grabbing;\n}\n\n.frame:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.circle {\n border-radius: var(--tempest-radius-full);\n}\n\n.image {\n position: absolute;\n top: 50%;\n left: 50%;\n /*\n * Both `max-*`, not just the width. The size is set inline from the zoom, so\n * either cap silently overrides it — and an app reset carrying\n * `img { max-height: 100% }` is enough, since a 0-0-1 element rule meets no\n * competition here. The failure is worse than it looks: `crop()` builds its\n * rectangle from `computeCropRect({ image: natural, ... })` and never reads the\n * rendered element, so the export stays correct while the preview is squashed\n * on one axis. The user drags against a distorted image and gets a framing they\n * never saw. A component that sizes itself inline owns neutralising both caps.\n */\n max-width: none;\n max-height: none;\n pointer-events: none;\n /*\n * Centring lives in `translate` and the pan in the inline `transform`, which\n * are separate CSS properties applied in that order. Keeping them apart means\n * a pan is just `transform: translate(x, y)` — it never has to re-derive the\n * `-50% -50%` centring, and the two cannot overwrite each other.\n */\n translate: -50% -50%;\n}\n\n.controls {\n display: flex;\n /*\n * Wraps rather than squeezing. The zoom slider is the flexible item, so on a\n * narrow row it is the one that gives — and a range input has no useful floor\n * of its own, so it gave all the way to `width: 0`, leaving the thumb alone and\n * no visible focus ring while the button beside it kept both. Measured at 390px\n * with a crowded row. Wrapping moves the slider to its own line instead.\n */\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.zoom {\n /*\n * `min-width: 0` is what let it collapse to nothing: it exists to let a flex\n * item shrink past its min-content size, which for a range input is the whole\n * control. A real floor keeps the slider draggable and its focus ring visible;\n * the wrap on `.controls` is what absorbs the width this refuses to give up.\n */\n flex: 1 1 6rem;\n min-width: 6rem;\n accent-color: var(--tempest-primary);\n}\n\n.zoom:disabled {\n opacity: 0.5;\n}\n\n.reset {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .reset:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.reset:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.reset:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.hint {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.hint kbd {\n padding: 0 var(--tempest-space-1);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface);\n font-family: var(--tempest-font-mono, monospace);\n font-size: inherit;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageCropper.module.js","names":[],"sources":["../../../src/components/ImageCropper/ImageCropper.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n max-width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.frame {\n position: relative;\n width: 100%;\n overflow: hidden;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n /*\n * `grab` rather than `move`: nothing is being moved to a destination, the\n * image is being dragged under a fixed frame.\n */\n cursor: grab;\n /*\n * The frame owns dragging on touch, so the browser must not also scroll the\n * page from the same gesture.\n */\n touch-action: none;\n user-select: none;\n}\n\n.frame:active {\n cursor: grabbing;\n}\n\n.frame:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.circle {\n border-radius: var(--tempest-radius-full);\n}\n\n.image {\n position: absolute;\n top: 50%;\n left: 50%;\n /*\n * Both `max-*`, not just the width. The size is set inline from the zoom, so\n * either cap silently overrides it — and an app reset carrying\n * `img { max-height: 100% }` is enough, since a 0-0-1 element rule meets no\n * competition here. The failure is worse than it looks: `crop()` builds its\n * rectangle from `computeCropRect({ image: natural, ... })` and never reads the\n * rendered element, so the export stays correct while the preview is squashed\n * on one axis. The user drags against a distorted image and gets a framing they\n * never saw. A component that sizes itself inline owns neutralising both caps.\n */\n max-width: none;\n max-height: none;\n pointer-events: none;\n /*\n * Centring lives in `translate` and the pan in the inline `transform`, which\n * are separate CSS properties applied in that order. Keeping them apart means\n * a pan is just `transform: translate(x, y)` — it never has to re-derive the\n * `-50% -50%` centring, and the two cannot overwrite each other.\n */\n translate: -50% -50%;\n}\n\n.controls {\n display: flex;\n /*\n * Wraps rather than squeezing. The zoom slider is the flexible item, so on a\n * narrow row it is the one that gives — and a range input has no useful floor\n * of its own, so it gave all the way to `width: 0`, leaving the thumb alone and\n * no visible focus ring while the button beside it kept both. Measured at 390px\n * with a crowded row. Wrapping moves the slider to its own line instead.\n */\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.zoom {\n /*\n * `min-width: 0` is what let it collapse to nothing: it exists to let a flex\n * item shrink past its min-content size, which for a range input is the whole\n * control. A real floor keeps the slider draggable and its focus ring visible;\n * the wrap on `.controls` is what absorbs the width this refuses to give up.\n */\n flex: 1 1 6rem;\n min-width: 6rem;\n accent-color: var(--tempest-primary);\n}\n\n.zoom:disabled {\n opacity: 0.5;\n}\n\n.reset {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .reset:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.reset:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.reset:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.hint {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.hint kbd {\n padding: 0 var(--tempest-space-1);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface);\n font-family: var(--tempest-font-mono, monospace);\n font-size: inherit;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"ImageCropper.module.js","names":[],"sources":["../../../src/components/ImageCropper/ImageCropper.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n max-width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.frame {\n position: relative;\n width: 100%;\n overflow: hidden;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n /*\n * `grab` rather than `move`: nothing is being moved to a destination, the\n * image is being dragged under a fixed frame.\n */\n cursor: grab;\n /*\n * The frame owns dragging on touch, so the browser must not also scroll the\n * page from the same gesture.\n */\n touch-action: none;\n user-select: none;\n}\n\n.frame:active {\n cursor: grabbing;\n}\n\n.frame:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.circle {\n border-radius: var(--tempest-radius-full);\n}\n\n.image {\n position: absolute;\n top: 50%;\n left: 50%;\n /*\n * Both `max-*`, not just the width. The size is set inline from the zoom, so\n * either cap silently overrides it — and an app reset carrying\n * `img { max-height: 100% }` is enough, since a 0-0-1 element rule meets no\n * competition here. The failure is worse than it looks: `crop()` builds its\n * rectangle from `computeCropRect({ image: natural, ... })` and never reads the\n * rendered element, so the export stays correct while the preview is squashed\n * on one axis. The user drags against a distorted image and gets a framing they\n * never saw. A component that sizes itself inline owns neutralising both caps.\n */\n max-width: none;\n max-height: none;\n pointer-events: none;\n /*\n * Centring lives in `translate` and the pan in the inline `transform`, which\n * are separate CSS properties applied in that order. Keeping them apart means\n * a pan is just `transform: translate(x, y)` — it never has to re-derive the\n * `-50% -50%` centring, and the two cannot overwrite each other.\n */\n translate: -50% -50%;\n}\n\n.controls {\n display: flex;\n /*\n * Wraps rather than squeezing. The zoom slider is the flexible item, so on a\n * narrow row it is the one that gives — and a range input has no useful floor\n * of its own, so it gave all the way to `width: 0`, leaving the thumb alone and\n * no visible focus ring while the button beside it kept both. Measured at 390px\n * with a crowded row. Wrapping moves the slider to its own line instead.\n */\n flex-wrap: wrap;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.zoom {\n /*\n * `min-width: 0` is what let it collapse to nothing: it exists to let a flex\n * item shrink past its min-content size, which for a range input is the whole\n * control. A real floor keeps the slider draggable and its focus ring visible;\n * the wrap on `.controls` is what absorbs the width this refuses to give up.\n */\n flex: 1 1 6rem;\n min-width: 6rem;\n accent-color: var(--tempest-primary);\n}\n\n.zoom:disabled {\n opacity: 0.5;\n}\n\n.reset {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .reset:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.reset:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.reset:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.hint {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.hint kbd {\n padding: 0 var(--tempest-space-1);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface);\n font-family: var(--tempest-font-mono, monospace);\n font-size: inherit;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"InstallButton.cjs","names":[],"sources":["../../../src/components/InstallButton/InstallButton.tsx"],"sourcesContent":["import { useId, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"@/components/Button\";\nimport { useInstallPrompt } from \"@/hooks/use-install-prompt\";\nimport { cn } from \"@/utils/cn\";\nimport { defaultInstallHint, type RenderInstallHint } from \"./install-hints\";\nimport styles from \"./InstallButton.module.css\";\n\nexport type InstallOutcome = \"accepted\" | \"dismissed\" | \"unsupported\";\n\nexport interface InstallButtonProps extends Omit<ButtonProps, \"onClick\" | \"children\"> {\n /** Button label. Default `\"Instalar app\"`. */\n label?: ReactNode;\n /**\n * Label used when the browser cannot be prompted and the button reveals the\n * manual instruction instead. Default `\"Como instalar\"`.\n */\n hintLabel?: ReactNode;\n /** Called with the user's choice after the install prompt resolves. */\n onResult?: (outcome: InstallOutcome) => void;\n /**\n * Replaces the instruction shown for the `\"ios\"` and `\"manual\"` methods.\n *\n * The default copy is in PT-BR and names the real menu entries. Pass this to\n * translate it, to shorten it, or to point at a screenshot of your own.\n */\n renderHint?: RenderInstallHint;\n /**\n * How long, in ms, to wait for `beforeinstallprompt` before falling back to\n * the manual instruction. Forwarded to {@link useInstallPrompt}; defaults to\n * 3000 there.\n */\n manualFallbackDelayMs?: number;\n /** Class applied to the wrapper that holds the button and the instruction. */\n wrapperClassName?: string;\n}\n\n/**\n * Button wired to PWA installation, through {@link useInstallPrompt}.\n *\n * Where the browser fires `beforeinstallprompt`, the click installs. Where it\n * does not — iOS Safari, and the Android Chromium forks (Mi Browser, UC, Opera\n * Mini, Huawei) that strip the API — the click reveals the instruction for that\n * platform instead of the button disappearing.\n *\n * That disappearance was the defect: the component was built on\n * `useBeforeInstallPrompt`, so it rendered `null` exactly where the user needs\n * the most help, and every app re-implemented the iOS and manual paths locally.\n * Nothing renders only when there is genuinely nothing to offer — already\n * installed, running standalone, or inside the decline cooldown.\n *\n * Inherits every {@link Button} prop (`variant`, `size`, `leftIcon`, …).\n *\n * @example\n * <InstallButton variant=\"primary\" leftIcon={<Download />} />\n *\n * @example\n * <InstallButton renderHint={({ method }) => (method === \"ios\" ? <IOSSteps /> : <MenuSteps />)} />\n */\nexport function InstallButton({\n label = \"Instalar app\",\n hintLabel = \"Como instalar\",\n onResult,\n renderHint = defaultInstallHint,\n manualFallbackDelayMs,\n wrapperClassName,\n ...props\n}: InstallButtonProps) {\n const { method, openInChromeIntent, install } = useInstallPrompt({ manualFallbackDelayMs });\n const [hintOpen, setHintOpen] = useState(false);\n const hintId = useId();\n\n if (method === \"none\") return null;\n\n if (method === \"native\") {\n return (\n <Button\n onClick={async () => {\n const accepted = await install();\n onResult?.(accepted ? \"accepted\" : \"dismissed\");\n }}\n {...props}\n >\n {label}\n </Button>\n );\n }\n\n const hint = renderHint({ method, openInChromeIntent });\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <Button\n aria-expanded={hintOpen}\n aria-controls={hintOpen && hint ? hintId : undefined}\n onClick={() => setHintOpen((open) => !open)}\n {...props}\n >\n {hintLabel}\n </Button>\n {hintOpen && hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n </div>\n );\n}\n"],"mappings":"uPA2DA,SAAgB,EAAc,CAC1B,QAAQ,eACR,YAAY,gBACZ,WACA,aAAa,EAAA,mBACb,wBACA,mBACA,GAAG,GACgB,CACnB,GAAM,CAAE,SAAQ,qBAAoB,WAAY,EAAA,iBAAiB,CAAE,uBAAsB,CAAC,EACpF,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAS,EAAK,EACxC,GAAA,EAAS,EAAA,MAAA,CAAM,EAErB,GAAI,IAAW,OAAQ,OAAO,KAE9B,GAAI,IAAW,SACX,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,QAAS,SAAY,CACjB,IAAM,EAAW,MAAM,EAAQ,EAC/B,IAAW,EAAW,WAAa,WAAW,CAClD,EACA,GAAI,EAEH,SAAA,CACG,CAAA,EAIhB,IAAM,EAAO,EAAW,CAAE,SAAQ,oBAAmB,CAAC,EAEtD,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAgB,EAAnD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,gBAAe,EACf,gBAAe,GAAY,EAAO,EAAS,IAAA,GAC3C,YAAe,EAAa,GAAS,CAAC,CAAI,EAC1C,GAAI,EAEH,SAAA,CACG,CAAA,EACP,GAAY,GACT,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,KAAM,GAAI,EAC1B,SAAA,CACF,CAAA,EACH,IACH,GAEb"}
1
+ {"version":3,"file":"InstallButton.cjs","names":[],"sources":["../../../src/components/InstallButton/InstallButton.tsx"],"sourcesContent":["import { useId, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonAsButtonProps } from \"@/components/Button\";\nimport { useInstallPrompt } from \"@/hooks/use-install-prompt\";\nimport { cn } from \"@/utils/cn\";\nimport { defaultInstallHint, type RenderInstallHint } from \"./install-hints\";\nimport styles from \"./InstallButton.module.css\";\n\nexport type InstallOutcome = \"accepted\" | \"dismissed\" | \"unsupported\";\n\nexport interface InstallButtonProps extends Omit<ButtonAsButtonProps, \"onClick\" | \"children\"> {\n /** Button label. Default `\"Instalar app\"`. */\n label?: ReactNode;\n /**\n * Label used when the browser cannot be prompted and the button reveals the\n * manual instruction instead. Default `\"Como instalar\"`.\n */\n hintLabel?: ReactNode;\n /** Called with the user's choice after the install prompt resolves. */\n onResult?: (outcome: InstallOutcome) => void;\n /**\n * Replaces the instruction shown for the `\"ios\"` and `\"manual\"` methods.\n *\n * The default copy is in PT-BR and names the real menu entries. Pass this to\n * translate it, to shorten it, or to point at a screenshot of your own.\n */\n renderHint?: RenderInstallHint;\n /**\n * How long, in ms, to wait for `beforeinstallprompt` before falling back to\n * the manual instruction. Forwarded to {@link useInstallPrompt}; defaults to\n * 3000 there.\n */\n manualFallbackDelayMs?: number;\n /** Class applied to the wrapper that holds the button and the instruction. */\n wrapperClassName?: string;\n}\n\n/**\n * Button wired to PWA installation, through {@link useInstallPrompt}.\n *\n * Where the browser fires `beforeinstallprompt`, the click installs. Where it\n * does not — iOS Safari, and the Android Chromium forks (Mi Browser, UC, Opera\n * Mini, Huawei) that strip the API — the click reveals the instruction for that\n * platform instead of the button disappearing.\n *\n * That disappearance was the defect: the component was built on\n * `useBeforeInstallPrompt`, so it rendered `null` exactly where the user needs\n * the most help, and every app re-implemented the iOS and manual paths locally.\n * Nothing renders only when there is genuinely nothing to offer — already\n * installed, running standalone, or inside the decline cooldown.\n *\n * Inherits every {@link Button} prop of the `<button>` mode (`variant`, `size`,\n * `leftIcon`, …) but not `href`: its click opens the install prompt\n * or toggles the instruction, which is an action, not a navigation.\n *\n * @example\n * <InstallButton variant=\"primary\" leftIcon={<Download />} />\n *\n * @example\n * <InstallButton renderHint={({ method }) => (method === \"ios\" ? <IOSSteps /> : <MenuSteps />)} />\n */\nexport function InstallButton({\n label = \"Instalar app\",\n hintLabel = \"Como instalar\",\n onResult,\n renderHint = defaultInstallHint,\n manualFallbackDelayMs,\n wrapperClassName,\n ...props\n}: InstallButtonProps) {\n const { method, openInChromeIntent, install } = useInstallPrompt({ manualFallbackDelayMs });\n const [hintOpen, setHintOpen] = useState(false);\n const hintId = useId();\n\n if (method === \"none\") return null;\n\n if (method === \"native\") {\n return (\n <Button\n onClick={async () => {\n const accepted = await install();\n onResult?.(accepted ? \"accepted\" : \"dismissed\");\n }}\n {...props}\n >\n {label}\n </Button>\n );\n }\n\n const hint = renderHint({ method, openInChromeIntent });\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <Button\n aria-expanded={hintOpen}\n aria-controls={hintOpen && hint ? hintId : undefined}\n onClick={() => setHintOpen((open) => !open)}\n {...props}\n >\n {hintLabel}\n </Button>\n {hintOpen && hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n </div>\n );\n}\n"],"mappings":"uPA6DA,SAAgB,EAAc,CAC1B,QAAQ,eACR,YAAY,gBACZ,WACA,aAAa,EAAA,mBACb,wBACA,mBACA,GAAG,GACgB,CACnB,GAAM,CAAE,SAAQ,qBAAoB,WAAY,EAAA,iBAAiB,CAAE,uBAAsB,CAAC,EACpF,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAS,EAAK,EACxC,GAAA,EAAS,EAAA,MAAA,CAAM,EAErB,GAAI,IAAW,OAAQ,OAAO,KAE9B,GAAI,IAAW,SACX,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,QAAS,SAAY,CACjB,IAAM,EAAW,MAAM,EAAQ,EAC/B,IAAW,EAAW,WAAa,WAAW,CAClD,EACA,GAAI,EAEH,SAAA,CACG,CAAA,EAIhB,IAAM,EAAO,EAAW,CAAE,SAAQ,oBAAmB,CAAC,EAEtD,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAgB,EAAnD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,gBAAe,EACf,gBAAe,GAAY,EAAO,EAAS,IAAA,GAC3C,YAAe,EAAa,GAAS,CAAC,CAAI,EAC1C,GAAI,EAEH,SAAA,CACG,CAAA,EACP,GAAY,GACT,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,KAAM,GAAI,EAC1B,SAAA,CACF,CAAA,EACH,IACH,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"InstallButton.js","names":[],"sources":["../../../src/components/InstallButton/InstallButton.tsx"],"sourcesContent":["import { useId, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"@/components/Button\";\nimport { useInstallPrompt } from \"@/hooks/use-install-prompt\";\nimport { cn } from \"@/utils/cn\";\nimport { defaultInstallHint, type RenderInstallHint } from \"./install-hints\";\nimport styles from \"./InstallButton.module.css\";\n\nexport type InstallOutcome = \"accepted\" | \"dismissed\" | \"unsupported\";\n\nexport interface InstallButtonProps extends Omit<ButtonProps, \"onClick\" | \"children\"> {\n /** Button label. Default `\"Instalar app\"`. */\n label?: ReactNode;\n /**\n * Label used when the browser cannot be prompted and the button reveals the\n * manual instruction instead. Default `\"Como instalar\"`.\n */\n hintLabel?: ReactNode;\n /** Called with the user's choice after the install prompt resolves. */\n onResult?: (outcome: InstallOutcome) => void;\n /**\n * Replaces the instruction shown for the `\"ios\"` and `\"manual\"` methods.\n *\n * The default copy is in PT-BR and names the real menu entries. Pass this to\n * translate it, to shorten it, or to point at a screenshot of your own.\n */\n renderHint?: RenderInstallHint;\n /**\n * How long, in ms, to wait for `beforeinstallprompt` before falling back to\n * the manual instruction. Forwarded to {@link useInstallPrompt}; defaults to\n * 3000 there.\n */\n manualFallbackDelayMs?: number;\n /** Class applied to the wrapper that holds the button and the instruction. */\n wrapperClassName?: string;\n}\n\n/**\n * Button wired to PWA installation, through {@link useInstallPrompt}.\n *\n * Where the browser fires `beforeinstallprompt`, the click installs. Where it\n * does not — iOS Safari, and the Android Chromium forks (Mi Browser, UC, Opera\n * Mini, Huawei) that strip the API — the click reveals the instruction for that\n * platform instead of the button disappearing.\n *\n * That disappearance was the defect: the component was built on\n * `useBeforeInstallPrompt`, so it rendered `null` exactly where the user needs\n * the most help, and every app re-implemented the iOS and manual paths locally.\n * Nothing renders only when there is genuinely nothing to offer — already\n * installed, running standalone, or inside the decline cooldown.\n *\n * Inherits every {@link Button} prop (`variant`, `size`, `leftIcon`, …).\n *\n * @example\n * <InstallButton variant=\"primary\" leftIcon={<Download />} />\n *\n * @example\n * <InstallButton renderHint={({ method }) => (method === \"ios\" ? <IOSSteps /> : <MenuSteps />)} />\n */\nexport function InstallButton({\n label = \"Instalar app\",\n hintLabel = \"Como instalar\",\n onResult,\n renderHint = defaultInstallHint,\n manualFallbackDelayMs,\n wrapperClassName,\n ...props\n}: InstallButtonProps) {\n const { method, openInChromeIntent, install } = useInstallPrompt({ manualFallbackDelayMs });\n const [hintOpen, setHintOpen] = useState(false);\n const hintId = useId();\n\n if (method === \"none\") return null;\n\n if (method === \"native\") {\n return (\n <Button\n onClick={async () => {\n const accepted = await install();\n onResult?.(accepted ? \"accepted\" : \"dismissed\");\n }}\n {...props}\n >\n {label}\n </Button>\n );\n }\n\n const hint = renderHint({ method, openInChromeIntent });\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <Button\n aria-expanded={hintOpen}\n aria-controls={hintOpen && hint ? hintId : undefined}\n onClick={() => setHintOpen((open) => !open)}\n {...props}\n >\n {hintLabel}\n </Button>\n {hintOpen && hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA2DA,SAAgB,EAAc,EAC1B,WAAQ,gBACR,eAAY,iBACZ,aACA,gBAAa,GACb,0BACA,qBACA,GAAG,KACgB;CACnB,IAAM,EAAE,WAAQ,uBAAoB,eAAY,EAAiB,EAAE,yBAAsB,CAAC,GACpF,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,IAAS,EAAM;CAErB,IAAI,MAAW,QAAQ,OAAO;CAE9B,IAAI,MAAW,UACX,OACI,kBAAC,GAAD;EACI,SAAS,YAAY;GACjB,IAAM,IAAW,MAAM,EAAQ;GAC/B,IAAW,IAAW,aAAa,WAAW;EAClD;EACA,GAAI;EAEH,UAAA;CACG,CAAA;CAIhB,IAAM,IAAO,EAAW;EAAE;EAAQ;CAAmB,CAAC;CAEtD,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAgB;EAAnD,UAAA,CACI,kBAAC,GAAD;GACI,iBAAe;GACf,iBAAe,KAAY,IAAO,IAAS,KAAA;GAC3C,eAAe,GAAa,MAAS,CAAC,CAAI;GAC1C,GAAI;GAEH,UAAA;EACG,CAAA,GACP,KAAY,IACT,kBAAC,KAAD;GAAG,WAAW,EAAO;GAAM,IAAI;GAC1B,UAAA;EACF,CAAA,IACH,IACH;;AAEb"}
1
+ {"version":3,"file":"InstallButton.js","names":[],"sources":["../../../src/components/InstallButton/InstallButton.tsx"],"sourcesContent":["import { useId, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonAsButtonProps } from \"@/components/Button\";\nimport { useInstallPrompt } from \"@/hooks/use-install-prompt\";\nimport { cn } from \"@/utils/cn\";\nimport { defaultInstallHint, type RenderInstallHint } from \"./install-hints\";\nimport styles from \"./InstallButton.module.css\";\n\nexport type InstallOutcome = \"accepted\" | \"dismissed\" | \"unsupported\";\n\nexport interface InstallButtonProps extends Omit<ButtonAsButtonProps, \"onClick\" | \"children\"> {\n /** Button label. Default `\"Instalar app\"`. */\n label?: ReactNode;\n /**\n * Label used when the browser cannot be prompted and the button reveals the\n * manual instruction instead. Default `\"Como instalar\"`.\n */\n hintLabel?: ReactNode;\n /** Called with the user's choice after the install prompt resolves. */\n onResult?: (outcome: InstallOutcome) => void;\n /**\n * Replaces the instruction shown for the `\"ios\"` and `\"manual\"` methods.\n *\n * The default copy is in PT-BR and names the real menu entries. Pass this to\n * translate it, to shorten it, or to point at a screenshot of your own.\n */\n renderHint?: RenderInstallHint;\n /**\n * How long, in ms, to wait for `beforeinstallprompt` before falling back to\n * the manual instruction. Forwarded to {@link useInstallPrompt}; defaults to\n * 3000 there.\n */\n manualFallbackDelayMs?: number;\n /** Class applied to the wrapper that holds the button and the instruction. */\n wrapperClassName?: string;\n}\n\n/**\n * Button wired to PWA installation, through {@link useInstallPrompt}.\n *\n * Where the browser fires `beforeinstallprompt`, the click installs. Where it\n * does not — iOS Safari, and the Android Chromium forks (Mi Browser, UC, Opera\n * Mini, Huawei) that strip the API — the click reveals the instruction for that\n * platform instead of the button disappearing.\n *\n * That disappearance was the defect: the component was built on\n * `useBeforeInstallPrompt`, so it rendered `null` exactly where the user needs\n * the most help, and every app re-implemented the iOS and manual paths locally.\n * Nothing renders only when there is genuinely nothing to offer — already\n * installed, running standalone, or inside the decline cooldown.\n *\n * Inherits every {@link Button} prop of the `<button>` mode (`variant`, `size`,\n * `leftIcon`, …) but not `href`: its click opens the install prompt\n * or toggles the instruction, which is an action, not a navigation.\n *\n * @example\n * <InstallButton variant=\"primary\" leftIcon={<Download />} />\n *\n * @example\n * <InstallButton renderHint={({ method }) => (method === \"ios\" ? <IOSSteps /> : <MenuSteps />)} />\n */\nexport function InstallButton({\n label = \"Instalar app\",\n hintLabel = \"Como instalar\",\n onResult,\n renderHint = defaultInstallHint,\n manualFallbackDelayMs,\n wrapperClassName,\n ...props\n}: InstallButtonProps) {\n const { method, openInChromeIntent, install } = useInstallPrompt({ manualFallbackDelayMs });\n const [hintOpen, setHintOpen] = useState(false);\n const hintId = useId();\n\n if (method === \"none\") return null;\n\n if (method === \"native\") {\n return (\n <Button\n onClick={async () => {\n const accepted = await install();\n onResult?.(accepted ? \"accepted\" : \"dismissed\");\n }}\n {...props}\n >\n {label}\n </Button>\n );\n }\n\n const hint = renderHint({ method, openInChromeIntent });\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <Button\n aria-expanded={hintOpen}\n aria-controls={hintOpen && hint ? hintId : undefined}\n onClick={() => setHintOpen((open) => !open)}\n {...props}\n >\n {hintLabel}\n </Button>\n {hintOpen && hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA6DA,SAAgB,EAAc,EAC1B,WAAQ,gBACR,eAAY,iBACZ,aACA,gBAAa,GACb,0BACA,qBACA,GAAG,KACgB;CACnB,IAAM,EAAE,WAAQ,uBAAoB,eAAY,EAAiB,EAAE,yBAAsB,CAAC,GACpF,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,IAAS,EAAM;CAErB,IAAI,MAAW,QAAQ,OAAO;CAE9B,IAAI,MAAW,UACX,OACI,kBAAC,GAAD;EACI,SAAS,YAAY;GACjB,IAAM,IAAW,MAAM,EAAQ;GAC/B,IAAW,IAAW,aAAa,WAAW;EAClD;EACA,GAAI;EAEH,UAAA;CACG,CAAA;CAIhB,IAAM,IAAO,EAAW;EAAE;EAAQ;CAAmB,CAAC;CAEtD,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAgB;EAAnD,UAAA,CACI,kBAAC,GAAD;GACI,iBAAe;GACf,iBAAe,KAAY,IAAO,IAAS,KAAA;GAC3C,eAAe,GAAa,MAAS,CAAC,CAAI;GAC1C,GAAI;GAEH,UAAA;EACG,CAAA,GACP,KAAY,IACT,kBAAC,KAAD;GAAG,WAAW,EAAO;GAAM,IAAI;GAC1B,UAAA;EACF,CAAA,IACH,IACH;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ListTile.module.cjs","names":[],"sources":["../../../src/components/ListTile/ListTile.module.css"],"sourcesContent":[".tile {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n width: 100%;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n background: var(--tempest-surface);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n text-align: left;\n border: 0;\n border-radius: var(--tempest-radius-md);\n}\n\n.interactive {\n cursor: pointer;\n transition: background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.interactive:hover {\n background: var(--tempest-surface-2);\n}\n\n.interactive:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, var(--tempest-primary));\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.selected {\n background: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.interactive.selected:hover {\n background: var(--tempest-primary-soft-hover, var(--tempest-primary-soft));\n}\n\n.disabled {\n opacity: 0.4;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.leading,\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n line-height: 1;\n}\n\n.trailing {\n margin-left: auto;\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.title {\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.subtitle {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected .subtitle {\n color: var(--tempest-primary);\n opacity: 0.8;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"ListTile.module.cjs","names":[],"sources":["../../../src/components/ListTile/ListTile.module.css"],"sourcesContent":[".tile {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n width: 100%;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n background: var(--tempest-surface);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n text-align: left;\n border: 0;\n border-radius: var(--tempest-radius-md);\n}\n\n.interactive {\n cursor: pointer;\n transition: background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.interactive:hover {\n background: var(--tempest-surface-2);\n}\n\n.interactive:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, currentColor);\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.selected {\n background: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.interactive.selected:hover {\n background: var(--tempest-primary-soft-hover, var(--tempest-primary-soft));\n}\n\n.disabled {\n opacity: 0.4;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.leading,\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n line-height: 1;\n}\n\n.trailing {\n margin-left: auto;\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.title {\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.subtitle {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected .subtitle {\n color: var(--tempest-primary);\n opacity: 0.8;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"ListTile.module.js","names":[],"sources":["../../../src/components/ListTile/ListTile.module.css"],"sourcesContent":[".tile {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n width: 100%;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n background: var(--tempest-surface);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n text-align: left;\n border: 0;\n border-radius: var(--tempest-radius-md);\n}\n\n.interactive {\n cursor: pointer;\n transition: background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.interactive:hover {\n background: var(--tempest-surface-2);\n}\n\n.interactive:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, var(--tempest-primary));\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.selected {\n background: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.interactive.selected:hover {\n background: var(--tempest-primary-soft-hover, var(--tempest-primary-soft));\n}\n\n.disabled {\n opacity: 0.4;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.leading,\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n line-height: 1;\n}\n\n.trailing {\n margin-left: auto;\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.title {\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.subtitle {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected .subtitle {\n color: var(--tempest-primary);\n opacity: 0.8;\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"ListTile.module.js","names":[],"sources":["../../../src/components/ListTile/ListTile.module.css"],"sourcesContent":[".tile {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n width: 100%;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n background: var(--tempest-surface);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n text-align: left;\n border: 0;\n border-radius: var(--tempest-radius-md);\n}\n\n.interactive {\n cursor: pointer;\n transition: background var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n}\n\n.interactive:hover {\n background: var(--tempest-surface-2);\n}\n\n.interactive:focus-visible {\n outline: var(--tempest-focus-ring-width, 2px) solid\n var(--tempest-focus-ring-color, currentColor);\n outline-offset: var(--tempest-focus-ring-offset, 2px);\n}\n\n.selected {\n background: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.interactive.selected:hover {\n background: var(--tempest-primary-soft-hover, var(--tempest-primary-soft));\n}\n\n.disabled {\n opacity: 0.4;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.leading,\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n line-height: 1;\n}\n\n.trailing {\n margin-left: auto;\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.title {\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.subtitle {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-snug, 1.3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected .subtitle {\n color: var(--tempest-primary);\n opacity: 0.8;\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.module.cjs","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Markdown.module.cjs","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.module.js","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Markdown.module.js","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"Menubar.module.cjs","names":[],"sources":["../../../src/components/Menubar/Menubar.module.css"],"sourcesContent":[".root {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.menu {\n position: relative;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n padding: var(--tempest-space-1) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: inherit;\n line-height: var(--tempest-leading-snug);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .trigger:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.trigger:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.triggerOpen {\n background-color: var(--tempest-surface);\n}\n\n.panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: var(--tempest-z-dropdown);\n min-width: 200px;\n max-width: 360px;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n animation: tempest-menubar-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-4);\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n text-align: left;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .item:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.item:focus {\n outline: none;\n background-color: var(--tempest-surface);\n}\n\n.item:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.itemLabel {\n flex: 1;\n}\n\n.shortcut {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.separator {\n height: 1px;\n background-color: var(--tempest-border);\n margin: var(--tempest-space-1) 0;\n}\n\n@keyframes tempest-menubar-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel {\n animation: none;\n }\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Menubar.module.cjs","names":[],"sources":["../../../src/components/Menubar/Menubar.module.css"],"sourcesContent":[".root {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.menu {\n position: relative;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n padding: var(--tempest-space-1) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: inherit;\n line-height: var(--tempest-leading-snug);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .trigger:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.triggerOpen {\n background-color: var(--tempest-surface);\n}\n\n.panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: var(--tempest-z-dropdown);\n min-width: 200px;\n max-width: 360px;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n animation: tempest-menubar-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-4);\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n text-align: left;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .item:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.item:focus {\n outline: none;\n background-color: var(--tempest-surface);\n}\n\n.item:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.itemLabel {\n flex: 1;\n}\n\n.shortcut {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.separator {\n height: 1px;\n background-color: var(--tempest-border);\n margin: var(--tempest-space-1) 0;\n}\n\n@keyframes tempest-menubar-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel {\n animation: none;\n }\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"Menubar.module.js","names":[],"sources":["../../../src/components/Menubar/Menubar.module.css"],"sourcesContent":[".root {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.menu {\n position: relative;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n padding: var(--tempest-space-1) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: inherit;\n line-height: var(--tempest-leading-snug);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .trigger:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.trigger:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.triggerOpen {\n background-color: var(--tempest-surface);\n}\n\n.panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: var(--tempest-z-dropdown);\n min-width: 200px;\n max-width: 360px;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n animation: tempest-menubar-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-4);\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n text-align: left;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .item:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.item:focus {\n outline: none;\n background-color: var(--tempest-surface);\n}\n\n.item:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.itemLabel {\n flex: 1;\n}\n\n.shortcut {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.separator {\n height: 1px;\n background-color: var(--tempest-border);\n margin: var(--tempest-space-1) 0;\n}\n\n@keyframes tempest-menubar-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel {\n animation: none;\n }\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Menubar.module.js","names":[],"sources":["../../../src/components/Menubar/Menubar.module.css"],"sourcesContent":[".root {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n}\n\n.menu {\n position: relative;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n padding: var(--tempest-space-1) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: inherit;\n line-height: var(--tempest-leading-snug);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .trigger:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.triggerOpen {\n background-color: var(--tempest-surface);\n}\n\n.panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: var(--tempest-z-dropdown);\n min-width: 200px;\n max-width: 360px;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n animation: tempest-menubar-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-4);\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n background: none;\n border: none;\n border-radius: var(--tempest-radius-sm);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n text-align: left;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .item:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.item:focus {\n outline: none;\n background-color: var(--tempest-surface);\n}\n\n.item:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.itemLabel {\n flex: 1;\n}\n\n.shortcut {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.separator {\n height: 1px;\n background-color: var(--tempest-border);\n margin: var(--tempest-space-1) 0;\n}\n\n@keyframes tempest-menubar-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel {\n animation: none;\n }\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-sm);\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("../Portal/escape-layer.cjs"),n=require("../../hooks/use-focus-trap.cjs"),r=require("../Portal/portal-host.cjs"),i=require("./Modal.module.cjs");let a=require("react"),o=require("react/jsx-runtime"),s=require("react-dom");function c({open:c,onClose:d,title:f,children:p,footer:m,size:h=`md`,closeOnBackdrop:g=!0,closeOnEsc:_=!0,className:v,hideCloseButton:y=!1,fullscreen:b=!1,fullscreenOnMobile:x=!1,"aria-label":S}){let C=(0,a.useId)(),w=(0,a.useRef)(null);n.useFocusTrap(w,c),t.useEscapeLayer(c,_?d:null),(0,a.useEffect)(()=>{if(!c)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[c]);let T=r.usePortalHost();return!c||!T?null:(0,s.createPortal)((0,o.jsx)(`div`,{className:i.default.overlay,role:`presentation`,onClick:()=>{g&&d()},children:(0,o.jsxs)(`div`,{ref:w,role:`dialog`,"aria-modal":`true`,tabIndex:-1,"aria-labelledby":f?C:void 0,"aria-label":f?void 0:S,className:e.cn(i.default.dialog,l(h),b&&i.default.fullscreen,x&&i.default.fullscreenOnMobile,v),onClick:e=>e.stopPropagation(),children:[(f||!y)&&(0,o.jsxs)(`header`,{className:i.default.header,children:[f&&(0,o.jsx)(`h3`,{id:C,className:i.default.title,children:f}),!y&&(0,o.jsx)(`button`,{type:`button`,className:i.default.close,"aria-label":`Fechar`,onClick:d,children:(0,o.jsx)(u,{})})]}),(0,o.jsx)(`div`,{className:i.default.body,children:p}),m&&(0,o.jsx)(`footer`,{className:i.default.footer,children:m})]})}),T)}function l(e){return e===`2xl`?i.default.size2xl:e===`3xl`?i.default.size3xl:i.default[e]}function u(){return(0,o.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,children:(0,o.jsx)(`path`,{d:`M6 6l12 12M6 18L18 6`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`})})}exports.Modal=c;
1
+ const e=require("../../utils/cn.cjs"),t=require("../Portal/escape-layer.cjs"),n=require("../../hooks/use-focus-trap.cjs"),r=require("../Portal/portal-host.cjs"),i=require("./Modal.module.cjs");let a=require("react"),o=require("react/jsx-runtime"),s=require("react-dom");function c({open:c,onClose:d,title:f,children:p,footer:m,size:h=`md`,closeOnBackdrop:g=!0,closeOnEsc:_=!0,className:v,hideCloseButton:y=!1,fullscreen:b=!1,fullscreenOnMobile:x=!1,"aria-label":S}){let C=(0,a.useId)(),w=(0,a.useRef)(null);n.useFocusTrap(w,c),t.useEscapeLayer(c,_?d:null),(0,a.useEffect)(()=>{if(!c)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[c]);let T=r.usePortalHost();return!c||!T?null:(0,s.createPortal)((0,o.jsx)(`div`,{className:i.default.overlay,role:`presentation`,onClick:()=>{g&&d()},children:(0,o.jsxs)(`div`,{ref:w,role:`dialog`,"aria-modal":`true`,tabIndex:-1,"aria-labelledby":f?C:void 0,"aria-label":f?void 0:S,className:e.cn(i.default.dialog,l(h),b&&i.default.fullscreen,x&&i.default.fullscreenOnMobile,v),onClick:e=>e.stopPropagation(),children:[(f||!y)&&(0,o.jsxs)(`header`,{className:i.default.header,children:[f&&(0,o.jsx)(`h3`,{id:C,className:i.default.title,children:f}),!y&&(0,o.jsx)(`button`,{type:`button`,className:i.default.close,"aria-label":`Fechar`,onClick:d,children:(0,o.jsx)(u,{})})]}),(0,o.jsx)(`div`,{className:i.default.body,children:p}),m&&(0,o.jsx)(`footer`,{className:i.default.footer,children:m})]})}),T)}function l(e){return e===`2xl`?i.default.size2Xl:e===`3xl`?i.default.size3Xl:i.default[e]}function u(){return(0,o.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,children:(0,o.jsx)(`path`,{d:`M6 6l12 12M6 18L18 6`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`})})}exports.Modal=c;
2
2
  //# sourceMappingURL=Modal.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.cjs","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * Keyboard focus is trapped in the dialog while it is open (`useFocusTrap`): it\n * enters on the first tab stop — or the dialog itself when there is none —,\n * `Tab`/`Shift+Tab` cycle inside it, including the panels of a `Popover` or\n * `HoverCard` opened from it, and closing returns focus to the element that\n * opened it. `aria-modal=\"true\"` tells a screen reader the page behind is inert;\n * the trap is what makes that true for the keyboard.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n const dialogRef = useRef<HTMLDivElement>(null);\n useFocusTrap(dialogRef, open);\n useEscapeLayer(open, closeOnEsc ? onClose : null);\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n portalHost,\n );\n}\n\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2xl;\n if (size === \"3xl\") return styles.size3xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"8QAwDA,SAAgB,EAAM,CAClB,OACA,UACA,QACA,WACA,SACA,OAAO,KACP,kBAAkB,GAClB,aAAa,GACb,YACA,kBAAkB,GAClB,aAAa,GACb,qBAAqB,GACrB,aAAc,GACH,CACX,IAAM,GAAA,EAAU,EAAA,MAAA,CAAM,EAChB,GAAA,EAAY,EAAA,OAAA,CAAuB,IAAI,EAC7C,EAAA,aAAa,EAAW,CAAI,EAC5B,EAAA,eAAe,EAAM,EAAa,EAAU,IAAI,GAChD,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,OACX,IAAM,EAAmB,SAAS,KAAK,MAAM,SAE7C,MADA,UAAS,KAAK,MAAM,SAAW,aAClB,CACT,SAAS,KAAK,MAAM,SAAW,CACnC,CACJ,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,EAAa,EAAA,cAAc,EAIjC,MAFI,CAAC,GAAQ,CAAC,EAAmB,MAEjC,EAAO,EAAA,aAAA,EACH,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,QAClB,KAAK,eACL,YAAe,CACP,GAAiB,EAAQ,CACjC,EAEA,UAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,KAAK,SACL,aAAW,OACX,SAAU,GACV,kBAAiB,EAAQ,EAAU,IAAA,GACnC,aAAY,EAAQ,IAAA,GAAY,EAChC,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAc,CAAI,EAClB,GAAc,EAAA,QAAO,WACrB,GAAsB,EAAA,QAAO,mBAC7B,CACJ,EACA,QAAU,GAAU,EAAM,gBAAgB,EAd9C,SAAA,EAgBM,GAAS,CAAC,KACR,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAA1B,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAS,UAAW,EAAA,QAAO,MAC9B,SAAA,CACD,CAAA,EAEP,CAAC,IACE,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,MAClB,aAAW,SACX,QAAS,EAET,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACR,CAAA,CAER,KAEZ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,UAAc,CAAA,EAC3C,IAAU,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAAS,SAAA,CAAe,CAAA,CAC5D,GACJ,CAAA,EACL,CACJ,CACJ,CAEA,SAAS,EAAc,EAAqC,CAGxD,OAFI,IAAS,MAAc,EAAA,QAAO,QAC9B,IAAS,MAAc,EAAA,QAAO,QAC3B,EAAA,QAAO,EAClB,CAEA,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACjD,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,uBACF,OAAO,eACP,YAAY,IACZ,cAAc,OACjB,CAAA,CACA,CAAA,CAEb"}
1
+ {"version":3,"file":"Modal.cjs","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * Keyboard focus is trapped in the dialog while it is open (`useFocusTrap`): it\n * enters on the first tab stop — or the dialog itself when there is none —,\n * `Tab`/`Shift+Tab` cycle inside it, including the panels of a `Popover` or\n * `HoverCard` opened from it, and closing returns focus to the element that\n * opened it. `aria-modal=\"true\"` tells a screen reader the page behind is inert;\n * the trap is what makes that true for the keyboard.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n const dialogRef = useRef<HTMLDivElement>(null);\n useFocusTrap(dialogRef, open);\n useEscapeLayer(open, closeOnEsc ? onClose : null);\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n portalHost,\n );\n}\n\n/**\n * Resolve the width class for a {@link ModalSize}.\n *\n * `2xl`/`3xl` are not valid CSS identifiers, so their rules are `.size2Xl` and\n * `.size3Xl` — spelled exactly as the build exports them. The build camelCases\n * CSS-module keys (`localsConvention: \"camelCaseOnly\"`), which turns `.size2xl`\n * into the key `size2Xl`; a lookup of `styles.size2xl` was `undefined` in `dist/`\n * and both sizes rendered with no `max-width` at all (issue #405).\n *\n * @param size - The requested modal size.\n * @returns The CSS-module class name for that size.\n */\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2Xl;\n if (size === \"3xl\") return styles.size3Xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"8QAwDA,SAAgB,EAAM,CAClB,OACA,UACA,QACA,WACA,SACA,OAAO,KACP,kBAAkB,GAClB,aAAa,GACb,YACA,kBAAkB,GAClB,aAAa,GACb,qBAAqB,GACrB,aAAc,GACH,CACX,IAAM,GAAA,EAAU,EAAA,MAAA,CAAM,EAChB,GAAA,EAAY,EAAA,OAAA,CAAuB,IAAI,EAC7C,EAAA,aAAa,EAAW,CAAI,EAC5B,EAAA,eAAe,EAAM,EAAa,EAAU,IAAI,GAChD,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,OACX,IAAM,EAAmB,SAAS,KAAK,MAAM,SAE7C,MADA,UAAS,KAAK,MAAM,SAAW,aAClB,CACT,SAAS,KAAK,MAAM,SAAW,CACnC,CACJ,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,EAAa,EAAA,cAAc,EAIjC,MAFI,CAAC,GAAQ,CAAC,EAAmB,MAEjC,EAAO,EAAA,aAAA,EACH,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,QAClB,KAAK,eACL,YAAe,CACP,GAAiB,EAAQ,CACjC,EAEA,UAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,KAAK,SACL,aAAW,OACX,SAAU,GACV,kBAAiB,EAAQ,EAAU,IAAA,GACnC,aAAY,EAAQ,IAAA,GAAY,EAChC,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAc,CAAI,EAClB,GAAc,EAAA,QAAO,WACrB,GAAsB,EAAA,QAAO,mBAC7B,CACJ,EACA,QAAU,GAAU,EAAM,gBAAgB,EAd9C,SAAA,EAgBM,GAAS,CAAC,KACR,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAA1B,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAS,UAAW,EAAA,QAAO,MAC9B,SAAA,CACD,CAAA,EAEP,CAAC,IACE,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,MAClB,aAAW,SACX,QAAS,EAET,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACR,CAAA,CAER,KAEZ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,UAAc,CAAA,EAC3C,IAAU,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAAS,SAAA,CAAe,CAAA,CAC5D,GACJ,CAAA,EACL,CACJ,CACJ,CAcA,SAAS,EAAc,EAAqC,CAGxD,OAFI,IAAS,MAAc,EAAA,QAAO,QAC9B,IAAS,MAAc,EAAA,QAAO,QAC3B,EAAA,QAAO,EAClB,CAEA,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACjD,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,uBACF,OAAO,eACP,YAAY,IACZ,cAAc,OACjB,CAAA,CACA,CAAA,CAEb"}
@@ -60,7 +60,7 @@ function d({ open: d, onClose: m, title: h, children: g, footer: _, size: v = "m
60
60
  }), O);
61
61
  }
62
62
  function f(e) {
63
- return e === "2xl" ? i.size2xl : e === "3xl" ? i.size3xl : i[e];
63
+ return e === "2xl" ? i.size2Xl : e === "3xl" ? i.size3Xl : i[e];
64
64
  }
65
65
  function p() {
66
66
  return /* @__PURE__ */ c("svg", {
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * Keyboard focus is trapped in the dialog while it is open (`useFocusTrap`): it\n * enters on the first tab stop — or the dialog itself when there is none —,\n * `Tab`/`Shift+Tab` cycle inside it, including the panels of a `Popover` or\n * `HoverCard` opened from it, and closing returns focus to the element that\n * opened it. `aria-modal=\"true\"` tells a screen reader the page behind is inert;\n * the trap is what makes that true for the keyboard.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n const dialogRef = useRef<HTMLDivElement>(null);\n useFocusTrap(dialogRef, open);\n useEscapeLayer(open, closeOnEsc ? onClose : null);\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n portalHost,\n );\n}\n\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2xl;\n if (size === \"3xl\") return styles.size3xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;;;;;AAwDA,SAAgB,EAAM,EAClB,SACA,YACA,UACA,aACA,WACA,UAAO,MACP,qBAAkB,IAClB,gBAAa,IACb,cACA,qBAAkB,IAClB,gBAAa,IACb,wBAAqB,IACrB,cAAc,KACH;CACX,IAAM,IAAU,EAAM,GAChB,IAAY,EAAuB,IAAI;CAG7C,AAFA,EAAa,GAAW,CAAI,GAC5B,EAAe,GAAM,IAAa,IAAU,IAAI,GAChD,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAmB,SAAS,KAAK,MAAM;EAE7C,OADA,SAAS,KAAK,MAAM,WAAW,gBAClB;GACT,SAAS,KAAK,MAAM,WAAW;EACnC;CACJ,GAAG,CAAC,CAAI,CAAC;CAET,IAAM,IAAa,EAAc;CAIjC,OAFI,CAAC,KAAQ,CAAC,IAAmB,OAE1B,EACH,kBAAC,OAAD;EACI,WAAW,EAAO;EAClB,MAAK;EACL,eAAe;GACX,AAAI,KAAiB,EAAQ;EACjC;EAEA,UAAA,kBAAC,OAAD;GACI,KAAK;GACL,MAAK;GACL,cAAW;GACX,UAAU;GACV,mBAAiB,IAAQ,IAAU,KAAA;GACnC,cAAY,IAAQ,KAAA,IAAY;GAChC,WAAW,EACP,EAAO,QACP,EAAc,CAAI,GAClB,KAAc,EAAO,YACrB,KAAsB,EAAO,oBAC7B,CACJ;GACA,UAAU,MAAU,EAAM,gBAAgB;GAd9C,UAAA;KAgBM,KAAS,CAAC,MACR,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAA1B,UAAA,CACK,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW,EAAO;MAC9B,UAAA;KACD,CAAA,GAEP,CAAC,KACE,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,cAAW;MACX,SAAS;MAET,UAAA,kBAAC,GAAD,CAAY,CAAA;KACR,CAAA,CAER;;IAEZ,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;IAC3C,KAAU,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAAS,UAAA;IAAe,CAAA;GAC5D;;CACJ,CAAA,GACL,CACJ;AACJ;AAEA,SAAS,EAAc,GAAqC;CAGxD,OAFI,MAAS,QAAc,EAAO,UAC9B,MAAS,QAAc,EAAO,UAC3B,EAAO;AAClB;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EACjD,UAAA,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"Modal.js","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * Keyboard focus is trapped in the dialog while it is open (`useFocusTrap`): it\n * enters on the first tab stop — or the dialog itself when there is none —,\n * `Tab`/`Shift+Tab` cycle inside it, including the panels of a `Popover` or\n * `HoverCard` opened from it, and closing returns focus to the element that\n * opened it. `aria-modal=\"true\"` tells a screen reader the page behind is inert;\n * the trap is what makes that true for the keyboard.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n const dialogRef = useRef<HTMLDivElement>(null);\n useFocusTrap(dialogRef, open);\n useEscapeLayer(open, closeOnEsc ? onClose : null);\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n portalHost,\n );\n}\n\n/**\n * Resolve the width class for a {@link ModalSize}.\n *\n * `2xl`/`3xl` are not valid CSS identifiers, so their rules are `.size2Xl` and\n * `.size3Xl` — spelled exactly as the build exports them. The build camelCases\n * CSS-module keys (`localsConvention: \"camelCaseOnly\"`), which turns `.size2xl`\n * into the key `size2Xl`; a lookup of `styles.size2xl` was `undefined` in `dist/`\n * and both sizes rendered with no `max-width` at all (issue #405).\n *\n * @param size - The requested modal size.\n * @returns The CSS-module class name for that size.\n */\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2Xl;\n if (size === \"3xl\") return styles.size3Xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;;;;;AAwDA,SAAgB,EAAM,EAClB,SACA,YACA,UACA,aACA,WACA,UAAO,MACP,qBAAkB,IAClB,gBAAa,IACb,cACA,qBAAkB,IAClB,gBAAa,IACb,wBAAqB,IACrB,cAAc,KACH;CACX,IAAM,IAAU,EAAM,GAChB,IAAY,EAAuB,IAAI;CAG7C,AAFA,EAAa,GAAW,CAAI,GAC5B,EAAe,GAAM,IAAa,IAAU,IAAI,GAChD,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAmB,SAAS,KAAK,MAAM;EAE7C,OADA,SAAS,KAAK,MAAM,WAAW,gBAClB;GACT,SAAS,KAAK,MAAM,WAAW;EACnC;CACJ,GAAG,CAAC,CAAI,CAAC;CAET,IAAM,IAAa,EAAc;CAIjC,OAFI,CAAC,KAAQ,CAAC,IAAmB,OAE1B,EACH,kBAAC,OAAD;EACI,WAAW,EAAO;EAClB,MAAK;EACL,eAAe;GACX,AAAI,KAAiB,EAAQ;EACjC;EAEA,UAAA,kBAAC,OAAD;GACI,KAAK;GACL,MAAK;GACL,cAAW;GACX,UAAU;GACV,mBAAiB,IAAQ,IAAU,KAAA;GACnC,cAAY,IAAQ,KAAA,IAAY;GAChC,WAAW,EACP,EAAO,QACP,EAAc,CAAI,GAClB,KAAc,EAAO,YACrB,KAAsB,EAAO,oBAC7B,CACJ;GACA,UAAU,MAAU,EAAM,gBAAgB;GAd9C,UAAA;KAgBM,KAAS,CAAC,MACR,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAA1B,UAAA,CACK,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW,EAAO;MAC9B,UAAA;KACD,CAAA,GAEP,CAAC,KACE,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,cAAW;MACX,SAAS;MAET,UAAA,kBAAC,GAAD,CAAY,CAAA;KACR,CAAA,CAER;;IAEZ,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;IAC3C,KAAU,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAAS,UAAA;IAAe,CAAA;GAC5D;;CACJ,CAAA,GACL,CACJ;AACJ;AAcA,SAAS,EAAc,GAAqC;CAGxD,OAFI,MAAS,QAAc,EAAO,UAC9B,MAAS,QAAc,EAAO,UAC3B,EAAO;AAClB;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EACjD,UAAA,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
@@ -1,3 +1,3 @@
1
1
  require("../../styles/component/Modal.css");
2
- var e=`tempest_overlay_dd9h1`,t=`tempest_tempest-fade-in_DvgSp`,n=`tempest_dialog_ptM-K`,r=`tempest_tempest-modal-in_UoxQC`,i=`tempest_sm_K5k3W`,a=`tempest_md_gvyR7`,o=`tempest_lg_BgB1a`,s=`tempest_xl_MR-68`,c=`tempest_size2xl_-PH9e`,l=`tempest_size3xl_iqDwN`,u=`tempest_fullscreen_o84Xi`,d=`tempest_fullscreenOnMobile_0bDwe`,f=`tempest_body_lVhql`,p=`tempest_header_ILG9i`,m=`tempest_footer_rro2w`,h=`tempest_title_A5OeE`,g=`tempest_close_-ER1C`,_={overlay:e,tempestFadeIn:t,dialog:n,tempestModalIn:r,sm:i,md:a,lg:o,xl:s,size2Xl:c,size3Xl:l,fullscreen:u,fullscreenOnMobile:d,body:f,header:p,footer:m,title:h,close:g};exports.body=f,exports.close=g,exports.default=_,exports.dialog=n,exports.footer=m,exports.fullscreen=u,exports.fullscreenOnMobile=d,exports.header=p,exports.lg=o,exports.md=a,exports.overlay=e,exports.size2Xl=c,exports.size3Xl=l,exports.sm=i,exports.tempestFadeIn=t,exports.tempestModalIn=r,exports.title=h,exports.xl=s;
2
+ var e=`tempest_overlay_dd9h1`,t=`tempest_tempest-fade-in_DvgSp`,n=`tempest_dialog_ptM-K`,r=`tempest_tempest-modal-in_UoxQC`,i=`tempest_sm_K5k3W`,a=`tempest_md_gvyR7`,o=`tempest_lg_BgB1a`,s=`tempest_xl_MR-68`,c=`tempest_size2Xl_oLq5O`,l=`tempest_size3Xl_YzlSH`,u=`tempest_fullscreen_o84Xi`,d=`tempest_fullscreenOnMobile_0bDwe`,f=`tempest_body_lVhql`,p=`tempest_header_ILG9i`,m=`tempest_footer_rro2w`,h=`tempest_title_A5OeE`,g=`tempest_close_-ER1C`,_={overlay:e,tempestFadeIn:t,dialog:n,tempestModalIn:r,sm:i,md:a,lg:o,xl:s,size2Xl:c,size3Xl:l,fullscreen:u,fullscreenOnMobile:d,body:f,header:p,footer:m,title:h,close:g};exports.body=f,exports.close=g,exports.default=_,exports.dialog=n,exports.footer=m,exports.fullscreen=u,exports.fullscreenOnMobile=d,exports.header=p,exports.lg=o,exports.md=a,exports.overlay=e,exports.size2Xl=c,exports.size3Xl=l,exports.sm=i,exports.tempestFadeIn=t,exports.tempestModalIn=r,exports.title=h,exports.xl=s;
3
3
  //# sourceMappingURL=Modal.module.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.module.cjs","names":[],"sources":["../../../src/components/Modal/Modal.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(15, 23, 42, 0.55);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: max(var(--tempest-space-4), var(--tempest-safe-area-top))\n max(var(--tempest-space-4), var(--tempest-safe-area-right))\n max(var(--tempest-space-4), var(--tempest-safe-area-bottom))\n max(var(--tempest-space-4), var(--tempest-safe-area-left));\n z-index: var(--tempest-z-modal);\n animation: tempest-fade-in var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.dialog {\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n border-radius: var(--tempest-radius-xl);\n box-shadow: var(--tempest-shadow-xl);\n width: 100%;\n max-height: 90vh;\n max-height: 90dvh;\n display: flex;\n flex-direction: column;\n animation: tempest-modal-in var(--tempest-duration-base) var(--tempest-ease-emphasized);\n}\n\n.sm {\n max-width: 400px;\n}\n.md {\n max-width: 560px;\n}\n.lg {\n max-width: 800px;\n}\n.xl {\n max-width: 1024px;\n}\n.size2xl {\n max-width: 1280px;\n}\n.size3xl {\n max-width: 1440px;\n}\n\n/* Fullscreen — fill entire viewport regardless of size. */\n.fullscreen {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n}\n\n/* Auto-fullscreen below mobile breakpoint. */\n@media (max-width: 639.98px) {\n .fullscreenOnMobile {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n }\n}\n\n/* Mobile padding adjustment for non-fullscreen modals. */\n@media (max-width: 639.98px) {\n .dialog:not(.fullscreen):not(.fullscreenOnMobile) {\n border-radius: var(--tempest-radius-lg);\n }\n .body {\n padding: var(--tempest-space-4);\n }\n .header,\n .footer {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n }\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-4) var(--tempest-space-5);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n margin: 0;\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n color: var(--tempest-text);\n}\n\n.close {\n background: none;\n border: none;\n color: var(--tempest-text-muted);\n padding: var(--tempest-space-1);\n border-radius: var(--tempest-radius-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .close:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.close:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.body {\n padding: var(--tempest-space-5);\n overflow-y: auto;\n line-height: var(--tempest-leading-normal);\n}\n\n.footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-4) var(--tempest-space-5);\n border-top: 1px solid var(--tempest-border);\n background-color: var(--tempest-surface);\n border-radius: 0 0 var(--tempest-radius-xl) var(--tempest-radius-xl);\n}\n\n@keyframes tempest-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes tempest-modal-in {\n from {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay,\n .dialog {\n animation: none;\n }\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Modal.module.cjs","names":[],"sources":["../../../src/components/Modal/Modal.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(15, 23, 42, 0.55);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: max(var(--tempest-space-4), var(--tempest-safe-area-top))\n max(var(--tempest-space-4), var(--tempest-safe-area-right))\n max(var(--tempest-space-4), var(--tempest-safe-area-bottom))\n max(var(--tempest-space-4), var(--tempest-safe-area-left));\n z-index: var(--tempest-z-modal);\n animation: tempest-fade-in var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.dialog {\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n border-radius: var(--tempest-radius-xl);\n box-shadow: var(--tempest-shadow-xl);\n width: 100%;\n max-height: 90vh;\n max-height: 90dvh;\n display: flex;\n flex-direction: column;\n animation: tempest-modal-in var(--tempest-duration-base) var(--tempest-ease-emphasized);\n}\n\n.sm {\n max-width: 400px;\n}\n.md {\n max-width: 560px;\n}\n.lg {\n max-width: 800px;\n}\n.xl {\n max-width: 1024px;\n}\n.size2Xl {\n max-width: 1280px;\n}\n.size3Xl {\n max-width: 1440px;\n}\n\n/* Fullscreen — fill entire viewport regardless of size. */\n.fullscreen {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n}\n\n/* Auto-fullscreen below mobile breakpoint. */\n@media (max-width: 639.98px) {\n .fullscreenOnMobile {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n }\n}\n\n/* Mobile padding adjustment for non-fullscreen modals. */\n@media (max-width: 639.98px) {\n .dialog:not(.fullscreen):not(.fullscreenOnMobile) {\n border-radius: var(--tempest-radius-lg);\n }\n .body {\n padding: var(--tempest-space-4);\n }\n .header,\n .footer {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n }\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-4) var(--tempest-space-5);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n margin: 0;\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n color: var(--tempest-text);\n}\n\n.close {\n background: none;\n border: none;\n color: var(--tempest-text-muted);\n padding: var(--tempest-space-1);\n border-radius: var(--tempest-radius-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .close:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.close:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.body {\n padding: var(--tempest-space-5);\n overflow-y: auto;\n line-height: var(--tempest-leading-normal);\n}\n\n.footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-4) var(--tempest-space-5);\n border-top: 1px solid var(--tempest-border);\n background-color: var(--tempest-surface);\n border-radius: 0 0 var(--tempest-radius-xl) var(--tempest-radius-xl);\n}\n\n@keyframes tempest-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes tempest-modal-in {\n from {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay,\n .dialog {\n animation: none;\n }\n}\n"],"mappings":";"}
@@ -1,6 +1,6 @@
1
1
  import "../../styles/component/Modal.css";
2
2
  //#region src/components/Modal/Modal.module.css
3
- var e = "tempest_overlay_dd9h1", t = "tempest_tempest-fade-in_DvgSp", n = "tempest_dialog_ptM-K", r = "tempest_tempest-modal-in_UoxQC", i = "tempest_sm_K5k3W", a = "tempest_md_gvyR7", o = "tempest_lg_BgB1a", s = "tempest_xl_MR-68", c = "tempest_size2xl_-PH9e", l = "tempest_size3xl_iqDwN", u = "tempest_fullscreen_o84Xi", d = "tempest_fullscreenOnMobile_0bDwe", f = "tempest_body_lVhql", p = "tempest_header_ILG9i", m = "tempest_footer_rro2w", h = "tempest_title_A5OeE", g = "tempest_close_-ER1C", _ = {
3
+ var e = "tempest_overlay_dd9h1", t = "tempest_tempest-fade-in_DvgSp", n = "tempest_dialog_ptM-K", r = "tempest_tempest-modal-in_UoxQC", i = "tempest_sm_K5k3W", a = "tempest_md_gvyR7", o = "tempest_lg_BgB1a", s = "tempest_xl_MR-68", c = "tempest_size2Xl_oLq5O", l = "tempest_size3Xl_YzlSH", u = "tempest_fullscreen_o84Xi", d = "tempest_fullscreenOnMobile_0bDwe", f = "tempest_body_lVhql", p = "tempest_header_ILG9i", m = "tempest_footer_rro2w", h = "tempest_title_A5OeE", g = "tempest_close_-ER1C", _ = {
4
4
  overlay: e,
5
5
  tempestFadeIn: t,
6
6
  dialog: n,
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.module.js","names":[],"sources":["../../../src/components/Modal/Modal.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(15, 23, 42, 0.55);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: max(var(--tempest-space-4), var(--tempest-safe-area-top))\n max(var(--tempest-space-4), var(--tempest-safe-area-right))\n max(var(--tempest-space-4), var(--tempest-safe-area-bottom))\n max(var(--tempest-space-4), var(--tempest-safe-area-left));\n z-index: var(--tempest-z-modal);\n animation: tempest-fade-in var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.dialog {\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n border-radius: var(--tempest-radius-xl);\n box-shadow: var(--tempest-shadow-xl);\n width: 100%;\n max-height: 90vh;\n max-height: 90dvh;\n display: flex;\n flex-direction: column;\n animation: tempest-modal-in var(--tempest-duration-base) var(--tempest-ease-emphasized);\n}\n\n.sm {\n max-width: 400px;\n}\n.md {\n max-width: 560px;\n}\n.lg {\n max-width: 800px;\n}\n.xl {\n max-width: 1024px;\n}\n.size2xl {\n max-width: 1280px;\n}\n.size3xl {\n max-width: 1440px;\n}\n\n/* Fullscreen — fill entire viewport regardless of size. */\n.fullscreen {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n}\n\n/* Auto-fullscreen below mobile breakpoint. */\n@media (max-width: 639.98px) {\n .fullscreenOnMobile {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n }\n}\n\n/* Mobile padding adjustment for non-fullscreen modals. */\n@media (max-width: 639.98px) {\n .dialog:not(.fullscreen):not(.fullscreenOnMobile) {\n border-radius: var(--tempest-radius-lg);\n }\n .body {\n padding: var(--tempest-space-4);\n }\n .header,\n .footer {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n }\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-4) var(--tempest-space-5);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n margin: 0;\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n color: var(--tempest-text);\n}\n\n.close {\n background: none;\n border: none;\n color: var(--tempest-text-muted);\n padding: var(--tempest-space-1);\n border-radius: var(--tempest-radius-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .close:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.close:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.body {\n padding: var(--tempest-space-5);\n overflow-y: auto;\n line-height: var(--tempest-leading-normal);\n}\n\n.footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-4) var(--tempest-space-5);\n border-top: 1px solid var(--tempest-border);\n background-color: var(--tempest-surface);\n border-radius: 0 0 var(--tempest-radius-xl) var(--tempest-radius-xl);\n}\n\n@keyframes tempest-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes tempest-modal-in {\n from {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay,\n .dialog {\n animation: none;\n }\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Modal.module.js","names":[],"sources":["../../../src/components/Modal/Modal.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(15, 23, 42, 0.55);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: max(var(--tempest-space-4), var(--tempest-safe-area-top))\n max(var(--tempest-space-4), var(--tempest-safe-area-right))\n max(var(--tempest-space-4), var(--tempest-safe-area-bottom))\n max(var(--tempest-space-4), var(--tempest-safe-area-left));\n z-index: var(--tempest-z-modal);\n animation: tempest-fade-in var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.dialog {\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n border-radius: var(--tempest-radius-xl);\n box-shadow: var(--tempest-shadow-xl);\n width: 100%;\n max-height: 90vh;\n max-height: 90dvh;\n display: flex;\n flex-direction: column;\n animation: tempest-modal-in var(--tempest-duration-base) var(--tempest-ease-emphasized);\n}\n\n.sm {\n max-width: 400px;\n}\n.md {\n max-width: 560px;\n}\n.lg {\n max-width: 800px;\n}\n.xl {\n max-width: 1024px;\n}\n.size2Xl {\n max-width: 1280px;\n}\n.size3Xl {\n max-width: 1440px;\n}\n\n/* Fullscreen — fill entire viewport regardless of size. */\n.fullscreen {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n}\n\n/* Auto-fullscreen below mobile breakpoint. */\n@media (max-width: 639.98px) {\n .fullscreenOnMobile {\n max-width: 100%;\n max-height: 100vh;\n max-height: 100dvh;\n width: 100%;\n height: 100%;\n border-radius: 0;\n }\n}\n\n/* Mobile padding adjustment for non-fullscreen modals. */\n@media (max-width: 639.98px) {\n .dialog:not(.fullscreen):not(.fullscreenOnMobile) {\n border-radius: var(--tempest-radius-lg);\n }\n .body {\n padding: var(--tempest-space-4);\n }\n .header,\n .footer {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n }\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-4) var(--tempest-space-5);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n margin: 0;\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n color: var(--tempest-text);\n}\n\n.close {\n background: none;\n border: none;\n color: var(--tempest-text-muted);\n padding: var(--tempest-space-1);\n border-radius: var(--tempest-radius-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .close:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.close:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.body {\n padding: var(--tempest-space-5);\n overflow-y: auto;\n line-height: var(--tempest-leading-normal);\n}\n\n.footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-4) var(--tempest-space-5);\n border-top: 1px solid var(--tempest-border);\n background-color: var(--tempest-surface);\n border-radius: 0 0 var(--tempest-radius-xl) var(--tempest-radius-xl);\n}\n\n@keyframes tempest-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes tempest-modal-in {\n from {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay,\n .dialog {\n animation: none;\n }\n}\n"],"mappings":";"}