@allxsmith/bestax-bulma 5.26.6 → 5.27.1

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 (342) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/columns/Column.js +48 -0
  4. package/dist/esm/columns/Column.js.map +1 -0
  5. package/dist/esm/columns/Columns.js +53 -0
  6. package/dist/esm/columns/Columns.js.map +1 -0
  7. package/dist/esm/components/Avatar.js +299 -0
  8. package/dist/esm/components/Avatar.js.map +1 -0
  9. package/dist/esm/components/Avatars.js +81 -0
  10. package/dist/esm/components/Avatars.js.map +1 -0
  11. package/dist/esm/components/Badge.js +105 -0
  12. package/dist/esm/components/Badge.js.map +1 -0
  13. package/dist/esm/components/Breadcrumb.js +36 -0
  14. package/dist/esm/components/Breadcrumb.js.map +1 -0
  15. package/dist/esm/components/Card.js +252 -0
  16. package/dist/esm/components/Card.js.map +1 -0
  17. package/dist/esm/components/Carousel.js +351 -0
  18. package/dist/esm/components/Carousel.js.map +1 -0
  19. package/dist/esm/components/Collapse.js +193 -0
  20. package/dist/esm/components/Collapse.js.map +1 -0
  21. package/dist/esm/components/Collapses.js +99 -0
  22. package/dist/esm/components/Collapses.js.map +1 -0
  23. package/dist/esm/components/Dialog.js +230 -0
  24. package/dist/esm/components/Dialog.js.map +1 -0
  25. package/dist/esm/components/Dropdown.js +362 -0
  26. package/dist/esm/components/Dropdown.js.map +1 -0
  27. package/dist/esm/components/Loading.js +87 -0
  28. package/dist/esm/components/Loading.js.map +1 -0
  29. package/dist/esm/components/Menu.js +117 -0
  30. package/dist/esm/components/Menu.js.map +1 -0
  31. package/dist/esm/components/Message.js +56 -0
  32. package/dist/esm/components/Message.js.map +1 -0
  33. package/dist/esm/components/Modal.js +354 -0
  34. package/dist/esm/components/Modal.js.map +1 -0
  35. package/dist/esm/components/Navbar.js +287 -0
  36. package/dist/esm/components/Navbar.js.map +1 -0
  37. package/dist/esm/components/Pagination.js +191 -0
  38. package/dist/esm/components/Pagination.js.map +1 -0
  39. package/dist/esm/components/Panel.js +100 -0
  40. package/dist/esm/components/Panel.js.map +1 -0
  41. package/dist/esm/components/Popover.js +298 -0
  42. package/dist/esm/components/Popover.js.map +1 -0
  43. package/dist/esm/components/Reveal.js +157 -0
  44. package/dist/esm/components/Reveal.js.map +1 -0
  45. package/dist/esm/components/Sidebar.js +209 -0
  46. package/dist/esm/components/Sidebar.js.map +1 -0
  47. package/dist/esm/components/Steps.js +128 -0
  48. package/dist/esm/components/Steps.js.map +1 -0
  49. package/dist/esm/components/Tabs.js +335 -0
  50. package/dist/esm/components/Tabs.js.map +1 -0
  51. package/dist/esm/components/Toast.js +322 -0
  52. package/dist/esm/components/Toast.js.map +1 -0
  53. package/dist/esm/components/Tooltip.js +202 -0
  54. package/dist/esm/components/Tooltip.js.map +1 -0
  55. package/dist/esm/components/collapsesContext.js +12 -0
  56. package/dist/esm/components/collapsesContext.js.map +1 -0
  57. package/dist/esm/elements/Block.js +29 -0
  58. package/dist/esm/elements/Block.js.map +1 -0
  59. package/dist/esm/elements/Box.js +32 -0
  60. package/dist/esm/elements/Box.js.map +1 -0
  61. package/dist/esm/elements/Button.js +139 -0
  62. package/dist/esm/elements/Button.js.map +1 -0
  63. package/dist/esm/elements/Buttons.js +42 -0
  64. package/dist/esm/elements/Buttons.js.map +1 -0
  65. package/dist/esm/elements/Code.js +25 -0
  66. package/dist/esm/elements/Code.js.map +1 -0
  67. package/dist/esm/elements/Content.js +33 -0
  68. package/dist/esm/elements/Content.js.map +1 -0
  69. package/dist/esm/elements/Delete.js +35 -0
  70. package/dist/esm/elements/Delete.js.map +1 -0
  71. package/dist/esm/elements/Divider.js +27 -0
  72. package/dist/esm/elements/Divider.js.map +1 -0
  73. package/dist/esm/elements/Emphasis.js +25 -0
  74. package/dist/esm/elements/Emphasis.js.map +1 -0
  75. package/dist/esm/elements/Figure.js +58 -0
  76. package/dist/esm/elements/Figure.js.map +1 -0
  77. package/dist/esm/elements/Icon.js +256 -0
  78. package/dist/esm/elements/Icon.js.map +1 -0
  79. package/dist/esm/elements/IconText.js +36 -0
  80. package/dist/esm/elements/IconText.js.map +1 -0
  81. package/dist/esm/elements/Image.js +46 -0
  82. package/dist/esm/elements/Image.js.map +1 -0
  83. package/dist/esm/elements/Link.js +36 -0
  84. package/dist/esm/elements/Link.js.map +1 -0
  85. package/dist/esm/elements/LinkButton.js +37 -0
  86. package/dist/esm/elements/LinkButton.js.map +1 -0
  87. package/dist/esm/elements/ListItem.js +28 -0
  88. package/dist/esm/elements/ListItem.js.map +1 -0
  89. package/dist/esm/elements/Loader.js +37 -0
  90. package/dist/esm/elements/Loader.js.map +1 -0
  91. package/dist/esm/elements/Notification.js +316 -0
  92. package/dist/esm/elements/Notification.js.map +1 -0
  93. package/dist/esm/elements/OrderedList.js +31 -0
  94. package/dist/esm/elements/OrderedList.js.map +1 -0
  95. package/dist/esm/elements/Paragraph.js +28 -0
  96. package/dist/esm/elements/Paragraph.js.map +1 -0
  97. package/dist/esm/elements/Pre.js +25 -0
  98. package/dist/esm/elements/Pre.js.map +1 -0
  99. package/dist/esm/elements/Progress.js +33 -0
  100. package/dist/esm/elements/Progress.js.map +1 -0
  101. package/dist/esm/elements/Skeleton.js +30 -0
  102. package/dist/esm/elements/Skeleton.js.map +1 -0
  103. package/dist/esm/elements/Span.js +28 -0
  104. package/dist/esm/elements/Span.js.map +1 -0
  105. package/dist/esm/elements/Strong.js +25 -0
  106. package/dist/esm/elements/Strong.js.map +1 -0
  107. package/dist/esm/elements/SubTitle.js +51 -0
  108. package/dist/esm/elements/SubTitle.js.map +1 -0
  109. package/dist/esm/elements/Table.js +51 -0
  110. package/dist/esm/elements/Table.js.map +1 -0
  111. package/dist/esm/elements/Tag.js +49 -0
  112. package/dist/esm/elements/Tag.js.map +1 -0
  113. package/dist/esm/elements/Tags.js +34 -0
  114. package/dist/esm/elements/Tags.js.map +1 -0
  115. package/dist/esm/elements/Tbody.js +26 -0
  116. package/dist/esm/elements/Tbody.js.map +1 -0
  117. package/dist/esm/elements/Td.js +61 -0
  118. package/dist/esm/elements/Td.js.map +1 -0
  119. package/dist/esm/elements/Tfoot.js +26 -0
  120. package/dist/esm/elements/Tfoot.js.map +1 -0
  121. package/dist/esm/elements/Th.js +34 -0
  122. package/dist/esm/elements/Th.js.map +1 -0
  123. package/dist/esm/elements/Thead.js +26 -0
  124. package/dist/esm/elements/Thead.js.map +1 -0
  125. package/dist/esm/elements/Title.js +44 -0
  126. package/dist/esm/elements/Title.js.map +1 -0
  127. package/dist/esm/elements/Tr.js +31 -0
  128. package/dist/esm/elements/Tr.js.map +1 -0
  129. package/dist/esm/elements/UnorderedList.js +31 -0
  130. package/dist/esm/elements/UnorderedList.js.map +1 -0
  131. package/dist/esm/elements/iconProps.js +49 -0
  132. package/dist/esm/elements/iconProps.js.map +1 -0
  133. package/dist/esm/form/Autocomplete.js +279 -0
  134. package/dist/esm/form/Autocomplete.js.map +1 -0
  135. package/dist/esm/form/Checkbox.js +111 -0
  136. package/dist/esm/form/Checkbox.js.map +1 -0
  137. package/dist/esm/form/Checkboxes.js +89 -0
  138. package/dist/esm/form/Checkboxes.js.map +1 -0
  139. package/dist/esm/form/Control.js +79 -0
  140. package/dist/esm/form/Control.js.map +1 -0
  141. package/dist/esm/form/DateInput.js +87 -0
  142. package/dist/esm/form/DateInput.js.map +1 -0
  143. package/dist/esm/form/DateInputBase.js +263 -0
  144. package/dist/esm/form/DateInputBase.js.map +1 -0
  145. package/dist/esm/form/DateRangeInput.js +76 -0
  146. package/dist/esm/form/DateRangeInput.js.map +1 -0
  147. package/dist/esm/form/DateRangeInputBase.js +301 -0
  148. package/dist/esm/form/DateRangeInputBase.js.map +1 -0
  149. package/dist/esm/form/DateTimeInput.js +87 -0
  150. package/dist/esm/form/DateTimeInput.js.map +1 -0
  151. package/dist/esm/form/DateTimeInputBase.js +333 -0
  152. package/dist/esm/form/DateTimeInputBase.js.map +1 -0
  153. package/dist/esm/form/Field.js +153 -0
  154. package/dist/esm/form/Field.js.map +1 -0
  155. package/dist/esm/form/File.js +109 -0
  156. package/dist/esm/form/File.js.map +1 -0
  157. package/dist/esm/form/FormContext.js +170 -0
  158. package/dist/esm/form/FormContext.js.map +1 -0
  159. package/dist/esm/form/Input.js +88 -0
  160. package/dist/esm/form/Input.js.map +1 -0
  161. package/dist/esm/form/InputBase.js +40 -0
  162. package/dist/esm/form/InputBase.js.map +1 -0
  163. package/dist/esm/form/Numberinput.js +199 -0
  164. package/dist/esm/form/Numberinput.js.map +1 -0
  165. package/dist/esm/form/Radio.js +108 -0
  166. package/dist/esm/form/Radio.js.map +1 -0
  167. package/dist/esm/form/Radios.js +91 -0
  168. package/dist/esm/form/Radios.js.map +1 -0
  169. package/dist/esm/form/Rate.js +279 -0
  170. package/dist/esm/form/Rate.js.map +1 -0
  171. package/dist/esm/form/Select.js +81 -0
  172. package/dist/esm/form/Select.js.map +1 -0
  173. package/dist/esm/form/SelectBase.js +54 -0
  174. package/dist/esm/form/SelectBase.js.map +1 -0
  175. package/dist/esm/form/Slider.js +459 -0
  176. package/dist/esm/form/Slider.js.map +1 -0
  177. package/dist/esm/form/Switch.js +96 -0
  178. package/dist/esm/form/Switch.js.map +1 -0
  179. package/dist/esm/form/Taginput.js +352 -0
  180. package/dist/esm/form/Taginput.js.map +1 -0
  181. package/dist/esm/form/TextArea.js +77 -0
  182. package/dist/esm/form/TextArea.js.map +1 -0
  183. package/dist/esm/form/TextAreaBase.js +45 -0
  184. package/dist/esm/form/TextAreaBase.js.map +1 -0
  185. package/dist/esm/form/TimeInput.js +83 -0
  186. package/dist/esm/form/TimeInput.js.map +1 -0
  187. package/dist/esm/form/TimeInputBase.js +246 -0
  188. package/dist/esm/form/TimeInputBase.js.map +1 -0
  189. package/dist/esm/form/_pickerInternals/Calendar.js +760 -0
  190. package/dist/esm/form/_pickerInternals/Calendar.js.map +1 -0
  191. package/dist/esm/form/_pickerInternals/PickerPopover.js +95 -0
  192. package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -0
  193. package/dist/esm/form/_pickerInternals/TimeWheels.js +721 -0
  194. package/dist/esm/form/_pickerInternals/TimeWheels.js.map +1 -0
  195. package/dist/esm/form/_pickerInternals/audioTick.js +109 -0
  196. package/dist/esm/form/_pickerInternals/audioTick.js.map +1 -0
  197. package/dist/esm/form/_pickerInternals/dateUtils.js +267 -0
  198. package/dist/esm/form/_pickerInternals/dateUtils.js.map +1 -0
  199. package/dist/esm/form/_pickerInternals/formatters.js +322 -0
  200. package/dist/esm/form/_pickerInternals/formatters.js.map +1 -0
  201. package/dist/esm/form/_pickerInternals/haptics.js +38 -0
  202. package/dist/esm/form/_pickerInternals/haptics.js.map +1 -0
  203. package/dist/esm/form/_pickerInternals/nativeInputSupport.js +25 -0
  204. package/dist/esm/form/_pickerInternals/nativeInputSupport.js.map +1 -0
  205. package/dist/esm/form/_pickerInternals/pickerTypes.js +50 -0
  206. package/dist/esm/form/_pickerInternals/pickerTypes.js.map +1 -0
  207. package/dist/esm/form/_pickerInternals/segmentMap.js +315 -0
  208. package/dist/esm/form/_pickerInternals/segmentMap.js.map +1 -0
  209. package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js +49 -0
  210. package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js.map +1 -0
  211. package/dist/esm/form/_pickerInternals/useSegmentedEntry.js +427 -0
  212. package/dist/esm/form/_pickerInternals/useSegmentedEntry.js.map +1 -0
  213. package/dist/esm/form/controlLoading.js +18 -0
  214. package/dist/esm/form/controlLoading.js.map +1 -0
  215. package/dist/esm/form/useAutoLabelId.js +54 -0
  216. package/dist/esm/form/useAutoLabelId.js.map +1 -0
  217. package/dist/esm/grid/Cell.js +35 -0
  218. package/dist/esm/grid/Cell.js.map +1 -0
  219. package/dist/esm/grid/Grid.js +51 -0
  220. package/dist/esm/grid/Grid.js.map +1 -0
  221. package/dist/esm/helpers/ClientOnly.js +33 -0
  222. package/dist/esm/helpers/ClientOnly.js.map +1 -0
  223. package/dist/esm/helpers/Config.js +60 -0
  224. package/dist/esm/helpers/Config.js.map +1 -0
  225. package/dist/esm/helpers/Theme.js +947 -0
  226. package/dist/esm/helpers/Theme.js.map +1 -0
  227. package/dist/esm/helpers/anchorAttrs.js +72 -0
  228. package/dist/esm/helpers/anchorAttrs.js.map +1 -0
  229. package/dist/esm/helpers/bulmaClassHelpers.js +415 -0
  230. package/dist/esm/helpers/bulmaClassHelpers.js.map +1 -0
  231. package/dist/esm/helpers/buttonType.js +24 -0
  232. package/dist/esm/helpers/buttonType.js.map +1 -0
  233. package/dist/esm/helpers/classNames.js +137 -0
  234. package/dist/esm/helpers/classNames.js.map +1 -0
  235. package/dist/esm/helpers/colorDeprecations.js +50 -0
  236. package/dist/esm/helpers/colorDeprecations.js.map +1 -0
  237. package/dist/esm/helpers/devWarnings.js +27 -0
  238. package/dist/esm/helpers/devWarnings.js.map +1 -0
  239. package/dist/esm/helpers/inertProps.js +27 -0
  240. package/dist/esm/helpers/inertProps.js.map +1 -0
  241. package/dist/esm/helpers/mergeBulmaStyles.js +20 -0
  242. package/dist/esm/helpers/mergeBulmaStyles.js.map +1 -0
  243. package/dist/esm/helpers/polymorphic.js +18 -0
  244. package/dist/esm/helpers/polymorphic.js.map +1 -0
  245. package/dist/esm/helpers/portal.js +76 -0
  246. package/dist/esm/helpers/portal.js.map +1 -0
  247. package/dist/esm/helpers/positionStacks.js +45 -0
  248. package/dist/esm/helpers/positionStacks.js.map +1 -0
  249. package/dist/esm/helpers/scrollLock.js +38 -0
  250. package/dist/esm/helpers/scrollLock.js.map +1 -0
  251. package/dist/esm/helpers/shadowDom.js +71 -0
  252. package/dist/esm/helpers/shadowDom.js.map +1 -0
  253. package/dist/esm/helpers/statusRegion.js +282 -0
  254. package/dist/esm/helpers/statusRegion.js.map +1 -0
  255. package/dist/esm/helpers/useAnchoredPosition.js +86 -0
  256. package/dist/esm/helpers/useAnchoredPosition.js.map +1 -0
  257. package/dist/esm/helpers/useBulmaClasses.js +158 -0
  258. package/dist/esm/helpers/useBulmaClasses.js.map +1 -0
  259. package/dist/esm/helpers/useClientLayoutEffect.js +13 -0
  260. package/dist/esm/helpers/useClientLayoutEffect.js.map +1 -0
  261. package/dist/esm/helpers/useColorClasses.js +84 -0
  262. package/dist/esm/helpers/useColorClasses.js.map +1 -0
  263. package/dist/esm/helpers/useFlexboxClasses.js +92 -0
  264. package/dist/esm/helpers/useFlexboxClasses.js.map +1 -0
  265. package/dist/esm/helpers/useFocusTrap.js +470 -0
  266. package/dist/esm/helpers/useFocusTrap.js.map +1 -0
  267. package/dist/esm/helpers/useIsHydrated.js +31 -0
  268. package/dist/esm/helpers/useIsHydrated.js.map +1 -0
  269. package/dist/esm/helpers/useOtherClasses.js +115 -0
  270. package/dist/esm/helpers/useOtherClasses.js.map +1 -0
  271. package/dist/esm/helpers/useSpacingClasses.js +82 -0
  272. package/dist/esm/helpers/useSpacingClasses.js.map +1 -0
  273. package/dist/esm/helpers/useTypographyClasses.js +93 -0
  274. package/dist/esm/helpers/useTypographyClasses.js.map +1 -0
  275. package/dist/esm/helpers/useVisibilityClasses.js +134 -0
  276. package/dist/esm/helpers/useVisibilityClasses.js.map +1 -0
  277. package/dist/esm/helpers/withSubComponents.js +24 -0
  278. package/dist/esm/helpers/withSubComponents.js.map +1 -0
  279. package/dist/esm/layout/Container.js +48 -0
  280. package/dist/esm/layout/Container.js.map +1 -0
  281. package/dist/esm/layout/Footer.js +33 -0
  282. package/dist/esm/layout/Footer.js.map +1 -0
  283. package/dist/esm/layout/Hero.js +90 -0
  284. package/dist/esm/layout/Hero.js.map +1 -0
  285. package/dist/esm/layout/Level.js +110 -0
  286. package/dist/esm/layout/Level.js.map +1 -0
  287. package/dist/esm/layout/Media.js +86 -0
  288. package/dist/esm/layout/Media.js.map +1 -0
  289. package/dist/esm/layout/Section.js +30 -0
  290. package/dist/esm/layout/Section.js.map +1 -0
  291. package/dist/extras.css +1 -1
  292. package/dist/extras.css.map +1 -1
  293. package/dist/index.cjs +821 -102
  294. package/dist/index.cjs.map +1 -1
  295. package/dist/index.esm.js +115 -16845
  296. package/dist/index.esm.js.map +1 -1
  297. package/dist/types/components/Tabs.d.ts +25 -3
  298. package/dist/types/elements/Icon.d.ts +10 -7
  299. package/dist/types/form/DateInputBase.d.ts +8 -6
  300. package/dist/types/form/DateRangeInput.d.ts +91 -0
  301. package/dist/types/form/DateRangeInputBase.d.ts +172 -0
  302. package/dist/types/form/DateTimeInputBase.d.ts +10 -6
  303. package/dist/types/form/File.d.ts +18 -5
  304. package/dist/types/form/FormContext.d.ts +11 -0
  305. package/dist/types/form/TimeInputBase.d.ts +1 -1
  306. package/dist/types/form/_pickerInternals/PickerPopover.d.ts +1 -0
  307. package/dist/types/form/_pickerInternals/dateUtils.d.ts +7 -0
  308. package/dist/types/form/_pickerInternals/formatters.d.ts +14 -0
  309. package/dist/types/form/_pickerInternals/pickerTypes.d.ts +13 -0
  310. package/dist/types/form/_pickerInternals/useSegmentedEntry.d.ts +12 -3
  311. package/dist/types/index.d.ts +4 -0
  312. package/dist/types-cjs/components/Tabs.d.ts +25 -3
  313. package/dist/types-cjs/elements/Icon.d.ts +10 -7
  314. package/dist/types-cjs/form/DateInputBase.d.ts +8 -6
  315. package/dist/types-cjs/form/DateRangeInput.d.ts +91 -0
  316. package/dist/types-cjs/form/DateRangeInputBase.d.ts +172 -0
  317. package/dist/types-cjs/form/DateTimeInputBase.d.ts +10 -6
  318. package/dist/types-cjs/form/File.d.ts +18 -5
  319. package/dist/types-cjs/form/FormContext.d.ts +11 -0
  320. package/dist/types-cjs/form/TimeInputBase.d.ts +1 -1
  321. package/dist/types-cjs/form/_pickerInternals/PickerPopover.d.ts +1 -0
  322. package/dist/types-cjs/form/_pickerInternals/dateUtils.d.ts +7 -0
  323. package/dist/types-cjs/form/_pickerInternals/formatters.d.ts +14 -0
  324. package/dist/types-cjs/form/_pickerInternals/pickerTypes.d.ts +13 -0
  325. package/dist/types-cjs/form/_pickerInternals/useSegmentedEntry.d.ts +12 -3
  326. package/dist/types-cjs/index.d.ts +4 -0
  327. package/dist/versions/bestax-no-dark-mode.css +1 -1
  328. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  329. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  330. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  331. package/dist/versions/bestax-no-helpers.css +1 -1
  332. package/dist/versions/bestax-no-helpers.css.map +1 -1
  333. package/dist/versions/bestax-prefixed.css +1 -1
  334. package/dist/versions/bestax-prefixed.css.map +1 -1
  335. package/package.json +1 -1
  336. package/src/scss/components/_tabs.scss +44 -0
  337. package/src/scss/form/_dateinput.scss +87 -8
  338. package/src/scss/form/_daterangeinput.scss +63 -0
  339. package/src/scss/form/_datetimeinput.scss +7 -2
  340. package/src/scss/form/_file.scss +37 -0
  341. package/src/scss/form/_index.scss +2 -0
  342. package/src/scss/form/_picker-popover.scss +1 -4
@@ -0,0 +1,53 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
4
+ import { withSubComponents } from '../helpers/withSubComponents.js';
5
+ import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
6
+ import { Column } from './Column.js';
7
+
8
+ /**
9
+ * The `Columns` component provides Bulma's flexible, responsive grid container for aligning and distributing [`Column`](./column.md) components.
10
+ *
11
+ * @function
12
+ * @param {ColumnsProps} props - Props for the Columns component.
13
+ * @returns {JSX.Element} The rendered columns container.
14
+ * @see {@link https://bulma.io/documentation/columns/ | Bulma Columns documentation}
15
+ */
16
+ const ColumnsComponent = ({ className, textColor, color: _fieldColor, bgColor, isCentered, isGapless, isMultiline, isVCentered, isMobile, isDesktop, gap, gapMobile, gapTablet, gapDesktop, gapWidescreen, gapFullhd, gapSize, gapSizeMobile, gapSizeTablet, gapSizeDesktop, gapSizeWidescreen, gapSizeFullhd, children, ...props }) => {
17
+ const resolvedGap = gap ?? gapSize;
18
+ const resolvedGapMobile = gapMobile ?? gapSizeMobile;
19
+ const resolvedGapTablet = gapTablet ?? gapSizeTablet;
20
+ const resolvedGapDesktop = gapDesktop ?? gapSizeDesktop;
21
+ const resolvedGapWidescreen = gapWidescreen ?? gapSizeWidescreen;
22
+ const resolvedGapFullhd = gapFullhd ?? gapSizeFullhd;
23
+ // Untyped code can still pass the gap helpers ColumnsProps leaves out. They
24
+ // are dropped here, so they render no class and never reach the DOM.
25
+ const { columnGap: _columnGap, rowGap: _rowGap, ...helperProps } = props;
26
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
27
+ color: textColor,
28
+ backgroundColor: bgColor,
29
+ ...helperProps,
30
+ });
31
+ const mainClass = usePrefixedClassNames('columns');
32
+ // Build gap classes with prefixes
33
+ const gapClasses = usePrefixedClassNames('', {
34
+ [`is-${resolvedGap}`]: resolvedGap !== undefined && resolvedGap !== null,
35
+ [`is-${resolvedGapMobile}-mobile`]: resolvedGapMobile !== undefined && resolvedGapMobile !== null,
36
+ [`is-${resolvedGapTablet}-tablet`]: resolvedGapTablet !== undefined && resolvedGapTablet !== null,
37
+ [`is-${resolvedGapDesktop}-desktop`]: resolvedGapDesktop !== undefined && resolvedGapDesktop !== null,
38
+ [`is-${resolvedGapWidescreen}-widescreen`]: resolvedGapWidescreen !== undefined && resolvedGapWidescreen !== null,
39
+ [`is-${resolvedGapFullhd}-fullhd`]: resolvedGapFullhd !== undefined && resolvedGapFullhd !== null,
40
+ 'is-centered': !!isCentered,
41
+ 'is-gapless': !!isGapless,
42
+ 'is-multiline': !!isMultiline,
43
+ 'is-vcentered': !!isVCentered,
44
+ 'is-mobile': !!isMobile,
45
+ 'is-desktop': !!isDesktop,
46
+ });
47
+ const columnsClasses = classNames(mainClass, gapClasses, className, bulmaHelperClasses);
48
+ return (jsx("div", { className: columnsClasses, ...rest, children: children }));
49
+ };
50
+ const Columns = withSubComponents(ColumnsComponent, { Column }, 'Columns');
51
+
52
+ export { Columns };
53
+ //# sourceMappingURL=Columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Columns.js","sources":["../../../src/columns/Columns.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport type { BulmaGapValue } from '../grid/Grid';\nimport { Column } from './Column';\n\n/**\n * Possible values for the Bulma columns gap size.\n * @deprecated Use {@link BulmaGapValue} instead — `gapSize*` and `gap*` share\n * the same 0-8 scale.\n */\nexport type BulmaGapSize = BulmaGapValue;\n\n/**\n * Props for the Columns component.\n */\nexport interface ColumnsProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n // The column and row gap helpers are left out, as the `gap` helper is: the\n // gutter is padding inside each column, so CSS `gap` would add to it, and\n // only from the tablet width up, where `.columns` is flex.\n Omit<\n BulmaClassesProps,\n 'color' | 'backgroundColor' | 'columnGap' | 'rowGap'\n > {\n /** Additional CSS classes for the columns container. */\n className?: string;\n /** Text color. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color modifier for all columns. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for all columns. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Horizontally center columns within the container. */\n isCentered?: boolean;\n /** Remove gap between columns. */\n isGapless?: boolean;\n /** Allow columns to wrap to multiple lines. */\n isMultiline?: boolean;\n /** Vertically center columns within the container. */\n isVCentered?: boolean;\n /** Apply columns layout on mobile and up. */\n isMobile?: boolean;\n /** Apply columns layout on desktop and up. */\n isDesktop?: boolean;\n\n /**\n * Gap size for all breakpoints, the columns gutter (`is-<value>`). Whole\n * steps of the same scale as `Grid`'s `gap` prop; wins over `gapSize` if\n * both are set.\n *\n * This is not the `gap` helper prop other components take, which renders\n * `is-gap-<value>`: on `Columns` the gutter is padding inside each column,\n * so the helper's CSS `gap` would add to it rather than replace it.\n */\n gap?: BulmaGapValue;\n /** Gap size for mobile. Wins over `gapSizeMobile` if both are set. */\n gapMobile?: BulmaGapValue;\n /** Gap size for tablet. Wins over `gapSizeTablet` if both are set. */\n gapTablet?: BulmaGapValue;\n /** Gap size for desktop. Wins over `gapSizeDesktop` if both are set. */\n gapDesktop?: BulmaGapValue;\n /** Gap size for widescreen. Wins over `gapSizeWidescreen` if both are set. */\n gapWidescreen?: BulmaGapValue;\n /** Gap size for fullhd. Wins over `gapSizeFullhd` if both are set. */\n gapFullhd?: BulmaGapValue;\n\n /** Gap size for all breakpoints. @deprecated Use `gap` instead — `gap` wins if both are set. */\n gapSize?: BulmaGapSize;\n /** Gap size for mobile. @deprecated Use `gapMobile` instead — `gapMobile` wins if both are set. */\n gapSizeMobile?: BulmaGapSize;\n /** Gap size for tablet. @deprecated Use `gapTablet` instead — `gapTablet` wins if both are set. */\n gapSizeTablet?: BulmaGapSize;\n /** Gap size for desktop. @deprecated Use `gapDesktop` instead — `gapDesktop` wins if both are set. */\n gapSizeDesktop?: BulmaGapSize;\n /** Gap size for widescreen. @deprecated Use `gapWidescreen` instead — `gapWidescreen` wins if both are set. */\n gapSizeWidescreen?: BulmaGapSize;\n /** Gap size for fullhd. @deprecated Use `gapFullhd` instead — `gapFullhd` wins if both are set. */\n gapSizeFullhd?: BulmaGapSize;\n\n /** Columns to render within the container. */\n children?: React.ReactNode;\n}\n\n/**\n * The `Columns` component provides Bulma's flexible, responsive grid container for aligning and distributing [`Column`](./column.md) components.\n *\n * @function\n * @param {ColumnsProps} props - Props for the Columns component.\n * @returns {JSX.Element} The rendered columns container.\n * @see {@link https://bulma.io/documentation/columns/ | Bulma Columns documentation}\n */\nconst ColumnsComponent: React.FC<ColumnsProps> = ({\n className,\n textColor,\n color: _fieldColor,\n bgColor,\n isCentered,\n isGapless,\n isMultiline,\n isVCentered,\n isMobile,\n isDesktop,\n gap,\n gapMobile,\n gapTablet,\n gapDesktop,\n gapWidescreen,\n gapFullhd,\n gapSize,\n gapSizeMobile,\n gapSizeTablet,\n gapSizeDesktop,\n gapSizeWidescreen,\n gapSizeFullhd,\n children,\n ...props\n}) => {\n const resolvedGap = gap ?? gapSize;\n const resolvedGapMobile = gapMobile ?? gapSizeMobile;\n const resolvedGapTablet = gapTablet ?? gapSizeTablet;\n const resolvedGapDesktop = gapDesktop ?? gapSizeDesktop;\n const resolvedGapWidescreen = gapWidescreen ?? gapSizeWidescreen;\n const resolvedGapFullhd = gapFullhd ?? gapSizeFullhd;\n\n // Untyped code can still pass the gap helpers ColumnsProps leaves out. They\n // are dropped here, so they render no class and never reach the DOM.\n const {\n columnGap: _columnGap,\n rowGap: _rowGap,\n ...helperProps\n } = props as typeof props & { columnGap?: unknown; rowGap?: unknown };\n\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...helperProps,\n });\n\n const mainClass = usePrefixedClassNames('columns');\n\n // Build gap classes with prefixes\n const gapClasses = usePrefixedClassNames('', {\n [`is-${resolvedGap}`]: resolvedGap !== undefined && resolvedGap !== null,\n [`is-${resolvedGapMobile}-mobile`]:\n resolvedGapMobile !== undefined && resolvedGapMobile !== null,\n [`is-${resolvedGapTablet}-tablet`]:\n resolvedGapTablet !== undefined && resolvedGapTablet !== null,\n [`is-${resolvedGapDesktop}-desktop`]:\n resolvedGapDesktop !== undefined && resolvedGapDesktop !== null,\n [`is-${resolvedGapWidescreen}-widescreen`]:\n resolvedGapWidescreen !== undefined && resolvedGapWidescreen !== null,\n [`is-${resolvedGapFullhd}-fullhd`]:\n resolvedGapFullhd !== undefined && resolvedGapFullhd !== null,\n 'is-centered': !!isCentered,\n 'is-gapless': !!isGapless,\n 'is-multiline': !!isMultiline,\n 'is-vcentered': !!isVCentered,\n 'is-mobile': !!isMobile,\n 'is-desktop': !!isDesktop,\n });\n\n const columnsClasses = classNames(\n mainClass,\n gapClasses,\n className,\n bulmaHelperClasses\n );\n\n return (\n <div className={columnsClasses} {...rest}>\n {children}\n </div>\n );\n};\n\nexport const Columns = withSubComponents(\n ColumnsComponent,\n { Column },\n 'Columns'\n);\n"],"names":["_jsx"],"mappings":";;;;;;;AA0FA;;;;;;;AAOG;AACH,MAAM,gBAAgB,GAA2B,CAAC,EAChD,SAAS,EACT,SAAS,EACT,KAAK,EAAE,WAAW,EAClB,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,QAAQ,EACR,SAAS,EACT,GAAG,EACH,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,EACb,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,QAAQ,EACR,GAAG,KAAK,EACT,KAAI;AACH,IAAA,MAAM,WAAW,GAAG,GAAG,IAAI,OAAO;AAClC,IAAA,MAAM,iBAAiB,GAAG,SAAS,IAAI,aAAa;AACpD,IAAA,MAAM,iBAAiB,GAAG,SAAS,IAAI,aAAa;AACpD,IAAA,MAAM,kBAAkB,GAAG,UAAU,IAAI,cAAc;AACvD,IAAA,MAAM,qBAAqB,GAAG,aAAa,IAAI,iBAAiB;AAChE,IAAA,MAAM,iBAAiB,GAAG,SAAS,IAAI,aAAa;;;AAIpD,IAAA,MAAM,EACJ,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,OAAO,EACf,GAAG,WAAW,EACf,GAAG,KAAiE;AAErE,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,GAAG,WAAW;AACf,KAAA,CAAC;AAEF,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,CAAC;;AAGlD,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,EAAE,EAAE;QAC3C,CAAC,CAAA,GAAA,EAAM,WAAW,CAAA,CAAE,GAAG,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,IAAI;QACxE,CAAC,CAAA,GAAA,EAAM,iBAAiB,CAAA,OAAA,CAAS,GAC/B,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,IAAI;QAC/D,CAAC,CAAA,GAAA,EAAM,iBAAiB,CAAA,OAAA,CAAS,GAC/B,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,IAAI;QAC/D,CAAC,CAAA,GAAA,EAAM,kBAAkB,CAAA,QAAA,CAAU,GACjC,kBAAkB,KAAK,SAAS,IAAI,kBAAkB,KAAK,IAAI;QACjE,CAAC,CAAA,GAAA,EAAM,qBAAqB,CAAA,WAAA,CAAa,GACvC,qBAAqB,KAAK,SAAS,IAAI,qBAAqB,KAAK,IAAI;QACvE,CAAC,CAAA,GAAA,EAAM,iBAAiB,CAAA,OAAA,CAAS,GAC/B,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,IAAI;QAC/D,aAAa,EAAE,CAAC,CAAC,UAAU;QAC3B,YAAY,EAAE,CAAC,CAAC,SAAS;QACzB,cAAc,EAAE,CAAC,CAAC,WAAW;QAC7B,cAAc,EAAE,CAAC,CAAC,WAAW;QAC7B,WAAW,EAAE,CAAC,CAAC,QAAQ;QACvB,YAAY,EAAE,CAAC,CAAC,SAAS;AAC1B,KAAA,CAAC;AAEF,IAAA,MAAM,cAAc,GAAG,UAAU,CAC/B,SAAS,EACT,UAAU,EACV,SAAS,EACT,kBAAkB,CACnB;IAED,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,cAAc,EAAA,GAAM,IAAI,EAAA,QAAA,EACrC,QAAQ,EAAA,CACL;AAEV,CAAC;AAEM,MAAM,OAAO,GAAG,iBAAiB,CACtC,gBAAgB,EAChB,EAAE,MAAM,EAAE,EACV,SAAS;;"}
@@ -0,0 +1,299 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef, useState, useRef, useEffect } from 'react';
4
+ import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
5
+ import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
6
+ import { buttonType } from '../helpers/buttonType.js';
7
+ import { isCustomElement } from '../helpers/polymorphic.js';
8
+ import { warnOnce } from '../helpers/devWarnings.js';
9
+
10
+ const avatarColors = [
11
+ 'primary',
12
+ 'link',
13
+ 'info',
14
+ 'success',
15
+ 'warning',
16
+ 'danger',
17
+ 'black',
18
+ 'dark',
19
+ 'light',
20
+ 'white',
21
+ ];
22
+ const autoAvatarColors = [
23
+ 'primary',
24
+ 'link',
25
+ 'info',
26
+ 'success',
27
+ 'warning',
28
+ 'danger',
29
+ ];
30
+ const avatarSizes = [
31
+ '16x16',
32
+ '24x24',
33
+ '32x32',
34
+ '48x48',
35
+ '64x64',
36
+ '96x96',
37
+ '128x128',
38
+ ];
39
+ /**
40
+ * The roles a caller can use to say "this avatar is not a control", and so claim
41
+ * the non-interactive treatment for a custom `as` target we would otherwise have
42
+ * to guess about.
43
+ *
44
+ * Read by VALUE, not by presence. Any role at all used to count, which let
45
+ * `role="button"` — a claim of the opposite — route a real control into the
46
+ * decorative branch and come out `aria-hidden` and nameless. `img` is what the
47
+ * fallback itself applies; `presentation` and `none` are the standard ways to say
48
+ * an element carries no semantics, which is what pairs with `alt=""`.
49
+ */
50
+ const NON_INTERACTIVE_ROLES = [
51
+ 'img',
52
+ 'presentation',
53
+ 'none',
54
+ ];
55
+ /**
56
+ * Elements other than `a` that declare `target` themselves, so on them it is
57
+ * the element's own attribute and not a link attribute Avatar withholds for
58
+ * want of one. The link attribute warning leaves `target` out on these, the way
59
+ * it leaves `rel` out everywhere. `area` and `base` are void elements, which
60
+ * Avatar's content rules out, so `form` is the one a caller can reach.
61
+ */
62
+ const ELEMENTS_WITH_OWN_TARGET = [
63
+ 'form',
64
+ 'area',
65
+ 'base',
66
+ ];
67
+ /**
68
+ * Derives a small set of initials from a name (e.g. "Ada Lovelace" -> "AL").
69
+ */
70
+ function getInitialsFromName(name) {
71
+ const words = name.trim().split(/\s+/).filter(Boolean);
72
+ if (words.length === 0)
73
+ return '';
74
+ // Iterate by code point (Array.from) so astral-plane characters (emoji, some
75
+ // CJK) don't get split into half surrogates.
76
+ if (words.length === 1) {
77
+ return Array.from(words[0]).slice(0, 2).join('').toUpperCase();
78
+ }
79
+ const first = Array.from(words[0])[0];
80
+ const last = Array.from(words[words.length - 1])[0];
81
+ return (first + last).toUpperCase();
82
+ }
83
+ /**
84
+ * Deterministically hashes a string to pick one of the auto avatar colors.
85
+ */
86
+ function getAutoColor(name) {
87
+ let hash = 0;
88
+ for (let i = 0; i < name.length; i++) {
89
+ hash = (hash << 5) - hash + name.charCodeAt(i);
90
+ hash |= 0;
91
+ }
92
+ const index = Math.abs(hash) % autoAvatarColors.length;
93
+ return autoAvatarColors[index];
94
+ }
95
+ /**
96
+ * Default generic avatar icon shown when there is no image, name, initials, or icon.
97
+ */
98
+ function DefaultAvatarIcon() {
99
+ return (jsx("svg", { viewBox: "0 0 24 24", width: "60%", height: "60%", "aria-hidden": "true", children: jsx("path", { fill: "currentColor", d: "M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0 2c-4.42 0-9 2.24-9 5v2a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1v-2c0-2.76-4.58-5-9-5Z" }) }));
100
+ }
101
+ /**
102
+ * The `Avatar` component represents a person or entity as a compact image.
103
+ *
104
+ * @function
105
+ * @param {AvatarProps} props - Props for the Avatar component.
106
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
107
+ * @returns {JSX.Element} The rendered avatar element.
108
+ *
109
+ * @example
110
+ * <Avatar src="/users/ada.jpg" name="Ada Lovelace" size="64x64" />
111
+ * @example
112
+ * <Avatar name="Grace Hopper" />
113
+ */
114
+ const Avatar = forwardRef(function Avatar(avatarProps, ref) {
115
+ const { className, src, alt, name, initials, icon, size, shape = 'circle', color, as, href, target, rel, imageProps, style, ...props } = avatarProps;
116
+ // Tracks the src that failed to load. A src change clears the latch during
117
+ // render (React's "reset state when props change" pattern) so a previously
118
+ // failed src is retried when switched back to. The img is additionally
119
+ // keyed by src so a swap discards the old DOM node — a late error event
120
+ // from the previous request can't fire on a retained node and latch the
121
+ // replacement src as failed.
122
+ const [erroredSrc, setErroredSrc] = useState(undefined);
123
+ const [prevSrc, setPrevSrc] = useState(src);
124
+ if (src !== prevSrc) {
125
+ setPrevSrc(src);
126
+ setErroredSrc(undefined);
127
+ }
128
+ const imgRef = useRef(null);
129
+ const { bulmaHelperClasses, rest } = useBulmaClasses(props);
130
+ const showImage = !!src && src !== erroredSrc;
131
+ // Catch images that failed before hydration: in SSR/static pages a broken
132
+ // image can finish loading before React attaches its onError, so it never
133
+ // fires. A complete image with no intrinsic width is a load failure.
134
+ useEffect(() => {
135
+ const img = imgRef.current;
136
+ if (img && img.complete && img.naturalWidth === 0) {
137
+ setErroredSrc(src);
138
+ }
139
+ }, [src]);
140
+ const resolvedInitials = initials
141
+ ? initials.toUpperCase()
142
+ : name
143
+ ? getInitialsFromName(name)
144
+ : '';
145
+ const showInitials = !showImage && !!resolvedInitials;
146
+ const showIcon = !showImage && !showInitials && !!icon;
147
+ const showDefaultIcon = !showImage && !showInitials && !showIcon;
148
+ const resolvedColor = color ?? (name ? getAutoColor(name) : undefined);
149
+ const isPresetSize = typeof size === 'string' && avatarSizes.includes(size);
150
+ const sizeStyle = typeof size === 'number'
151
+ ? { width: size, height: size, fontSize: size / 2.5 }
152
+ : undefined;
153
+ const avatarClasses = usePrefixedClassNames('avatar', {
154
+ [`is-${size}`]: isPresetSize,
155
+ [`is-${shape}`]: shape,
156
+ [`is-${resolvedColor}`]: resolvedColor && !showImage && avatarColors.includes(resolvedColor),
157
+ });
158
+ const combinedClasses = classNames(avatarClasses, bulmaHelperClasses, className);
159
+ const initialsClass = usePrefixedClassNames('avatar-initials');
160
+ const Tag = as ?? (href ? 'a' : 'figure');
161
+ // A custom component counts as interactive whether or not it was given OUR
162
+ // href: a router link takes `to`, creates the anchor itself, and cannot be
163
+ // classified from the props it arrives with (#668). Marking a real link as a
164
+ // picture is the worse failure — and `alt=""` would go further and mark it
165
+ // decorative (aria-hidden), leaving it nameless.
166
+ //
167
+ // A custom ELEMENT still needs the href. A hyphenated tag renders a real DOM
168
+ // element of that name, so nothing is hidden from us: without a link to follow
169
+ // it is still a picture. `Navbar.Link` draws the same line for `role="button"`.
170
+ //
171
+ // Where we are guessing, the caller settles it: an explicit `role` or
172
+ // `aria-hidden` states the semantics, so a custom component that really is a
173
+ // wrapper gets `role="img"` and its `alt=""` opt-out back. `role` alone would
174
+ // be a half-override — interactivity also drives the decorative opt-out and the
175
+ // name fallback, and overriding one of the three is worse than overriding none.
176
+ //
177
+ // An `href` ENDS the guess, so it outranks the signal. `as="a"`, `as="button"`
178
+ // and a target we were handed an href for are known to be interactive, and there
179
+ // the rule that an interactive element always carries an accessible name is not
180
+ // the caller's to waive: without this, `as={RouterLink} href="/x" role="img"`
181
+ // with `alt=""` rendered a real anchor as `aria-hidden` and nameless — the very
182
+ // failure #668 is about. `Navbar.Link` orders the same two the same way.
183
+ //
184
+ // The signal has to MEAN what it is used for, so both halves read a value rather
185
+ // than a presence — the way `Navbar.Link` reads `role === 'button'`. A role only
186
+ // claims to be a picture if it says so: `role="button"` or `role="link"` is the
187
+ // opposite claim, and taking any role as the signal handed an interactive-role
188
+ // element `aria-hidden` and no name. Likewise `aria-hidden={false}` denies
189
+ // hiding, so only a truthy one counts.
190
+ const ariaHidden = rest['aria-hidden'];
191
+ const statesItIsNotAControl = (rest.role !== undefined && NON_INTERACTIVE_ROLES.includes(rest.role)) ||
192
+ ariaHidden === true ||
193
+ ariaHidden === 'true';
194
+ const customTargetStatesSemantics = typeof Tag !== 'string' && href == null && statesItIsNotAControl;
195
+ const isInteractive = Tag === 'a' ||
196
+ Tag === 'button' ||
197
+ (typeof Tag !== 'string' && !customTargetStatesSemantics) ||
198
+ (isCustomElement(Tag) && href != null);
199
+ // Only forward link attributes when rendering an anchor or a custom (non-DOM)
200
+ // component; a plain `as="div"` must not receive a stray `href`/`target`/`rel`.
201
+ const isLinkLike = Tag === 'a' || typeof Tag !== 'string' || isCustomElement(Tag);
202
+ // A plain element like a `div` declares no `href` or `target`, so the type
203
+ // accepts them as Avatar's own while the drop below withholds them, and
204
+ // without this they would vanish in silence (#733). Forwarding them would put
205
+ // them where HTML has no such attribute, so the drop stays and development
206
+ // reports it instead, naming only the ones actually passed.
207
+ //
208
+ // `rel` is withheld too but left out here. React declares it on every
209
+ // element, so on a plain `as` it is that element's own attribute, and
210
+ // "render it as a link" would be the wrong advice for it. `target` is the
211
+ // same on an element that declares it, such as `form`, so it is left out
212
+ // there. Whether to forward either one to such an element is a separate
213
+ // question from this warning.
214
+ //
215
+ // Only for an `as` the caller wrote. Without one the element is Avatar's own
216
+ // choice, and a message naming an `as` they never passed sends them looking
217
+ // for it. A value counts when it is truthy, the same test that picks `'a'`
218
+ // over `'figure'`, so an empty `href` from data asks for no link and draws no
219
+ // warning. The key is the element plus the attributes passed, so a re-render
220
+ // or a list of avatars warns once, while a different combination on the same
221
+ // element still gets its own warning rather than hiding behind the first.
222
+ //
223
+ // Development-only is `warnOnce`'s job, as it is for the colour warnings, so
224
+ // this block has no production check of its own. One here would have to read
225
+ // `process` safely, and a `typeof process` test is not something a bundler
226
+ // replaces: in a browser it is false, and the warning never fired in the
227
+ // development builds it exists for. The cost is that production still
228
+ // collects the attributes and builds the message for an avatar that needs
229
+ // it, which is small and limited to the case the warning is about.
230
+ if (as != null && !isLinkLike) {
231
+ const dropped = Object.entries({
232
+ href,
233
+ target: ELEMENTS_WITH_OWN_TARGET.includes(as) ? undefined : target,
234
+ })
235
+ .filter(([, value]) => value)
236
+ .map(([key]) => key);
237
+ if (dropped.length > 0) {
238
+ warnOnce(`Avatar:link-props-on-${as}:${dropped.join('+')}`, `[bestax-bulma] <Avatar as="${as}" ${dropped.join(' ')}>: this ` +
239
+ `<${as}> renders without ` +
240
+ `${dropped.map(key => `"${key}"`).join(' and ')}, because Avatar ` +
241
+ `passes link attributes on only to a target that can be a link (an ` +
242
+ `"a", a custom element, or a component). To make it a link, render ` +
243
+ `it as="a" or pass a link component to "as".`);
244
+ }
245
+ }
246
+ // Present-only, not `{ href, target, rel }`. An unconditional spread hands the
247
+ // target these keys whatever the caller passed, and a key existing is not free:
248
+ // a target that tests for one sees a link where there is none, and one that
249
+ // spreads its own `{...rest}` onward passes the nothing along. It is NOT about
250
+ // a destructuring default, which an explicit `undefined` triggers just as an
251
+ // absent key does. What stops a target that REQUIRES one from being rendered
252
+ // without it is the type (#665) — this is the smaller half, and the backstop for
253
+ // the callers a type does not reach: a plain-JavaScript one and a loose spread,
254
+ // the same pair `Button` and `Menu.Item` keep their own filters for.
255
+ const linkProps = isLinkLike
256
+ ? {
257
+ ...(href !== undefined && { href }),
258
+ ...(target !== undefined && { target }),
259
+ ...(rel !== undefined && { rel }),
260
+ }
261
+ : {};
262
+ // alt coalesces with ?? (not ||) so an explicit alt="" survives as the
263
+ // standard decorative marker instead of being overridden by name.
264
+ const accessibleName = alt ?? name;
265
+ // The decorative opt-out never applies to an interactive avatar — a link or
266
+ // button must always expose an accessible name.
267
+ const isDecorative = alt === '' && !isInteractive;
268
+ const a11yDefaults = showImage
269
+ ? isInteractive && !accessibleName
270
+ ? // The img alt normally names the control; with no alt/name (an API
271
+ // returning only a photo URL) the link/button would be nameless.
272
+ { 'aria-label': name || 'Avatar' }
273
+ : {}
274
+ : isDecorative
275
+ ? { 'aria-hidden': true }
276
+ : {
277
+ ...(isInteractive ? {} : { role: 'img' }),
278
+ 'aria-label': accessibleName || name || 'Avatar',
279
+ };
280
+ // Each default yields to a value the caller passed, and is applied after
281
+ // `rest` reading through it rather than spread before it. React treats an
282
+ // `undefined` attribute as "remove it", and a spread carrying the key with no
283
+ // value is how that arrives, so a default spread first was erased by it: an
284
+ // `aria-label: undefined` left a button avatar nameless, and `role` and
285
+ // `aria-hidden` went the same way. The button `type` below has the same
286
+ // shape (#690).
287
+ const a11yProps = Object.fromEntries(Object.entries(a11yDefaults).map(([key, fallback]) => [
288
+ key,
289
+ rest[key] ?? fallback,
290
+ ]));
291
+ return (jsxs(Tag, { ref: ref, className: combinedClasses, style: { ...sizeStyle, ...style }, ...linkProps, ...rest, ...a11yProps, ...(Tag === 'button' ? { type: buttonType(rest.type) } : {}), children: [showImage && (jsx("img", { ...imageProps, ref: imgRef, src: src, alt: accessibleName ?? '', onError: e => {
292
+ imageProps?.onError?.(e);
293
+ setErroredSrc(src);
294
+ } }, src)), showInitials && (jsx("span", { className: initialsClass, children: resolvedInitials })), showIcon && icon, showDefaultIcon && jsx(DefaultAvatarIcon, {})] }));
295
+ });
296
+ Avatar.displayName = 'Avatar';
297
+
298
+ export { Avatar };
299
+ //# sourceMappingURL=Avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.js","sources":["../../../src/components/Avatar.tsx"],"sourcesContent":["import React, { forwardRef, useEffect, useRef, useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { buttonType } from '../helpers/buttonType';\nimport {\n isCustomElement,\n type PolymorphicComponent,\n} from '../helpers/polymorphic';\nimport { warnOnce } from '../helpers/devWarnings';\n\nconst avatarColors = [\n 'primary',\n 'link',\n 'info',\n 'success',\n 'warning',\n 'danger',\n 'black',\n 'dark',\n 'light',\n 'white',\n] as const;\n\n/** Valid color values for the Avatar component. */\nexport type AvatarColor = (typeof avatarColors)[number];\n\nconst autoAvatarColors: AvatarColor[] = [\n 'primary',\n 'link',\n 'info',\n 'success',\n 'warning',\n 'danger',\n];\n\nconst avatarSizes = [\n '16x16',\n '24x24',\n '32x32',\n '48x48',\n '64x64',\n '96x96',\n '128x128',\n] as const;\n\n/** Valid preset size values for the Avatar component. */\nexport type AvatarSize = (typeof avatarSizes)[number];\n\n/**\n * The roles a caller can use to say \"this avatar is not a control\", and so claim\n * the non-interactive treatment for a custom `as` target we would otherwise have\n * to guess about.\n *\n * Read by VALUE, not by presence. Any role at all used to count, which let\n * `role=\"button\"` — a claim of the opposite — route a real control into the\n * decorative branch and come out `aria-hidden` and nameless. `img` is what the\n * fallback itself applies; `presentation` and `none` are the standard ways to say\n * an element carries no semantics, which is what pairs with `alt=\"\"`.\n */\nconst NON_INTERACTIVE_ROLES: readonly string[] = [\n 'img',\n 'presentation',\n 'none',\n];\n\n/**\n * Elements other than `a` that declare `target` themselves, so on them it is\n * the element's own attribute and not a link attribute Avatar withholds for\n * want of one. The link attribute warning leaves `target` out on these, the way\n * it leaves `rel` out everywhere. `area` and `base` are void elements, which\n * Avatar's content rules out, so `form` is the one a caller can reach.\n */\nconst ELEMENTS_WITH_OWN_TARGET: readonly React.ElementType[] = [\n 'form',\n 'area',\n 'base',\n];\n\n/** Valid shape values for the Avatar component. */\nexport type AvatarShape = 'circle' | 'rounded' | 'square';\n\n/**\n * Derives a small set of initials from a name (e.g. \"Ada Lovelace\" -> \"AL\").\n */\nfunction getInitialsFromName(name: string): string {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return '';\n // Iterate by code point (Array.from) so astral-plane characters (emoji, some\n // CJK) don't get split into half surrogates.\n if (words.length === 1) {\n return Array.from(words[0]).slice(0, 2).join('').toUpperCase();\n }\n const first = Array.from(words[0])[0];\n const last = Array.from(words[words.length - 1])[0];\n return (first + last).toUpperCase();\n}\n\n/**\n * Deterministically hashes a string to pick one of the auto avatar colors.\n */\nfunction getAutoColor(name: string): AvatarColor {\n let hash = 0;\n for (let i = 0; i < name.length; i++) {\n hash = (hash << 5) - hash + name.charCodeAt(i);\n hash |= 0;\n }\n const index = Math.abs(hash) % autoAvatarColors.length;\n return autoAvatarColors[index];\n}\n\n/**\n * Default generic avatar icon shown when there is no image, name, initials, or icon.\n */\nfunction DefaultAvatarIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" width=\"60%\" height=\"60%\" aria-hidden=\"true\">\n <path\n fill=\"currentColor\"\n d=\"M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0 2c-4.42 0-9 2.24-9 5v2a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1v-2c0-2.76-4.58-5-9-5Z\"\n />\n </svg>\n );\n}\n\n/**\n * The Avatar component's own props — everything it adds on top of the\n * attributes of whatever element `as` renders.\n */\nexport interface AvatarOwnProps extends Omit<BulmaClassesProps, 'color'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** Image URL. On load error (or if absent), falls back to initials, then `icon`. */\n src?: string;\n /**\n * Alternate text for the image (used for the accessible name in every render mode). An\n * explicit `alt=\"\"` marks a non-interactive avatar as decorative.\n *\n * A link or button avatar is never decorative — it keeps an accessible name — and a custom\n * component passed to `as` counts as one unless it states otherwise, so `alt=\"\"` on a custom\n * wrapper needs that signal alongside it. `as` documents which props carry it.\n */\n alt?: string;\n /** Derives initials and a deterministic background color when no `src` is shown. */\n name?: string;\n /** Explicit initials override (else derived from `name`). */\n initials?: string;\n /** Final fallback, rendered when there is no `src`, `name`, or `initials`. */\n icon?: React.ReactNode;\n /** Preset size, or a pixel size when a number. */\n size?: AvatarSize | number;\n /** Avatar shape. Default `'circle'`. */\n shape?: AvatarShape;\n /** Background color for initials/icon avatars (else auto-derived from `name`). */\n color?: AvatarColor;\n /**\n * When set, renders the avatar as a link: an `<a>` unless `as` names the element itself. An\n * `as` target declaring its own `href` supersedes this one, and its type and its requiredness\n * are what apply.\n *\n * It is passed on only to a target that can be a link: an `a`, a custom element, or a\n * component. Any other `as` you pass, such as `'figure'` or `'div'`, still accepts it but\n * renders without it, because an `href` is not valid HTML on those elements, and a\n * development build logs a console warning naming what was dropped. To make such an avatar a\n * link, render it `as=\"a\"` or pass a link component to `as`. An empty `href` asks for no link:\n * with no `as` it renders a `<figure>`, and it draws no warning.\n */\n href?: string;\n /** Anchor target, passed on only where `href` is (an `a`, a custom element, or a component) and superseded by the target's own declaration the way `href` is. Any other `as` you pass renders without it, with the same development warning as `href`, except `'form'`: it declares its own `target`, so there the attribute is still withheld but draws no warning. */\n target?: string;\n /** Anchor rel, passed on only where `href` is (an `a`, a custom element, or a component) and superseded by the target's own declaration the way `href` is. */\n rel?: string;\n /** Extra props forwarded to the underlying `<img>` (e.g. `loading`, `crossOrigin`); its `onError` is chained before the fallback fires. */\n imageProps?: React.ImgHTMLAttributes<HTMLImageElement>;\n /** Inline styles, merged after the size style. */\n style?: React.CSSProperties;\n /**\n * Not accepted. Avatar always renders its own content — the image, the\n * initials, or the icon — so anything a caller passed would be replaced. It\n * is declared unavailable rather than derived from `as`, which would let a\n * target requiring `children` compel a value it then never receives.\n * @internal\n */\n children?: never;\n}\n\n/**\n * The own props Avatar hands to the element `as` names rather than consuming.\n *\n * They are what *chooses* the element when `as` is absent — an `<a>` with an\n * `href`, a `<figure>` without one — so Avatar has to accept them before `as` is\n * known. Declaring them is only half of it. `PolymorphicProps` explains what\n * naming them here buys, and what leaving them unnamed cost (#665).\n */\ntype AvatarForwardedProp = 'href' | 'target' | 'rel';\n\n/**\n * Props for the Avatar component. The DOM attributes and the `ref` both follow\n * `as`.\n *\n * `href`, `target` and `rel` are Avatar's own props only for a target that has\n * none of its own: `<Avatar href=\"/x\" />` needs no `as`, while\n * `<Avatar as={NextLink} />` takes `next/link`'s `href` — required, and a URL\n * object as readily as a string.\n *\n * The type parameter defaults to `'figure'`, not to `React.ElementType`.\n * Defaulting to the constraint sounds truer to a runtime default that is\n * conditional, but `ComponentPropsWithoutRef<React.ElementType>` spreads across\n * every element at once and accepts anything — which is the false-positive this\n * whole change exists to remove. `'figure'` is the element a no-`href` avatar\n * actually renders, and the anchor props it can additionally take are declared\n * above.\n *\n * @extraProp {PolymorphicRef<React.ElementType>} [ref] - Ref forwarded to the element `as` renders, typed from `as`: the DOM node for an intrinsic tag, or whatever handle a custom component exposes.\n */\nexport type AvatarProps<T extends React.ElementType = 'figure'> = Omit<\n AvatarOwnProps,\n Extract<AvatarForwardedProp, keyof React.ComponentPropsWithoutRef<T>>\n> &\n Omit<\n React.ComponentPropsWithoutRef<T>,\n Exclude<keyof AvatarOwnProps, AvatarForwardedProp> | 'as'\n > & {\n /**\n * Element/component to render as. Defaults to `'a'` when `href` is set, else `'figure'`.\n *\n * This also decides whether the avatar is treated as interactive, which is what keeps\n * `role=\"img\"` and the `alt=\"\"` decorative opt-out off a link or button. A custom\n * component counts — a router link takes `to` rather than this component's `href`, so\n * its own props cannot say — while `'a'`, `'button'`, and a custom element given an\n * `href` count for the reason they read.\n *\n * If your custom component renders something that really is just a picture, say so with\n * `role=\"img\"` and it is treated as one, `alt=\"\"` included. A truthy `aria-hidden` says it\n * too, and so do `role=\"presentation\"` and `role=\"none\"` — though ARIA's own conflict\n * resolution drops those two whenever the avatar still carries a name, so prefer\n * `role=\"img\"`. A role claiming the opposite, such as `\"button\"`, says nothing here, and\n * neither does an `href`: that settles it on its own. A genuine `'a'`/`'button'`/`href`\n * avatar keeps its accessible name either way.\n *\n * `'button'` renders `type=\"button\"` unless you pass `type=\"submit\"` or `type=\"reset\"`, so\n * an avatar inside a form does not submit it.\n */\n as?: T;\n };\n\n/**\n * The shape the implementation destructures. The public contract is the generic\n * `AvatarProps<T>` above — the body cannot see through `T`, so it names the\n * handful of DOM props it actually reads back off `rest`.\n */\ntype AvatarImplProps = AvatarOwnProps & {\n as?: React.ElementType;\n role?: React.AriaRole;\n 'aria-hidden'?: React.AriaAttributes['aria-hidden'];\n 'aria-label'?: string;\n type?: React.ButtonHTMLAttributes<HTMLButtonElement>['type'];\n};\n\n/**\n * The `Avatar` component represents a person or entity as a compact image.\n *\n * @function\n * @param {AvatarProps} props - Props for the Avatar component.\n * @param {React.Ref} ref - Forwarded ref to the element `as` renders.\n * @returns {JSX.Element} The rendered avatar element.\n *\n * @example\n * <Avatar src=\"/users/ada.jpg\" name=\"Ada Lovelace\" size=\"64x64\" />\n * @example\n * <Avatar name=\"Grace Hopper\" />\n */\nexport const Avatar = forwardRef(function Avatar(\n avatarProps: AvatarProps,\n ref: React.Ref<HTMLElement>\n) {\n const {\n className,\n src,\n alt,\n name,\n initials,\n icon,\n size,\n shape = 'circle',\n color,\n as,\n href,\n target,\n rel,\n imageProps,\n style,\n ...props\n } = avatarProps as AvatarImplProps;\n // Tracks the src that failed to load. A src change clears the latch during\n // render (React's \"reset state when props change\" pattern) so a previously\n // failed src is retried when switched back to. The img is additionally\n // keyed by src so a swap discards the old DOM node — a late error event\n // from the previous request can't fire on a retained node and latch the\n // replacement src as failed.\n const [erroredSrc, setErroredSrc] = useState<string | undefined>(undefined);\n const [prevSrc, setPrevSrc] = useState(src);\n if (src !== prevSrc) {\n setPrevSrc(src);\n setErroredSrc(undefined);\n }\n const imgRef = useRef<HTMLImageElement>(null);\n\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n const showImage = !!src && src !== erroredSrc;\n\n // Catch images that failed before hydration: in SSR/static pages a broken\n // image can finish loading before React attaches its onError, so it never\n // fires. A complete image with no intrinsic width is a load failure.\n useEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth === 0) {\n setErroredSrc(src);\n }\n }, [src]);\n\n const resolvedInitials = initials\n ? initials.toUpperCase()\n : name\n ? getInitialsFromName(name)\n : '';\n const showInitials = !showImage && !!resolvedInitials;\n const showIcon = !showImage && !showInitials && !!icon;\n const showDefaultIcon = !showImage && !showInitials && !showIcon;\n\n const resolvedColor = color ?? (name ? getAutoColor(name) : undefined);\n\n const isPresetSize = typeof size === 'string' && avatarSizes.includes(size);\n const sizeStyle =\n typeof size === 'number'\n ? { width: size, height: size, fontSize: size / 2.5 }\n : undefined;\n\n const avatarClasses = usePrefixedClassNames('avatar', {\n [`is-${size}`]: isPresetSize,\n [`is-${shape}`]: shape,\n [`is-${resolvedColor}`]:\n resolvedColor && !showImage && avatarColors.includes(resolvedColor),\n });\n\n const combinedClasses = classNames(\n avatarClasses,\n bulmaHelperClasses,\n className\n );\n\n const initialsClass = usePrefixedClassNames('avatar-initials');\n\n const Tag: React.ElementType = as ?? (href ? 'a' : 'figure');\n // A custom component counts as interactive whether or not it was given OUR\n // href: a router link takes `to`, creates the anchor itself, and cannot be\n // classified from the props it arrives with (#668). Marking a real link as a\n // picture is the worse failure — and `alt=\"\"` would go further and mark it\n // decorative (aria-hidden), leaving it nameless.\n //\n // A custom ELEMENT still needs the href. A hyphenated tag renders a real DOM\n // element of that name, so nothing is hidden from us: without a link to follow\n // it is still a picture. `Navbar.Link` draws the same line for `role=\"button\"`.\n //\n // Where we are guessing, the caller settles it: an explicit `role` or\n // `aria-hidden` states the semantics, so a custom component that really is a\n // wrapper gets `role=\"img\"` and its `alt=\"\"` opt-out back. `role` alone would\n // be a half-override — interactivity also drives the decorative opt-out and the\n // name fallback, and overriding one of the three is worse than overriding none.\n //\n // An `href` ENDS the guess, so it outranks the signal. `as=\"a\"`, `as=\"button\"`\n // and a target we were handed an href for are known to be interactive, and there\n // the rule that an interactive element always carries an accessible name is not\n // the caller's to waive: without this, `as={RouterLink} href=\"/x\" role=\"img\"`\n // with `alt=\"\"` rendered a real anchor as `aria-hidden` and nameless — the very\n // failure #668 is about. `Navbar.Link` orders the same two the same way.\n //\n // The signal has to MEAN what it is used for, so both halves read a value rather\n // than a presence — the way `Navbar.Link` reads `role === 'button'`. A role only\n // claims to be a picture if it says so: `role=\"button\"` or `role=\"link\"` is the\n // opposite claim, and taking any role as the signal handed an interactive-role\n // element `aria-hidden` and no name. Likewise `aria-hidden={false}` denies\n // hiding, so only a truthy one counts.\n const ariaHidden = rest['aria-hidden'];\n const statesItIsNotAControl =\n (rest.role !== undefined && NON_INTERACTIVE_ROLES.includes(rest.role)) ||\n ariaHidden === true ||\n ariaHidden === 'true';\n\n const customTargetStatesSemantics =\n typeof Tag !== 'string' && href == null && statesItIsNotAControl;\n\n const isInteractive =\n Tag === 'a' ||\n Tag === 'button' ||\n (typeof Tag !== 'string' && !customTargetStatesSemantics) ||\n (isCustomElement(Tag) && href != null);\n\n // Only forward link attributes when rendering an anchor or a custom (non-DOM)\n // component; a plain `as=\"div\"` must not receive a stray `href`/`target`/`rel`.\n const isLinkLike =\n Tag === 'a' || typeof Tag !== 'string' || isCustomElement(Tag);\n // A plain element like a `div` declares no `href` or `target`, so the type\n // accepts them as Avatar's own while the drop below withholds them, and\n // without this they would vanish in silence (#733). Forwarding them would put\n // them where HTML has no such attribute, so the drop stays and development\n // reports it instead, naming only the ones actually passed.\n //\n // `rel` is withheld too but left out here. React declares it on every\n // element, so on a plain `as` it is that element's own attribute, and\n // \"render it as a link\" would be the wrong advice for it. `target` is the\n // same on an element that declares it, such as `form`, so it is left out\n // there. Whether to forward either one to such an element is a separate\n // question from this warning.\n //\n // Only for an `as` the caller wrote. Without one the element is Avatar's own\n // choice, and a message naming an `as` they never passed sends them looking\n // for it. A value counts when it is truthy, the same test that picks `'a'`\n // over `'figure'`, so an empty `href` from data asks for no link and draws no\n // warning. The key is the element plus the attributes passed, so a re-render\n // or a list of avatars warns once, while a different combination on the same\n // element still gets its own warning rather than hiding behind the first.\n //\n // Development-only is `warnOnce`'s job, as it is for the colour warnings, so\n // this block has no production check of its own. One here would have to read\n // `process` safely, and a `typeof process` test is not something a bundler\n // replaces: in a browser it is false, and the warning never fired in the\n // development builds it exists for. The cost is that production still\n // collects the attributes and builds the message for an avatar that needs\n // it, which is small and limited to the case the warning is about.\n if (as != null && !isLinkLike) {\n const dropped = Object.entries({\n href,\n target: ELEMENTS_WITH_OWN_TARGET.includes(as) ? undefined : target,\n })\n .filter(([, value]) => value)\n .map(([key]) => key);\n if (dropped.length > 0) {\n warnOnce(\n `Avatar:link-props-on-${as}:${dropped.join('+')}`,\n `[bestax-bulma] <Avatar as=\"${as}\" ${dropped.join(' ')}>: this ` +\n `<${as}> renders without ` +\n `${dropped.map(key => `\"${key}\"`).join(' and ')}, because Avatar ` +\n `passes link attributes on only to a target that can be a link (an ` +\n `\"a\", a custom element, or a component). To make it a link, render ` +\n `it as=\"a\" or pass a link component to \"as\".`\n );\n }\n }\n // Present-only, not `{ href, target, rel }`. An unconditional spread hands the\n // target these keys whatever the caller passed, and a key existing is not free:\n // a target that tests for one sees a link where there is none, and one that\n // spreads its own `{...rest}` onward passes the nothing along. It is NOT about\n // a destructuring default, which an explicit `undefined` triggers just as an\n // absent key does. What stops a target that REQUIRES one from being rendered\n // without it is the type (#665) — this is the smaller half, and the backstop for\n // the callers a type does not reach: a plain-JavaScript one and a loose spread,\n // the same pair `Button` and `Menu.Item` keep their own filters for.\n const linkProps = isLinkLike\n ? {\n ...(href !== undefined && { href }),\n ...(target !== undefined && { target }),\n ...(rel !== undefined && { rel }),\n }\n : {};\n\n // alt coalesces with ?? (not ||) so an explicit alt=\"\" survives as the\n // standard decorative marker instead of being overridden by name.\n const accessibleName = alt ?? name;\n // The decorative opt-out never applies to an interactive avatar — a link or\n // button must always expose an accessible name.\n const isDecorative = alt === '' && !isInteractive;\n\n const a11yDefaults: {\n 'aria-label'?: string;\n role?: 'img';\n 'aria-hidden'?: true;\n } = showImage\n ? isInteractive && !accessibleName\n ? // The img alt normally names the control; with no alt/name (an API\n // returning only a photo URL) the link/button would be nameless.\n { 'aria-label': name || 'Avatar' }\n : {}\n : isDecorative\n ? { 'aria-hidden': true }\n : {\n ...(isInteractive ? {} : { role: 'img' as const }),\n 'aria-label': accessibleName || name || 'Avatar',\n };\n\n // Each default yields to a value the caller passed, and is applied after\n // `rest` reading through it rather than spread before it. React treats an\n // `undefined` attribute as \"remove it\", and a spread carrying the key with no\n // value is how that arrives, so a default spread first was erased by it: an\n // `aria-label: undefined` left a button avatar nameless, and `role` and\n // `aria-hidden` went the same way. The button `type` below has the same\n // shape (#690).\n const a11yProps = Object.fromEntries(\n Object.entries(a11yDefaults).map(([key, fallback]) => [\n key,\n rest[key as keyof typeof a11yDefaults] ?? fallback,\n ])\n );\n\n return (\n <Tag\n ref={ref}\n className={combinedClasses}\n style={{ ...sizeStyle, ...style }}\n {...linkProps}\n {...rest}\n {...a11yProps}\n // A clickable avatar inside a form must not submit it, and `<button>`\n // defaults to type=\"submit\". A caller's `submit` or `reset` still wins.\n // Anything else becomes `button`, since HTML reads a value it does not\n // define for a button as submit too; `buttonType` says more.\n //\n // After `rest`, reading through it rather than before it: React treats\n // `type={undefined}` as \"remove the attribute\", and a spread carrying the\n // key with no value is how that arrives. Spreading the default first let\n // such a spread erase it (#690), so the guard only held for callers who\n // passed nothing. `Dropdown.Item` and `Menu.Item` apply their button\n // type after the spread too.\n {...(Tag === 'button' ? { type: buttonType(rest.type) } : {})}\n >\n {showImage && (\n <img\n key={src}\n {...imageProps}\n ref={imgRef}\n src={src}\n alt={accessibleName ?? ''}\n onError={e => {\n imageProps?.onError?.(e);\n setErroredSrc(src);\n }}\n />\n )}\n {showInitials && (\n <span className={initialsClass}>{resolvedInitials}</span>\n )}\n {showIcon && icon}\n {showDefaultIcon && <DefaultAvatarIcon />}\n </Tag>\n );\n}) as PolymorphicComponent<AvatarOwnProps, 'figure', AvatarForwardedProp>;\n\nAvatar.displayName = 'Avatar';\n\nexport default Avatar;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import React from 'react';
4
+ import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
5
+ import { withSubComponents } from '../helpers/withSubComponents.js';
6
+ import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
7
+ import { Avatar } from './Avatar.js';
8
+
9
+ /**
10
+ * Flattens Fragment children (recursively) into a flat element array so they
11
+ * participate in max clamping and size/shape injection. Children.toArray keys
12
+ * restart at ".0" inside each fragment, so fragment children are re-keyed by
13
+ * prefixing the fragment's own key — otherwise a fragment sibling of a direct
14
+ * child would collide (both ".0") and trigger duplicate-key warnings.
15
+ */
16
+ function flattenChildren$1(children, keyPrefix = '') {
17
+ return React.Children.toArray(children).flatMap(child => {
18
+ if (!React.isValidElement(child))
19
+ return [];
20
+ if (child.type === React.Fragment) {
21
+ return flattenChildren$1(child.props.children, keyPrefix + child.key);
22
+ }
23
+ const el = child;
24
+ return [
25
+ keyPrefix ? React.cloneElement(el, { key: keyPrefix + el.key }) : el,
26
+ ];
27
+ });
28
+ }
29
+ /**
30
+ * The `Avatars` component renders an overlapping/stacked group of `Avatar`s, the "members" list pattern.
31
+ *
32
+ * @function
33
+ * @param {AvatarsProps} props - Props for the Avatars component.
34
+ * @returns {JSX.Element} The rendered avatars group.
35
+ *
36
+ * @example
37
+ * <Avatars max={3} size="48x48">
38
+ * {members.map(m => <Avatar key={m.id} src={m.photo} name={m.name} />)}
39
+ * </Avatars>
40
+ */
41
+ const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced = false, surplusLabel, style, children, ...props }) => {
42
+ const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
43
+ // A preset spacing maps to a class; a numeric spacing sets the CSS var inline
44
+ // (mirrors Sidebar's inline --bulma-* width var).
45
+ const isPresetSpacing = typeof spacing === 'string';
46
+ const avatarsClasses = usePrefixedClassNames('avatars', {
47
+ [`is-spacing-${spacing}`]: isPresetSpacing,
48
+ 'is-spaced': spaced,
49
+ });
50
+ const spacingStyle = typeof spacing === 'number'
51
+ ? { '--bulma-avatars-spacing': `${spacing}px` }
52
+ : undefined;
53
+ const surplusClass = usePrefixedClassNames('is-surplus');
54
+ const combinedClasses = classNames(avatarsClasses, bulmaHelperClasses, className);
55
+ const childArray = flattenChildren$1(children);
56
+ const maxCount = typeof max === 'number' && Number.isInteger(max) && max >= 0
57
+ ? max
58
+ : undefined;
59
+ const overshoot = maxCount !== undefined ? childArray.length - maxCount : 0;
60
+ // A "+1" surplus bubble occupies the same slot the hidden avatar would, so
61
+ // only collapse into a surplus when it stands in for two or more avatars; a
62
+ // single overflow avatar is shown directly.
63
+ const clamp = maxCount !== undefined && overshoot >= 2;
64
+ const visibleChildren = clamp ? childArray.slice(0, maxCount) : childArray;
65
+ const overflowCount = clamp ? overshoot : 0;
66
+ return (jsxs("div", { className: combinedClasses, style: { ...spacingStyle, ...style }, ...rest, children: [visibleChildren.map(child =>
67
+ // Conditional-spread so an unset group size/shape doesn't clobber a
68
+ // child that set its own.
69
+ React.cloneElement(child, {
70
+ ...(size !== undefined ? { size } : {}),
71
+ ...(shape !== undefined ? { shape } : {}),
72
+ })), overflowCount > 0 && (jsx(Avatar, { initials: `+${overflowCount}`, alt:
73
+ // `||` (not a plain ternary): an empty string from surplusLabel
74
+ // would make the bubble decorative (alt="") and hide the count
75
+ // from assistive tech — fall back to the default label instead.
76
+ surplusLabel?.(overflowCount) || `${overflowCount} more`, size: size, shape: shape, className: surplusClass }))] }));
77
+ };
78
+ const Avatars = withSubComponents(AvatarsComponent, { Avatar }, 'Avatars');
79
+
80
+ export { Avatars };
81
+ //# sourceMappingURL=Avatars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatars.js","sources":["../../../src/components/Avatars.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { Avatar, AvatarProps } from './Avatar';\n\n/** Valid overlap spacing values for the Avatars component. */\nexport type AvatarsSpacing = 'sm' | 'md' | 'lg';\n\n/**\n * Props for the Avatars component.\n */\nexport interface AvatarsProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'backgroundColor' | 'color'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** Show only the first `max` children, replacing the overflow with a \"+N\" surplus avatar. A single overflow avatar is shown directly rather than as a pointless \"+1\". */\n max?: number;\n /** Uniform size applied to every child `Avatar` (and the surplus avatar). */\n size?: AvatarProps['size'];\n /** Uniform shape applied to every child `Avatar` (and the surplus avatar); a child's own `shape` wins when this is unset. */\n shape?: AvatarProps['shape'];\n /** Space between avatars: a preset or a pixel `number`. The overlap distance, or the gap when `spaced`. */\n spacing?: AvatarsSpacing | number;\n /** Lay the avatars out side by side (non-overlapping), using `spacing` as the gap. */\n spaced?: boolean;\n /** Builds the surplus avatar's accessible name from the hidden count, for localization. Default: `` `${count} more` ``. */\n surplusLabel?: (count: number) => string;\n /** `Avatar` elements to render inside the group. */\n children?: React.ReactNode;\n}\n\n/**\n * Flattens Fragment children (recursively) into a flat element array so they\n * participate in max clamping and size/shape injection. Children.toArray keys\n * restart at \".0\" inside each fragment, so fragment children are re-keyed by\n * prefixing the fragment's own key — otherwise a fragment sibling of a direct\n * child would collide (both \".0\") and trigger duplicate-key warnings.\n */\nfunction flattenChildren(\n children: React.ReactNode,\n keyPrefix = ''\n): React.ReactElement<AvatarProps>[] {\n return React.Children.toArray(children).flatMap(child => {\n if (!React.isValidElement(child)) return [];\n if (child.type === React.Fragment) {\n return flattenChildren(\n (child.props as { children?: React.ReactNode }).children,\n keyPrefix + child.key\n );\n }\n const el = child as React.ReactElement<AvatarProps>;\n return [\n keyPrefix ? React.cloneElement(el, { key: keyPrefix + el.key }) : el,\n ];\n });\n}\n\n/**\n * The `Avatars` component renders an overlapping/stacked group of `Avatar`s, the \"members\" list pattern.\n *\n * @function\n * @param {AvatarsProps} props - Props for the Avatars component.\n * @returns {JSX.Element} The rendered avatars group.\n *\n * @example\n * <Avatars max={3} size=\"48x48\">\n * {members.map(m => <Avatar key={m.id} src={m.photo} name={m.name} />)}\n * </Avatars>\n */\nconst AvatarsComponent: React.FC<AvatarsProps> = ({\n className,\n max,\n size,\n shape,\n spacing = 'md',\n spaced = false,\n surplusLabel,\n style,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });\n\n // A preset spacing maps to a class; a numeric spacing sets the CSS var inline\n // (mirrors Sidebar's inline --bulma-* width var).\n const isPresetSpacing = typeof spacing === 'string';\n const avatarsClasses = usePrefixedClassNames('avatars', {\n [`is-spacing-${spacing}`]: isPresetSpacing,\n 'is-spaced': spaced,\n });\n const spacingStyle: React.CSSProperties | undefined =\n typeof spacing === 'number'\n ? ({ '--bulma-avatars-spacing': `${spacing}px` } as React.CSSProperties)\n : undefined;\n\n const surplusClass = usePrefixedClassNames('is-surplus');\n\n const combinedClasses = classNames(\n avatarsClasses,\n bulmaHelperClasses,\n className\n );\n\n const childArray = flattenChildren(children);\n\n const maxCount =\n typeof max === 'number' && Number.isInteger(max) && max >= 0\n ? max\n : undefined;\n const overshoot = maxCount !== undefined ? childArray.length - maxCount : 0;\n // A \"+1\" surplus bubble occupies the same slot the hidden avatar would, so\n // only collapse into a surplus when it stands in for two or more avatars; a\n // single overflow avatar is shown directly.\n const clamp = maxCount !== undefined && overshoot >= 2;\n const visibleChildren = clamp ? childArray.slice(0, maxCount) : childArray;\n const overflowCount = clamp ? overshoot : 0;\n\n return (\n <div\n className={combinedClasses}\n style={{ ...spacingStyle, ...style }}\n {...rest}\n >\n {visibleChildren.map(child =>\n // Conditional-spread so an unset group size/shape doesn't clobber a\n // child that set its own.\n React.cloneElement(child, {\n ...(size !== undefined ? { size } : {}),\n ...(shape !== undefined ? { shape } : {}),\n })\n )}\n {overflowCount > 0 && (\n <Avatar\n initials={`+${overflowCount}`}\n alt={\n // `||` (not a plain ternary): an empty string from surplusLabel\n // would make the bubble decorative (alt=\"\") and hide the count\n // from assistive tech — fall back to the default label instead.\n surplusLabel?.(overflowCount) || `${overflowCount} more`\n }\n size={size}\n shape={shape}\n className={surplusClass}\n />\n )}\n </div>\n );\n};\n\nexport const Avatars = withSubComponents(\n AvatarsComponent,\n { Avatar },\n 'Avatars'\n);\n\nexport default Avatars;\n"],"names":["flattenChildren","_jsxs","_jsx"],"mappings":"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"}