@oxy.so/bloom 4.16.1 → 4.18.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 (267) hide show
  1. package/docs/adoption-matrix.mdx +15 -15
  2. package/docs/app-shell.mdx +3 -2
  3. package/docs/breadcrumb.mdx +11 -0
  4. package/docs/button-group.mdx +2 -1
  5. package/docs/button.mdx +24 -0
  6. package/docs/cart-panel.mdx +4 -2
  7. package/docs/checkout-summary.mdx +4 -0
  8. package/docs/chip.mdx +14 -1
  9. package/docs/dialog.mdx +5 -4
  10. package/docs/icons.mdx +53 -0
  11. package/docs/loading.mdx +11 -0
  12. package/docs/page-header.mdx +7 -0
  13. package/docs/price-breakdown.mdx +17 -0
  14. package/docs/rating.mdx +22 -0
  15. package/docs/stepper.mdx +25 -0
  16. package/docs/tabs.mdx +6 -0
  17. package/lib/commonjs/app-shell/AppShellEngine.js +9 -5
  18. package/lib/commonjs/app-shell/AppShellEngine.js.map +1 -1
  19. package/lib/commonjs/breadcrumb/Breadcrumb.js +36 -6
  20. package/lib/commonjs/breadcrumb/Breadcrumb.js.map +1 -1
  21. package/lib/commonjs/button/Button.js +7 -4
  22. package/lib/commonjs/button/Button.js.map +1 -1
  23. package/lib/commonjs/button/Button.web.js +21 -2
  24. package/lib/commonjs/button/Button.web.js.map +1 -1
  25. package/lib/commonjs/button-group/ButtonGroup.js +7 -4
  26. package/lib/commonjs/button-group/ButtonGroup.js.map +1 -1
  27. package/lib/commonjs/cart-panel/CartLine.js +32 -10
  28. package/lib/commonjs/cart-panel/CartLine.js.map +1 -1
  29. package/lib/commonjs/cart-panel/CartPanel.js +3 -0
  30. package/lib/commonjs/cart-panel/CartPanel.js.map +1 -1
  31. package/lib/commonjs/cart-panel/shared.js +2 -0
  32. package/lib/commonjs/cart-panel/shared.js.map +1 -1
  33. package/lib/commonjs/checkout-summary/CheckoutConfirm.js +11 -1
  34. package/lib/commonjs/checkout-summary/CheckoutConfirm.js.map +1 -1
  35. package/lib/commonjs/chip/Chip.js +3 -1
  36. package/lib/commonjs/chip/Chip.js.map +1 -1
  37. package/lib/commonjs/dialog/Dialog.js +15 -6
  38. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  39. package/lib/commonjs/dialog/Dialog.web.js +11 -5
  40. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  41. package/lib/commonjs/dialog/placement.js +18 -1
  42. package/lib/commonjs/dialog/placement.js.map +1 -1
  43. package/lib/commonjs/icons/index.js +8 -0
  44. package/lib/commonjs/icons/index.js.map +1 -1
  45. package/lib/commonjs/icons/render-icon.js +63 -0
  46. package/lib/commonjs/icons/render-icon.js.map +1 -0
  47. package/lib/commonjs/loading/Loading.js +7 -3
  48. package/lib/commonjs/loading/Loading.js.map +1 -1
  49. package/lib/commonjs/loading/Loading.web.js +7 -3
  50. package/lib/commonjs/loading/Loading.web.js.map +1 -1
  51. package/lib/commonjs/loading/LoadingBase.js +49 -2
  52. package/lib/commonjs/loading/LoadingBase.js.map +1 -1
  53. package/lib/commonjs/page-header/PageHeader.js +6 -1
  54. package/lib/commonjs/page-header/PageHeader.js.map +1 -1
  55. package/lib/commonjs/price-breakdown/PriceSummary.js +11 -1
  56. package/lib/commonjs/price-breakdown/PriceSummary.js.map +1 -1
  57. package/lib/commonjs/price-breakdown/PriceSummaryLine.js +13 -1
  58. package/lib/commonjs/price-breakdown/PriceSummaryLine.js.map +1 -1
  59. package/lib/commonjs/rating/Rating.js +90 -4
  60. package/lib/commonjs/rating/Rating.js.map +1 -1
  61. package/lib/commonjs/stepper/Stepper.js +18 -5
  62. package/lib/commonjs/stepper/Stepper.js.map +1 -1
  63. package/lib/commonjs/tabs/Tabs.js +8 -1
  64. package/lib/commonjs/tabs/Tabs.js.map +1 -1
  65. package/lib/module/app-shell/AppShellEngine.js +9 -5
  66. package/lib/module/app-shell/AppShellEngine.js.map +1 -1
  67. package/lib/module/breadcrumb/Breadcrumb.js +36 -6
  68. package/lib/module/breadcrumb/Breadcrumb.js.map +1 -1
  69. package/lib/module/button/Button.js +7 -4
  70. package/lib/module/button/Button.js.map +1 -1
  71. package/lib/module/button/Button.web.js +21 -2
  72. package/lib/module/button/Button.web.js.map +1 -1
  73. package/lib/module/button-group/ButtonGroup.js +7 -4
  74. package/lib/module/button-group/ButtonGroup.js.map +1 -1
  75. package/lib/module/cart-panel/CartLine.js +32 -10
  76. package/lib/module/cart-panel/CartLine.js.map +1 -1
  77. package/lib/module/cart-panel/CartPanel.js +3 -0
  78. package/lib/module/cart-panel/CartPanel.js.map +1 -1
  79. package/lib/module/cart-panel/shared.js +2 -0
  80. package/lib/module/cart-panel/shared.js.map +1 -1
  81. package/lib/module/checkout-summary/CheckoutConfirm.js +11 -1
  82. package/lib/module/checkout-summary/CheckoutConfirm.js.map +1 -1
  83. package/lib/module/chip/Chip.js +3 -1
  84. package/lib/module/chip/Chip.js.map +1 -1
  85. package/lib/module/dialog/Dialog.js +16 -7
  86. package/lib/module/dialog/Dialog.js.map +1 -1
  87. package/lib/module/dialog/Dialog.web.js +12 -6
  88. package/lib/module/dialog/Dialog.web.js.map +1 -1
  89. package/lib/module/dialog/placement.js +17 -1
  90. package/lib/module/dialog/placement.js.map +1 -1
  91. package/lib/module/icons/index.js +1 -0
  92. package/lib/module/icons/index.js.map +1 -1
  93. package/lib/module/icons/render-icon.js +59 -0
  94. package/lib/module/icons/render-icon.js.map +1 -0
  95. package/lib/module/loading/Loading.js +8 -4
  96. package/lib/module/loading/Loading.js.map +1 -1
  97. package/lib/module/loading/Loading.web.js +8 -4
  98. package/lib/module/loading/Loading.web.js.map +1 -1
  99. package/lib/module/loading/LoadingBase.js +49 -3
  100. package/lib/module/loading/LoadingBase.js.map +1 -1
  101. package/lib/module/page-header/PageHeader.js +6 -1
  102. package/lib/module/page-header/PageHeader.js.map +1 -1
  103. package/lib/module/price-breakdown/PriceSummary.js +11 -1
  104. package/lib/module/price-breakdown/PriceSummary.js.map +1 -1
  105. package/lib/module/price-breakdown/PriceSummaryLine.js +13 -1
  106. package/lib/module/price-breakdown/PriceSummaryLine.js.map +1 -1
  107. package/lib/module/rating/Rating.js +89 -4
  108. package/lib/module/rating/Rating.js.map +1 -1
  109. package/lib/module/stepper/Stepper.js +18 -5
  110. package/lib/module/stepper/Stepper.js.map +1 -1
  111. package/lib/module/tabs/Tabs.js +8 -1
  112. package/lib/module/tabs/Tabs.js.map +1 -1
  113. package/lib/typescript/commonjs/app-shell/AppShellEngine.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/breadcrumb/Breadcrumb.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/breadcrumb/types.d.ts +7 -0
  116. package/lib/typescript/commonjs/breadcrumb/types.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/button/Button.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/button/Button.web.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/button/types.d.ts +10 -0
  120. package/lib/typescript/commonjs/button/types.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/button-group/ButtonGroup.d.ts.map +1 -1
  122. package/lib/typescript/commonjs/button-group/types.d.ts +9 -0
  123. package/lib/typescript/commonjs/button-group/types.d.ts.map +1 -1
  124. package/lib/typescript/commonjs/cart-panel/CartLine.d.ts +10 -5
  125. package/lib/typescript/commonjs/cart-panel/CartLine.d.ts.map +1 -1
  126. package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts +1 -1
  127. package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts.map +1 -1
  128. package/lib/typescript/commonjs/cart-panel/shared.d.ts +1 -1
  129. package/lib/typescript/commonjs/cart-panel/shared.d.ts.map +1 -1
  130. package/lib/typescript/commonjs/cart-panel/types.d.ts +18 -0
  131. package/lib/typescript/commonjs/cart-panel/types.d.ts.map +1 -1
  132. package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts +4 -1
  133. package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
  134. package/lib/typescript/commonjs/checkout-summary/types.d.ts +6 -0
  135. package/lib/typescript/commonjs/checkout-summary/types.d.ts.map +1 -1
  136. package/lib/typescript/commonjs/chip/Chip.d.ts.map +1 -1
  137. package/lib/typescript/commonjs/chip/types.d.ts +8 -6
  138. package/lib/typescript/commonjs/chip/types.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  140. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/dialog/placement.d.ts +13 -2
  142. package/lib/typescript/commonjs/dialog/placement.d.ts.map +1 -1
  143. package/lib/typescript/commonjs/dialog/types.d.ts +3 -2
  144. package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/icons/index.d.ts +2 -0
  146. package/lib/typescript/commonjs/icons/index.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/icons/render-icon.d.ts +55 -0
  148. package/lib/typescript/commonjs/icons/render-icon.d.ts.map +1 -0
  149. package/lib/typescript/commonjs/loading/Loading.d.ts.map +1 -1
  150. package/lib/typescript/commonjs/loading/Loading.web.d.ts.map +1 -1
  151. package/lib/typescript/commonjs/loading/LoadingBase.d.ts +18 -0
  152. package/lib/typescript/commonjs/loading/LoadingBase.d.ts.map +1 -1
  153. package/lib/typescript/commonjs/loading/types.d.ts +11 -0
  154. package/lib/typescript/commonjs/loading/types.d.ts.map +1 -1
  155. package/lib/typescript/commonjs/page-header/PageHeader.d.ts.map +1 -1
  156. package/lib/typescript/commonjs/price-breakdown/PriceSummary.d.ts.map +1 -1
  157. package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts +3 -1
  158. package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
  159. package/lib/typescript/commonjs/price-breakdown/types.d.ts +12 -0
  160. package/lib/typescript/commonjs/price-breakdown/types.d.ts.map +1 -1
  161. package/lib/typescript/commonjs/rating/Rating.d.ts +3 -1
  162. package/lib/typescript/commonjs/rating/Rating.d.ts.map +1 -1
  163. package/lib/typescript/commonjs/rating/index.d.ts +1 -1
  164. package/lib/typescript/commonjs/rating/index.d.ts.map +1 -1
  165. package/lib/typescript/commonjs/rating/types.d.ts +20 -0
  166. package/lib/typescript/commonjs/rating/types.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/stepper/Stepper.d.ts +1 -1
  168. package/lib/typescript/commonjs/stepper/Stepper.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/stepper/types.d.ts +9 -0
  170. package/lib/typescript/commonjs/stepper/types.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/tabs/Tabs.d.ts.map +1 -1
  172. package/lib/typescript/module/app-shell/AppShellEngine.d.ts.map +1 -1
  173. package/lib/typescript/module/breadcrumb/Breadcrumb.d.ts.map +1 -1
  174. package/lib/typescript/module/breadcrumb/types.d.ts +7 -0
  175. package/lib/typescript/module/breadcrumb/types.d.ts.map +1 -1
  176. package/lib/typescript/module/button/Button.d.ts.map +1 -1
  177. package/lib/typescript/module/button/Button.web.d.ts.map +1 -1
  178. package/lib/typescript/module/button/types.d.ts +10 -0
  179. package/lib/typescript/module/button/types.d.ts.map +1 -1
  180. package/lib/typescript/module/button-group/ButtonGroup.d.ts.map +1 -1
  181. package/lib/typescript/module/button-group/types.d.ts +9 -0
  182. package/lib/typescript/module/button-group/types.d.ts.map +1 -1
  183. package/lib/typescript/module/cart-panel/CartLine.d.ts +10 -5
  184. package/lib/typescript/module/cart-panel/CartLine.d.ts.map +1 -1
  185. package/lib/typescript/module/cart-panel/CartPanel.d.ts +1 -1
  186. package/lib/typescript/module/cart-panel/CartPanel.d.ts.map +1 -1
  187. package/lib/typescript/module/cart-panel/shared.d.ts +1 -1
  188. package/lib/typescript/module/cart-panel/shared.d.ts.map +1 -1
  189. package/lib/typescript/module/cart-panel/types.d.ts +18 -0
  190. package/lib/typescript/module/cart-panel/types.d.ts.map +1 -1
  191. package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts +4 -1
  192. package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
  193. package/lib/typescript/module/checkout-summary/types.d.ts +6 -0
  194. package/lib/typescript/module/checkout-summary/types.d.ts.map +1 -1
  195. package/lib/typescript/module/chip/Chip.d.ts.map +1 -1
  196. package/lib/typescript/module/chip/types.d.ts +8 -6
  197. package/lib/typescript/module/chip/types.d.ts.map +1 -1
  198. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  199. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  200. package/lib/typescript/module/dialog/placement.d.ts +13 -2
  201. package/lib/typescript/module/dialog/placement.d.ts.map +1 -1
  202. package/lib/typescript/module/dialog/types.d.ts +3 -2
  203. package/lib/typescript/module/dialog/types.d.ts.map +1 -1
  204. package/lib/typescript/module/icons/index.d.ts +2 -0
  205. package/lib/typescript/module/icons/index.d.ts.map +1 -1
  206. package/lib/typescript/module/icons/render-icon.d.ts +55 -0
  207. package/lib/typescript/module/icons/render-icon.d.ts.map +1 -0
  208. package/lib/typescript/module/loading/Loading.d.ts.map +1 -1
  209. package/lib/typescript/module/loading/Loading.web.d.ts.map +1 -1
  210. package/lib/typescript/module/loading/LoadingBase.d.ts +18 -0
  211. package/lib/typescript/module/loading/LoadingBase.d.ts.map +1 -1
  212. package/lib/typescript/module/loading/types.d.ts +11 -0
  213. package/lib/typescript/module/loading/types.d.ts.map +1 -1
  214. package/lib/typescript/module/page-header/PageHeader.d.ts.map +1 -1
  215. package/lib/typescript/module/price-breakdown/PriceSummary.d.ts.map +1 -1
  216. package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts +3 -1
  217. package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
  218. package/lib/typescript/module/price-breakdown/types.d.ts +12 -0
  219. package/lib/typescript/module/price-breakdown/types.d.ts.map +1 -1
  220. package/lib/typescript/module/rating/Rating.d.ts +3 -1
  221. package/lib/typescript/module/rating/Rating.d.ts.map +1 -1
  222. package/lib/typescript/module/rating/index.d.ts +1 -1
  223. package/lib/typescript/module/rating/index.d.ts.map +1 -1
  224. package/lib/typescript/module/rating/types.d.ts +20 -0
  225. package/lib/typescript/module/rating/types.d.ts.map +1 -1
  226. package/lib/typescript/module/stepper/Stepper.d.ts +1 -1
  227. package/lib/typescript/module/stepper/Stepper.d.ts.map +1 -1
  228. package/lib/typescript/module/stepper/types.d.ts +9 -0
  229. package/lib/typescript/module/stepper/types.d.ts.map +1 -1
  230. package/lib/typescript/module/tabs/Tabs.d.ts.map +1 -1
  231. package/package.json +1 -1
  232. package/src/app-shell/AppShellEngine.tsx +9 -5
  233. package/src/breadcrumb/Breadcrumb.tsx +29 -4
  234. package/src/breadcrumb/types.ts +7 -0
  235. package/src/button/Button.tsx +15 -6
  236. package/src/button/Button.web.tsx +30 -3
  237. package/src/button/types.ts +10 -0
  238. package/src/button-group/ButtonGroup.tsx +15 -6
  239. package/src/button-group/types.ts +9 -0
  240. package/src/cart-panel/CartLine.tsx +30 -7
  241. package/src/cart-panel/CartPanel.tsx +3 -0
  242. package/src/cart-panel/shared.ts +11 -1
  243. package/src/cart-panel/types.ts +18 -0
  244. package/src/checkout-summary/CheckoutConfirm.tsx +9 -0
  245. package/src/checkout-summary/types.ts +6 -0
  246. package/src/chip/Chip.tsx +3 -1
  247. package/src/chip/types.ts +8 -6
  248. package/src/dialog/Dialog.tsx +19 -8
  249. package/src/dialog/Dialog.web.tsx +15 -7
  250. package/src/dialog/placement.ts +19 -2
  251. package/src/dialog/types.ts +3 -2
  252. package/src/icons/index.ts +2 -0
  253. package/src/icons/render-icon.tsx +65 -0
  254. package/src/loading/Loading.tsx +6 -2
  255. package/src/loading/Loading.web.tsx +6 -2
  256. package/src/loading/LoadingBase.tsx +55 -5
  257. package/src/loading/types.ts +11 -0
  258. package/src/page-header/PageHeader.tsx +6 -1
  259. package/src/price-breakdown/PriceSummary.tsx +10 -0
  260. package/src/price-breakdown/PriceSummaryLine.tsx +12 -0
  261. package/src/price-breakdown/types.ts +12 -0
  262. package/src/rating/Rating.tsx +87 -3
  263. package/src/rating/index.ts +1 -0
  264. package/src/rating/types.ts +21 -0
  265. package/src/stepper/Stepper.tsx +18 -5
  266. package/src/stepper/types.ts +9 -0
  267. package/src/tabs/Tabs.tsx +3 -0
@@ -37,7 +37,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
37
37
 
38
38
  | contract | applies to | reads | delegated | n/a¹ | adaptation |
39
39
  | --- | --- | --- | --- | --- | --- |
40
- | Field membership | 46 | 21 | 0 | 20 | 5 |
40
+ | Field membership | 47 | 21 | 0 | 20 | 5 |
41
41
  | Control presentation | 16 | 8 | 2 | 6 | 0 |
42
42
  | Trigger composition | 10 | 8 | 0 | 2 | 0 |
43
43
  | Controlled / uncontrolled state | 49 | 40 | 1 | 1 | 7 |
@@ -122,12 +122,12 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
122
122
  | `agent-log` | `@oxy.so/bloom/agent-log` + barrel | universal | `agent-log.mdx` | yes | 1 | | | | |
123
123
  | `agent-progress` | `@oxy.so/bloom/agent-progress` + barrel | universal | `agent-progress.mdx` | yes | 1 | | | | reads |
124
124
  | `agent-thinking` | `@oxy.so/bloom/agent-thinking` + barrel | universal | `agent-thinking.mdx` | yes | 1 | | | | |
125
- | `ai-chat` | `@oxy.so/bloom/ai-chat` + barrel | web fork | `ai-chat.mdx` | yes | 7 | | | | reads |
125
+ | `ai-chat` | `@oxy.so/bloom/ai-chat` + barrel | web fork | `ai-chat.mdx` | yes | 9 | | | | reads |
126
126
  | `ai-profile-card` | `@oxy.so/bloom/ai-profile-card` + barrel | universal | `ai-profile-card.mdx` | yes | 1 | | | | reads |
127
127
  | `alert-dialog` | `@oxy.so/bloom/alert-dialog` + barrel | web fork | `alert-dialog.mdx` | yes | 1 | | | | |
128
128
  | `animated-check` | `@oxy.so/bloom/animated-check` + barrel | universal | `animated-check.mdx` | yes | 2 | | | | |
129
129
  | `announcement` | `@oxy.so/bloom/announcement` + barrel | universal | `announcement.mdx` | yes | 1 | | | | |
130
- | `app-shell` | `@oxy.so/bloom/app-shell` + barrel | web fork | `app-shell.mdx` | yes | 3 | | | | reads |
130
+ | `app-shell` | `@oxy.so/bloom/app-shell` + barrel | web fork | `app-shell.mdx` | yes | 5 | | | | reads |
131
131
  | `appearance` | `@oxy.so/bloom/appearance` + barrel | universal | `appearance.mdx` | yes | 4 | | | | |
132
132
  | `aspect-ratio` | `@oxy.so/bloom/aspect-ratio` + barrel | universal | `aspect-ratio.mdx` | yes | 1 | | | | |
133
133
  | `auth-card` | `@oxy.so/bloom/auth-card` + barrel | universal | `auth-card.mdx` | yes | 1 | | | | |
@@ -135,11 +135,11 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
135
135
  | `avatar-group` | `@oxy.so/bloom/avatar-group` + barrel | web fork | `avatar-group.mdx` | yes | 3 | | | | |
136
136
  | `badge` | `@oxy.so/bloom/badge` + barrel | universal | `badge.mdx` | yes | 2 | | | | |
137
137
  | `booking` | `@oxy.so/bloom/booking` + barrel | universal | `booking.mdx` | yes | 3 | | | | reads |
138
- | `bottom-bar` | `@oxy.so/bloom/bottom-bar` + barrel | web fork | `bottom-bar.mdx` | yes | 1 | | | | |
138
+ | `bottom-bar` | `@oxy.so/bloom/bottom-bar` + barrel | web fork | `bottom-bar.mdx` | yes | 2 | | | | |
139
139
  | `bottom-sheet` | `@oxy.so/bloom/bottom-sheet` + barrel | web fork | `bottom-sheet.mdx` | yes | 6 | | | | |
140
140
  | `breadcrumb` | `@oxy.so/bloom/breadcrumb` + barrel | universal | `breadcrumb.mdx` | yes | 1 | | | | |
141
- | `button` | `@oxy.so/bloom/button` + barrel | web fork | `button.mdx` | yes | 30 | | | n/a¹ | |
142
- | `button-group` | `@oxy.so/bloom/button-group` + barrel | universal | `button-group.mdx` | yes | 5 | | reads | | |
141
+ | `button` | `@oxy.so/bloom/button` + barrel | web fork | `button.mdx` | yes | 31 | | | n/a¹ | |
142
+ | `button-group` | `@oxy.so/bloom/button-group` + barrel | universal | `button-group.mdx` | yes | 7 | | reads | | |
143
143
  | `calendar` | `@oxy.so/bloom/calendar` + barrel | universal | `calendar.mdx` | yes | 1 | | | | reads |
144
144
  | `call-ui` | `@oxy.so/bloom/call-ui` + barrel | universal | `call-ui.mdx` | yes | 1 | | | | |
145
145
  | `card` | `@oxy.so/bloom/card` + barrel | universal | `card.mdx` | yes | 3 | | | | |
@@ -173,7 +173,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
173
173
  | `date-picker` | `@oxy.so/bloom/date-picker` + barrel | universal | `date-picker.mdx` | yes | 4 | reads | reads | | reads |
174
174
  | `delivery-slot` | `@oxy.so/bloom/delivery-slot` + barrel | universal | `delivery-slot.mdx` | yes | 2 | reads | | | |
175
175
  | `design-tokens` | `@oxy.so/bloom/design-tokens` + barrel | universal | `design-tokens.mdx` | yes | 3 | | | | |
176
- | `dialog` | `@oxy.so/bloom/dialog` + barrel | web fork | `dialog.mdx` | yes | 16 | | | | |
176
+ | `dialog` | `@oxy.so/bloom/dialog` + barrel | web fork | `dialog.mdx` | yes | 17 | | | | |
177
177
  | `directions` | `@oxy.so/bloom/directions` + barrel | universal | `directions.mdx` | yes | 2 | | | | |
178
178
  | `divider` | `@oxy.so/bloom/divider` + barrel | universal | `divider.mdx` | yes | 1 | | | | |
179
179
  | `dot-grid-meter` | `@oxy.so/bloom/dot-grid-meter` + barrel | universal | `dot-grid-meter.mdx` | yes | 2 | | | | |
@@ -192,10 +192,10 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
192
192
  | `glass` | internal | universal | `glass.mdx` | — | 1 | | reads | | |
193
193
  | `grid` | `@oxy.so/bloom/grid` + barrel | universal | `grid.mdx` | yes | 1 | | | | |
194
194
  | `home-search` | `@oxy.so/bloom/home-search` + barrel | universal | `home-search.mdx` | yes | 1 | n/a¹ | | | |
195
- | `hooks` | `@oxy.so/bloom/hooks` + barrel | universal | `hooks.mdx` | yes | 10 | | | | reads |
195
+ | `hooks` | `@oxy.so/bloom/hooks` + barrel | universal | `hooks.mdx` | yes | 11 | | | | reads |
196
196
  | `hover-card` | `@oxy.so/bloom/hover-card` + barrel | web fork | `hover-card.mdx` | yes | 2 | | | reads | reads |
197
197
  | `icon-circle` | `@oxy.so/bloom/icon-circle` + barrel | universal | `icon-circle.mdx` | yes | 1 | | | | |
198
- | `icons` | `@oxy.so/bloom/icons` + barrel | universal | `icons.mdx` | yes | 48 | | | | |
198
+ | `icons` | `@oxy.so/bloom/icons` + barrel | universal | `icons.mdx` | yes | 51 | | | | |
199
199
  | `image-aspect-ratio-cache` | `@oxy.so/bloom/image-aspect-ratio-cache` + barrel | universal | `image-aspect-ratio-cache.mdx` | yes | 1 | | | | |
200
200
  | `image-resolver` | `@oxy.so/bloom/image-resolver` + barrel | universal | `image-resolver.mdx` | yes | 7 | | | | |
201
201
  | `important-alerts-card` | `@oxy.so/bloom/important-alerts-card` + barrel | universal | `important-alerts-card.mdx` | yes | 1 | | | | |
@@ -213,7 +213,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
213
213
  | `listing-card` | `@oxy.so/bloom/listing-card` + barrel | universal | `listing-card.mdx` | yes | 4 | | | | |
214
214
  | `listing-details` | `@oxy.so/bloom/listing-details` + barrel | universal | `listing-details.mdx` | yes | 4 | | | | reads |
215
215
  | `listing-editor` | `@oxy.so/bloom/listing-editor` + barrel | universal | `listing-editor.mdx` | yes | 1 | **adaptation** | | | reads |
216
- | `loading` | `@oxy.so/bloom/loading` + barrel | web fork | `loading.mdx` | yes | 2 | | | | |
216
+ | `loading` | `@oxy.so/bloom/loading` + barrel | web fork | `loading.mdx` | yes | 3 | | | | |
217
217
  | `location-puck` | `@oxy.so/bloom/location-puck` + barrel | universal | `location-puck.mdx` | yes | 1 | | | | |
218
218
  | `lyrics` | `@oxy.so/bloom/lyrics` + barrel | universal | `lyrics.mdx` | yes | 2 | | | | |
219
219
  | `mail-compose` | `@oxy.so/bloom/mail-compose` + barrel | universal | `mail-compose.mdx` | yes | 2 | reads | | | reads |
@@ -257,7 +257,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
257
257
  | `place-list` | `@oxy.so/bloom/place-list` + barrel | universal | `place-list.mdx` | yes | 1 | | | | |
258
258
  | `place-reviews` | `@oxy.so/bloom/place-reviews` + barrel | universal | `place-reviews.mdx` | yes | 1 | | | | reads |
259
259
  | `popover` | `@oxy.so/bloom/popover` + barrel | web fork | `popover.mdx` | yes | 7 | | | reads | reads |
260
- | `portal` | `@oxy.so/bloom/portal` + barrel | web fork | `portal.mdx` | yes | 15 | | | | |
260
+ | `portal` | `@oxy.so/bloom/portal` + barrel | web fork | `portal.mdx` | yes | 18 | | | | |
261
261
  | `pressable-scale` | `@oxy.so/bloom/pressable-scale` + barrel | universal | `pressable-scale.mdx` | yes | 1 | | | | |
262
262
  | `price-breakdown` | `@oxy.so/bloom/price-breakdown` + barrel | universal | `price-breakdown.mdx` | yes | 3 | | | | reads |
263
263
  | `progressive-blur` | `@oxy.so/bloom/progressive-blur` + barrel | web fork | `progressive-blur.mdx` | yes | 1 | | | | |
@@ -280,7 +280,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
280
280
  | `settings-list` | `@oxy.so/bloom/settings-list` + barrel | universal | `settings-list.mdx` | yes | 5 | | | | |
281
281
  | `settings-modal` | `@oxy.so/bloom/settings-modal` + barrel | universal | `settings-modal.mdx` | yes | 3 | | | | reads |
282
282
  | `shipment-request` | `@oxy.so/bloom/shipment-request` + barrel | universal | `shipment-request.mdx` | yes | 1 | **adaptation** | | | |
283
- | `sidebar` | `@oxy.so/bloom/sidebar` + barrel | universal | `sidebar.mdx` | yes | 6 | n/a¹ | | | reads |
283
+ | `sidebar` | `@oxy.so/bloom/sidebar` + barrel | universal | `sidebar.mdx` | yes | 8 | n/a¹ | | | reads |
284
284
  | `skeleton` | `@oxy.so/bloom/skeleton` + barrel | universal | `skeleton.mdx` | yes | 1 | | | | |
285
285
  | `slider` | `@oxy.so/bloom/slider` + barrel | universal | `slider.mdx` | yes | 4 | reads | | | |
286
286
  | `social-button` | `@oxy.so/bloom/social-button` + barrel | universal | `social-button.mdx` | yes | 1 | | | | |
@@ -290,12 +290,12 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
290
290
  | `stay-filters` | `@oxy.so/bloom/stay-filters` + barrel | universal | `stay-filters.mdx` | yes | 4 | n/a¹ | | | |
291
291
  | `stay-search` | `@oxy.so/bloom/stay-search` + barrel | universal | `stay-search.mdx` | yes | 4 | | | | |
292
292
  | `stepper` | `@oxy.so/bloom/stepper` + barrel | universal | `stepper.mdx` | yes | 3 | reads | | | |
293
- | `styles` | `@oxy.so/bloom/styles` + barrel | universal | `styles.mdx` | yes | 65 | | | | |
293
+ | `styles` | `@oxy.so/bloom/styles` + barrel | universal | `styles.mdx` | yes | 66 | **UNCLASSIFIED** | | | |
294
294
  | `subtle-hover` | `@oxy.so/bloom/subtle-hover` + barrel | universal | `subtle-hover.mdx` | yes | 1 | | | | |
295
295
  | `surfaces` | `@oxy.so/bloom/surfaces` + barrel | web fork | `alert.mdx` | yes | 2 | | | | |
296
296
  | `swipe-row` | `@oxy.so/bloom/swipe-row` + barrel | universal | `swipe-row.mdx` | yes | 1 | | | | |
297
297
  | `switch` | `@oxy.so/bloom/switch` + barrel | universal | `switch.mdx` | yes | 6 | reads | | | |
298
- | `tab-bar` | `@oxy.so/bloom/tab-bar` | web fork | `tab-bar.mdx` | yes | 12 | | | reads | |
298
+ | `tab-bar` | `@oxy.so/bloom/tab-bar` | web fork | `tab-bar.mdx` | yes | 13 | | | reads | |
299
299
  | `table` | `@oxy.so/bloom/table` + barrel | universal | `table.mdx` | yes | 1 | | | | |
300
300
  | `tabs` | `@oxy.so/bloom/tabs` + barrel | universal | `tabs.mdx` | yes | 3 | | | | |
301
301
  | `tag-field` | `@oxy.so/bloom/tag-field` + barrel | universal | `tag-field.mdx` | yes | 2 | reads | reads | | |
@@ -304,7 +304,7 @@ The classification is an EQUALITY in `src/__tests__/adoption-matrix.test.ts`, no
304
304
  | `tenancy` | `@oxy.so/bloom/tenancy` + barrel | universal | `tenancy.mdx` | yes | 3 | | n/a¹ | | |
305
305
  | `text-field` | `@oxy.so/bloom/text-field` + barrel | universal | `text-field.mdx` | yes | 13 | reads | reads | | |
306
306
  | `textarea` | `@oxy.so/bloom/textarea` + barrel | universal | `textarea.mdx` | yes | 4 | reads | reads | | n/a¹ |
307
- | `theme` | `@oxy.so/bloom/theme` + barrel | web fork | `theme.mdx` | yes | 295 | | | n/a¹ | reads |
307
+ | `theme` | `@oxy.so/bloom/theme` + barrel | web fork | `theme.mdx` | yes | 303 | | | n/a¹ | reads |
308
308
  | `theme-toggle` | `@oxy.so/bloom/theme-toggle` + barrel | universal | `theme-toggle.mdx` | yes | 1 | n/a¹ | | | |
309
309
  | `toast` | `@oxy.so/bloom/toast` + barrel | universal | `toast.mdx` | yes | 17 | | | | |
310
310
  | `tooltip` | `@oxy.so/bloom/tooltip` + barrel | web fork | `tooltip.mdx` | yes | 1 | | | | |
@@ -628,8 +628,9 @@ panel at rest and during scroll.
628
628
  `gutter` and the aside gap. The social template uses `navigationGap={0}` to bring
629
629
  plain navigation up to the reading panel while retaining the panel frame insets.
630
630
 
631
- A document-scrolling, content-aligned shell with a plain sidebar and no top bar
632
- has no root padding. The sidebar spans the viewport; the reading/context group
631
+ A content-aligned shell with a plain sidebar and no top bar has no root padding,
632
+ whichever way it scrolls: native resolves every shell to container scroll, and
633
+ the same layout draws the same frame there as on the web. The sidebar spans the viewport; the reading/context group
633
634
  owns the vertical gutter, which still supplies the panel mask and header inset.
634
635
  The social template uses an 8px gutter, matching the compact framed layout.
635
636
 
@@ -35,6 +35,16 @@ An item is a **link** with `href`, a **button** with `onPress`, and a plain labe
35
35
 
36
36
  The list scrolls horizontally, with no scrollbar, when it outgrows its container. Bloom uses a full pill, like every other pressable, rather than a 6px corner.
37
37
 
38
+ ### Right-to-left and custom separators
39
+
40
+ The chevron points the READING direction. In a right-to-left layout (`<html dir="rtl">` on web, `I18nManager.isRTL` natively) the row mirrors, and the chevron flips with it (`scaleX(-1)`, read from `useIsRtl()`) so it still points from each crumb to the next. The landmark also carries `dir` on web, so react-native-web resolves logical keys against it.
41
+
42
+ `separator` replaces the chevron with any node — a `"/"`, a dot, an icon. It is hidden from assistive tech like the chevron, and rendered as given: a custom glyph that has a direction is the caller's to mirror.
43
+
44
+ ```tsx
45
+ <Breadcrumb separator={<Text variant="caption-1-medium">/</Text>}>…</Breadcrumb>
46
+ ```
47
+
38
48
  ### `href` and routers
39
49
 
40
50
  On web an `href` item is a real `<a href>`, so middle-click and "open in new tab" work. Pass `onPress` too and the browser's navigation is prevented so the router can navigate instead. On native, an `href` item without `onPress` opens the URL with `Linking`.
@@ -48,6 +58,7 @@ On web an `href` item is a real `<a href>`, so middle-click and "open in new tab
48
58
  | Prop | Type | Default | Description |
49
59
  |------|------|---------|-------------|
50
60
  | `Breadcrumb.accessibilityLabel?` | `string` | `'Breadcrumb'` | Names the landmark. |
61
+ | `Breadcrumb.separator?` | `ReactNode` | direction-aware chevron | Replaces the chevron between items; hidden from assistive tech. |
51
62
  | `BreadcrumbItem.href?` | `string` | — | Makes the item a link. |
52
63
  | `BreadcrumbItem.onPress?` | `() => void` | — | Makes the item a button (or routes an `href`). |
53
64
  | `BreadcrumbItem.current?` | `boolean` | `false` | The active page. |
@@ -79,7 +79,7 @@ Use `checked` with `onCheckedChange` for a controlled boolean toggle. `onPress`
79
79
  | padding-x | 12 | 10 |
80
80
  | icon | 20 | 18 |
81
81
 
82
- Text is `body-medium` (Inter 14/20 500) through Bloom's typography `Text` — a bare React Native `Text` falls back to the system font. Pass icon components to `leadingIcon` / `trailingIcon`; `iconOnly` makes a square item that needs `accessibilityLabel`.
82
+ Text is `body-medium` (Inter 14/20 500) through Bloom's typography `Text` — a bare React Native `Text` falls back to the system font. Pass icon components to `leadingIcon` / `trailingIcon`; `iconOnly` makes a square item that needs `accessibilityLabel`. An app whose own icons take `size`/`color` rather than `width`/`height`/`fill` uses `renderLeadingIcon={({ size, color }) => …}` instead — see [Icons](/docs/icons).
83
83
 
84
84
  ## Props
85
85
 
@@ -94,6 +94,7 @@ Text is `body-medium` (Inter 14/20 500) through Bloom's typography `Text` — a
94
94
  | `ButtonGroupItem.disabled?` | `boolean` | `false` | Disabled paint, blocks presses. |
95
95
  | `ButtonGroupItem.iconOnly?` | `boolean` | `false` | Square icon-only item. |
96
96
  | `ButtonGroupItem.leadingIcon?` / `trailingIcon?` | `BloomIconComponent` | — | Icon components. |
97
+ | `ButtonGroupItem.renderLeadingIcon?` / `renderTrailingIcon?` | `BloomIconRenderer` | — | Draw the glyph yourself, handed `{ size, color }` for the current state — for an app's own icon set. Wins over the icon component. [Icons](/docs/icons). |
97
98
  | `ButtonGroupItem.size?` | `'md' \| 'sm'` | group size | Per-item override. |
98
99
  | `ButtonGroupItem.material?` | `'solid' \| 'glass'` | group material | Per-item override. Rarely needed — the group owns it. |
99
100
  | `ButtonGroupItem.hitSlop?` | `number \| {top,bottom,left,right}` | — | Extra touch area. NOT defaulted: items in a group are adjacent, so slop on one overlaps its neighbour. Use it for an item that stands alone in its own island. |
package/docs/button.mdx CHANGED
@@ -32,6 +32,30 @@ The pressable is the parent's layout child: `className` and `style` are applied
32
32
 
33
33
  See [Component contract](./appearance.mdx) for inheritance and [Migration](./coherent-system-migration.mdx) for the clean API cut.
34
34
 
35
+ ## An app's own icon set
36
+
37
+ `leadingIcon` and `trailingIcon` take a `BloomIconComponent` — `width`, `height`,
38
+ `fill` — and an app icon set usually spells that `size` and `color`. The two have
39
+ no property in common, so the icon does not typecheck against the slot, and
40
+ casting only moves the failure: Bloom tints by passing `fill`, so a glyph that
41
+ paints from `color` renders at its default colour with nothing thrown.
42
+
43
+ `renderLeadingIcon` / `renderTrailingIcon` hand the drawing back, with the box
44
+ and the foreground for the current state. They win over the icon component, and
45
+ supply the glyph for `iconOnly`.
46
+
47
+ ```tsx
48
+ <Button
49
+ iconOnly
50
+ accessibilityLabel="Search"
51
+ renderLeadingIcon={({ size, color }) => <AppSearchGlyph size={size} color={color} />}
52
+ />
53
+ ```
54
+
55
+ On web `color` is `currentColor`, so the glyph follows the stylesheet's state
56
+ colours without a re-render; native gets the resolved value. Full rationale, and
57
+ why this is a separate prop rather than a wider `leadingIcon`: [Icons](/docs/icons).
58
+
35
59
  ## Compatibility
36
60
 
37
61
  The shared `size`, `tone` and `appearance` vocabulary coexists with the previously published family props. Explicit shared props take precedence over legacy spellings; existing size and state callbacks remain supported. New code should prefer the shared vocabulary.
@@ -43,10 +43,12 @@ Inline in a desktop sidebar it is dropped in a `Card`; on a phone it is what a `
43
43
 
44
44
  Which is why the vendor is a header and not a field on every line. Switching vendor is a different action — it empties the basket — and this component does not offer it.
45
45
 
46
- ## The stepper does not remove
46
+ ## The stepper does not remove — unless you ask
47
47
 
48
48
  `CartLine`'s stepper has a floor of **1**, and removing is its own control with its own accessible name. A stepper that deletes the line when you press `−` once too often is a destructive action hiding behind an arithmetic one, and it has no label saying so.
49
49
 
50
+ `removeInStepper` (on `CartLine`, and on `CartPanel` for every line) opts into the storefront pattern instead: at quantity 1 the `−` becomes a trash button NAMED as removal — `removeLabel`, default `"Remove <name>"` — through `Stepper`'s `onRemove`, and the separate remove control is not drawn. It needs both `onQuantityChange` and `onRemove`. A sold-out line keeps the separate control, because its stepper is disabled and could not remove anything.
51
+
50
52
  The line is never pressable, which is what lets its controls live inside it: a pressable `Item` is a real `<button>` on web, and a control inside one is invalid HTML whose click also fires the row. Editing a line's options is `MenuItemOptions` in a sheet, opened from the dish rather than from a row that is mostly controls.
51
53
 
52
54
  ## The promo field has two states, not one
@@ -71,6 +73,6 @@ Once the order is placed it belongs to `order-status`: `OrderStatusTimeline` for
71
73
 
72
74
  ## Traps
73
75
 
74
- - **Every amount is a string.** `price` on a line is the line's own total, already multiplied by `quantity` **by the app**. Nothing here multiplies, converts or rounds.
76
+ - **Every amount is a string.** `price` on a line is the line's own total, already multiplied by `quantity` **by the app**. Nothing here multiplies, converts or rounds. A second currency is `secondaryPrice` (`"≈ 12,00 €"`), drawn de-emphasised under the price and added to the line's accessible name after it — `listing-card`'s `ListingPriceLine.secondary`, spelled after this family's `price`. The totals take `secondaryAmount` on their `PriceLine`s.
75
77
  - **The empty basket hides everything after the lines.** No tip picker, no promo field, no totals and no checkout button — each of them would be a control acting on nothing.
76
78
  - **`CartLine` takes the line's fields, not the entry.** `CartLineEntry` carries the `id` the panel keys and reports by; the standalone component takes the rest, so a caller cannot pass an id that reaches nothing.
@@ -88,3 +88,7 @@ screen and a button reading "Place order" are two, and the gap between them is w
88
88
  reader confirms a figure they last saw before a tip picker changed it. The separator is a
89
89
  middle dot: "Place order - €49.62" reads as a subtraction at a glance in a row that is
90
90
  otherwise full of money.
91
+
92
+ The button carries ONE amount — the one the charge is made in. A second currency is
93
+ `secondaryAmount` (`"≈ 49,62 €"`), pre-formatted like `amount` and drawn de-emphasised,
94
+ centred 8 under the button, above the terms.
package/docs/chip.mdx CHANGED
@@ -66,16 +66,29 @@ The hues sit BESIDE the accent recipe, not inside it: `resolveAccentColors` is u
66
66
 
67
67
  ### Role
68
68
 
69
- A pressable chip's ROLE decides which state attribute it carries, and the three are not interchangeable:
69
+ A pressable chip's ROLE decides which state attribute it carries, and the four are not interchangeable:
70
70
 
71
71
  | `role` | web | native |
72
72
  |---|---|---|
73
73
  | `button` (default) | `aria-pressed` | `accessibilityState.selected` |
74
+ | `checkbox` | `aria-checked` | `accessibilityState.checked` |
74
75
  | `radio` | `aria-checked` | `accessibilityState.checked` |
75
76
  | `tab` | `aria-selected` | `accessibilityState.selected` |
76
77
 
77
78
  `aria-pressed` is invalid on a radio and on a tab, which is what this component used to emit for every one of them. Put a `radio` inside a `role="radiogroup"` and a `tab` inside a `role="tablist"` — `ChipRow` takes that role for you.
78
79
 
80
+ A multi-select filter row (brands, sizes, amenities — any number on at once) is a `group` of `checkbox` chips: a screen reader then says "checked"/"not checked" rather than "pressed", which is what a filter is. `onCheckedChange` receives the next state.
81
+
82
+ ```tsx
83
+ <ChipRow accessibilityLabel="Brand">
84
+ {brands.map((brand) => (
85
+ <Chip key={brand} role="checkbox" checked={picked.has(brand)} onCheckedChange={(on) => toggle(brand, on)}>
86
+ {brand}
87
+ </Chip>
88
+ ))}
89
+ </ChipRow>
90
+ ```
91
+
79
92
  On web, `tabIndex` and `onKeyDown` are passed through for a roving-tabindex row (one tab stop, arrows move focus). Both are inert on native. A chip also forwards a ref to its pressable, so a row can focus one.
80
93
 
81
94
  ### `inverted`
package/docs/dialog.mdx CHANGED
@@ -6,7 +6,7 @@ order: 3
6
6
 
7
7
  # Dialog
8
8
 
9
- A single `<Dialog>` component for every overlay surface — centered modal, side-sheet (left/right drawer), or bottom-sheet — controlled by the `placement` prop. Same component, same props on every platform.
9
+ A single `<Dialog>` component for every overlay surface — centered modal, side-sheet (left/right or logical start/end drawer), or bottom-sheet — controlled by the `placement` prop. Same component, same props on every platform.
10
10
 
11
11
  <Callout variant="warning" title="Required providers (native)">
12
12
  Your app root **must** be wrapped with `GestureHandlerRootView` from `react-native-gesture-handler` for the bottom-sheet pan gestures to work. See [Getting started](/docs/bloom/main/getting-started).
@@ -105,7 +105,7 @@ Drop the declarative props entirely — `children` owns every pixel.
105
105
  | `children?` | `React.ReactNode` | — | Custom content rendered after the description. |
106
106
  | `onClose?` | `() => void` | — | Fires after the dialog finishes closing. In controlled mode, the host flips `open` to `false`. |
107
107
  | `contentPadding?` | `number` | `20` | Inner padding of the dialog body (px). Set `0` for custom children that own their insets. |
108
- | `width?` | `number` | `460` | Side-sheet width (px) on `left`/`right` placements. |
108
+ | `width?` | `number` | `460` | Side-sheet width (px) on `left`/`right`/`start`/`end` placements. |
109
109
  | `maxWidth?` | `number` | `480` | Centered-card max width (px). |
110
110
  | `maxHeightRatio?` | `number` | `0.9` | Bottom-sheet max height as a fraction of the viewport height. |
111
111
  | `inset?` | `{ top?; bottom?; left?; right? }` | — | Side-sheet inset (px) from the overlay container edges. |
@@ -123,7 +123,7 @@ Drop the declarative props entirely — `children` owns every pixel.
123
123
  `placement` accepts a single value or a **responsive map** resolved by `useWindowDimensions()`:
124
124
 
125
125
  ```ts
126
- type DialogPlacement = 'center' | 'left' | 'right' | 'bottom';
126
+ type DialogPlacement = 'center' | 'left' | 'right' | 'start' | 'end' | 'bottom';
127
127
 
128
128
  type ResponsiveDialogPlacement =
129
129
  | DialogPlacement
@@ -134,7 +134,8 @@ Breakpoints (px): `sm` 640 / `md` 768 / `lg` 1024 / `xl` 1280. The largest break
134
134
 
135
135
  Per-placement behavior:
136
136
  - `center` — DOM-portal modal (web) / detached floating card (native).
137
- - `left` / `right` — animated side-sheet anchored to the viewport edge.
137
+ - `left` / `right` — animated side-sheet anchored to that PHYSICAL viewport edge.
138
+ - `start` / `end` — the same side-sheet on the LOGICAL edge: `start` is the left in a left-to-right layout and the right in a right-to-left one (`end` the reverse), read from `useIsRtl()`, and the panel slides in from that edge. The matching `inset` side applies (`inset.right` for `start` in RTL). On native the panel is positioned with `insetInlineStart`/`insetInlineEnd`, which Yoga resolves against `I18nManager` — a physical `left`/`right` would be swapped by React Native's default `swapLeftAndRightInRTL`. On web the drawer is portaled outside any `dir` context, so it takes the physical edge `useIsRtl()` names. An app that ships Arabic or Hebrew wants `start`/`end`: `{ base: 'bottom', md: 'start' }` is the mirrored store drawer.
138
139
  - `bottom` — reuses the cross-platform `BottomSheet` on BOTH web and native (drag-to-dismiss + internal scroll work everywhere). Custom `children` on bottom placement are rendered in a NON-scrollable body — children own scrolling.
139
140
 
140
141
  ### `DialogAction`
package/docs/icons.mdx CHANGED
@@ -131,6 +131,59 @@ the chat parts label their glyphs for tests.
131
131
  Those are deliberate and stay. Reaching for `Props` when you only set
132
132
  width/height/fill is not: it refuses a caller's own glyph for no benefit.
133
133
 
134
+ ### Your OWN icon set: `renderLeadingIcon`
135
+
136
+ `BloomIconComponent` is the widest *component* a slot can take, but it is still
137
+ a shape: `width`, `height`, `fill`. An app icon set usually spells the same idea
138
+ `size` and `color`, and those two prop sets have **nothing in common** — so the
139
+ icon does not typecheck against the slot, and casting it does not help either.
140
+ Bloom tints by passing `fill`; an icon that paints from `color` renders fine and
141
+ never takes the tint, with nothing thrown. `frosted-icon-button/shared.ts` and
142
+ `tab-bar/types.ts` both record that hazard.
143
+
144
+ Passing `color` alongside `fill` is not the answer, for the reason
145
+ `applyIconColor` gives: the prop is not Bloom's to claim, because components use
146
+ it for semantic variants (`color="danger"`).
147
+
148
+ So the slot families expose a second prop that hands the drawing back to you,
149
+ with the box and the foreground for the CURRENT state:
150
+
151
+ ```tsx
152
+ import { RiSearchLine } from '@oxy.so/bloom/icons/RiSearchLine';
153
+
154
+ // Bloom's own glyph: the component, sized and tinted for you.
155
+ <ButtonGroupItem iconOnly leadingIcon={RiSearchLine} accessibilityLabel="Search" />
156
+
157
+ // Your app's glyph, whose props are `size` and `color`.
158
+ <ButtonGroupItem
159
+ iconOnly
160
+ renderLeadingIcon={({ size, color }) => <AppSearchGlyph size={size} color={color} />}
161
+ accessibilityLabel="Search"
162
+ />
163
+ ```
164
+
165
+ ```ts
166
+ type BloomIconPaint = { size: number; color: string };
167
+ type BloomIconRenderer = (paint: BloomIconPaint) => ReactNode;
168
+ ```
169
+
170
+ Where a family offers both, the renderer WINS, which is the rule `GlyphButton`
171
+ already uses for a caller-painted `children` over `icon`.
172
+
173
+ **On web `color` is `currentColor`.** Bloom paints web glyphs that way so they
174
+ follow the state colours the stylesheet sets without a re-render; native has no
175
+ cascade and gets the resolved value. Either way, passing it straight to your
176
+ icon's `color` is correct.
177
+
178
+ **Why a separate prop and not a wider `leadingIcon`.** The adapter a caller
179
+ writes today — `({ width, fill }) => <Glyph size={width} color={fill} />` — is a
180
+ function, and so is a paint callback. One prop taking both could not tell them
181
+ apart, and would silently re-interpret every existing adapter. Both forms are
182
+ pinned in `src/__tests__/icon-render-slot.test.tsx`.
183
+
184
+ Today this is on `Button` and `ButtonGroupItem`. The other icon slots still take
185
+ the component only.
186
+
134
187
  ### The per-family names still work
135
188
 
136
189
  Twenty-five families had declared this same type under their own name
package/docs/loading.mdx CHANGED
@@ -52,6 +52,16 @@ For native-tailwind users, `className` overrides `color`:
52
52
  <Loading variant="spinner" className="text-primary" />
53
53
  ```
54
54
 
55
+ ## Accessibility
56
+
57
+ A spinner draws no words, so nothing but a name can tell a screen reader what is loading. Pass `accessibilityLabel` and the indicator becomes an indeterminate `progressbar`: `role="progressbar"`, `aria-label` and `aria-busy="true"` on web (flat `aria-*`, because react-native-web drops `accessibilityState`), the same role, label and busy state natively, and deliberately **no** `aria-valuenow` — that omission is how ARIA says "indeterminate". The `top` bar carries it only while `showLoading`.
58
+
59
+ ```tsx
60
+ <Loading accessibilityLabel="Loading results" />
61
+ ```
62
+
63
+ It is opt-in, so an unlabelled `Loading` renders exactly as before, with no role. That is right when the spinner sits INSIDE something already announcing the wait — an upload tile's own named progressbar — where a second one would say it twice.
64
+
55
65
  ## Props
56
66
 
57
67
  ### Shared
@@ -64,6 +74,7 @@ For native-tailwind users, `className` overrides `color`:
64
74
  | `className?` | `string` | NativeWind class. Overrides `color`. |
65
75
  | `style?` | `ViewStyle` | Container style. |
66
76
  | `showLoading?` | `boolean` | For animated variants — pause when false. |
77
+ | `accessibilityLabel?` | `string` | Names the indicator and makes it an indeterminate `progressbar`. See [Accessibility](#accessibility). |
67
78
  | `testID?` | `string` | |
68
79
 
69
80
  ### `spinner`
@@ -286,3 +286,10 @@ The provider accepts the existing `scrollY` shared value or inherits `Screen`'s.
286
286
  Native lists retain sticky ownership and consume `useHeaderDockInset()` as their
287
287
  supported sticky-header offset; see [layout](./layout.mdx). Storybook's
288
288
  **Profile Docking** demonstrates the document-scroll composition.
289
+
290
+ For a native list behind the header, use `placement="overlay"` and let the list
291
+ consume `useHeaderDockInset()` for sticky clearance. This absolute header has
292
+ both a local stacking index and native elevation: Android scroll surfaces can
293
+ otherwise paint over its controls. `placement="overlap"` is the document-scroll
294
+ composition for web. Keep the header and list in the same unclipped parent;
295
+ no descendant elevation can escape an ancestor's clipping bounds.
@@ -37,6 +37,23 @@ two — and "quietly" is the problem: a mis-formatted price still renders.
37
37
  In particular, **`tone="discount"` colours a credit; it does not create one.** Pass
38
38
  `"−€5.00"`, not `"5.00"`.
39
39
 
40
+ ### A second currency
41
+
42
+ `secondaryAmount` — on a `PriceLine` and on the `total` — is a second, pre-formatted
43
+ rendering of the same amount, drawn under it in `body-2-regular` at the secondary rung,
44
+ tabular and right-aligned: the buyer's currency beside the shop's.
45
+
46
+ ```tsx
47
+ <PriceSummary
48
+ lines={[{ label: 'Subtotal', amount: '$13.20', secondaryAmount: '≈ 12,00 €' }]}
49
+ total={{ label: 'Total', amount: '$15.20', secondaryAmount: '≈ 13,82 €' }}
50
+ />
51
+ ```
52
+
53
+ It is the same contract as `amount`: drawn as given, never converted. The name follows
54
+ the family's own `amount`; `listing-card`'s `ListingPriceLine.secondary` and
55
+ `cart-panel`'s `secondaryPrice` are the same idea on those families' `price`.
56
+
40
57
  ## The three tones
41
58
 
42
59
  | tone | what it is for |
package/docs/rating.mdx CHANGED
@@ -32,6 +32,11 @@ const [stars, setStars] = useState<number | null>(null);
32
32
  | `reviewsLabel` | the word after the count, default `"reviews"` — translate it |
33
33
  | `newLabel` | drawn instead of the value when there is no rating yet, default `"New"` |
34
34
  | `size` | `'small'` (14px star, body-2 text) or `'medium'` (default, 16px star, body text) |
35
+ | `variant` | `'compact'` (default, one star) or `'stars'` (five stars, filled fractionally, before the value) |
36
+ | `color` | paints the star(s), the value and the count — e.g. white over a brand-coloured hero |
37
+ | `starColor` | the filled star(s) only (a gold star beside neutral text); default `color` |
38
+ | `countColor` | the count only; default `color` when given, else text-secondary |
39
+ | `emptyStarColor` | `stars` only: the unfilled part of each star; default the border colour |
35
40
  | `accessibilityLabel` | replaces the composed name — pass a translated sentence |
36
41
  | `style`, `testID` | |
37
42
 
@@ -41,6 +46,23 @@ named "Rated 4.92 out of 5, 128 reviews", so a screen reader does not read the
41
46
  star, the number and the brackets as separate items. That sentence is English;
42
47
  apps in other languages pass `accessibilityLabel`.
43
48
 
49
+ ### Five stars, and colour
50
+
51
+ `variant="stars"` draws a row of five stars 2px apart instead of the single
52
+ star. Each is the unfilled star (`emptyStarColor`) with the filled star clipped
53
+ over it to its share of the value — 4.3 fills four stars and 30% of the fifth. A
54
+ string `value` is parsed for the fill and drawn as given. The clip is anchored
55
+ with a logical inset, so in a right-to-left layout the row fills from the right
56
+ (the root carries `dir` on web for react-native-web to resolve it). The row
57
+ stays ONE named image, like the compact rating.
58
+
59
+ ```tsx
60
+ <Rating variant="stars" value={4.3} count={128} color="#fff" emptyStarColor="rgba(255,255,255,0.35)" />
61
+ ```
62
+
63
+ Over a surface the theme's text pair cannot sit on — a brand-coloured hero — pass
64
+ `color`; the default text-primary/text-secondary are measured against the PAGE.
65
+
44
66
  ## `RatingBar`
45
67
 
46
68
  | prop | decides |
package/docs/stepper.mdx CHANGED
@@ -36,6 +36,7 @@ import { Stepper, StepperRow } from '@oxy.so/bloom/stepper';
36
36
  | `formatValue` | the drawn and announced text, e.g. `(n) => (n === 8 ? '8+' : String(n))` |
37
37
  | `accessibilityLabel` | **required** — what is being counted |
38
38
  | `decrementLabel` / `incrementLabel` | the buttons' names, default `"Decrease"` / `"Increase"` — translate them |
39
+ | `onRemove` / `removeLabel` | opt-in: at `min` the `−` becomes a trash button named `removeLabel` (default `"Remove"`) that calls `onRemove`; without it the button disables at `min` |
39
40
  | `style`, `testID` | the row; `testID` also derives `-decrement`, `-value`, `-increment` |
40
41
 
41
42
  `StepperRow` takes every `Stepper` prop plus `title`, `description`, `divider`
@@ -53,6 +54,30 @@ import { Stepper, StepperRow } from '@oxy.so/bloom/stepper';
53
54
  - **Row** title `headline-medium` text-primary over a `body-regular`
54
55
  text-secondary description, the stepper on the right, 16 above and below.
55
56
 
57
+ ## Remove at the floor
58
+
59
+ By default the stepper floors at `min` and the `−` disables there. A basket line
60
+ that should go from 1 to gone opts in with `onRemove`:
61
+
62
+ ```tsx
63
+ <Stepper
64
+ value={quantity}
65
+ min={1}
66
+ onValueChange={setQuantity}
67
+ onRemove={removeLine}
68
+ removeLabel={`Remove ${name}`}
69
+ accessibilityLabel={name}
70
+ />
71
+ ```
72
+
73
+ At `min` the `−` draws `RiDeleteBinLine`, is named `removeLabel`, stays enabled
74
+ and calls `onRemove` rather than `onValueChange`. Above `min` it is the ordinary
75
+ decrement. Only the BUTTON removes: ArrowDown, Home and the native `decrement`
76
+ action on the value still stop at `min`, because a key or a swipe that deletes is
77
+ a destructive action behind an arithmetic one. So that a keyboard user can
78
+ reach it, the remove button joins the tab order (the decrement never does). A
79
+ `disabled` stepper offers no removal.
80
+
56
81
  ## Accessibility
57
82
 
58
83
  The stepper is a `group` named by `accessibilityLabel` — or, inside a
package/docs/tabs.mdx CHANGED
@@ -142,3 +142,9 @@ hover row and the `filled` thumb are steps off that surface.
142
142
  The rail used to be `neutral-800` in dark — the exact fill `QueuePanel` (and
143
143
  every other menu-surface family) paints its panel with, **ΔE 0**. A tab strip
144
144
  inside one had no rail. On the page the rail lands within 0.04 of its old colour.
145
+
146
+ The scrolling tab viewport keeps its intrinsic height (`flexGrow: 0`,
147
+ `flexShrink: 0`). This matters in native columns above virtualized lists:
148
+ React Native's default ScrollView growth otherwise takes space from the feed,
149
+ even when the caller gives the tab strip a fixed height. Caller `style` still
150
+ styles the strip content, including its height, padding, and separator.
@@ -578,7 +578,11 @@ function createAppShellEngine(ContentPanel, BloomColorScope) {
578
578
  // Plain navigation belongs to the viewport; only the reading surfaces are inset.
579
579
  const documentPanelInset = feedRevealed ? 12 : compactPanel ? 0 : gutter;
580
580
  const externalTopHeight = showTopBar ? topBarHeight : 0;
581
- const plainDocumentFrame = doc && contentAligned && flowSidebar?.surface === 'plain' && !topBarNode;
581
+ // A property of the NAVIGATION, not of who scrolls: native resolves every
582
+ // shell to container scroll, and gating this on `document` left native
583
+ // phones with an 8px frame around the reading panel that the same layout on
584
+ // the web does not draw.
585
+ const plainFrame = contentAligned && flowSidebar?.surface === 'plain' && !topBarNode;
582
586
  const readingGap = Math.max(0, asideGap ?? columnGap);
583
587
  const readingGroupWidth = contentWidth + (asideBeside ? asideWidth + readingGap : 0);
584
588
  const centredBody = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
@@ -598,7 +602,7 @@ function createAppShellEngine(ContentPanel, BloomColorScope) {
598
602
  flexBasis: compactPanel ? 'auto' : readingGroupWidth,
599
603
  maxWidth: compactPanel ? undefined : readingGroupWidth
600
604
  } : {}),
601
- ...(plainDocumentFrame ? {
605
+ ...(plainFrame ? {
602
606
  paddingTop: compactPanel ? 0 : gutter,
603
607
  paddingBottom: compactPanel ? 0 : gutter
604
608
  } : {})
@@ -840,7 +844,7 @@ function createAppShellEngine(ContentPanel, BloomColorScope) {
840
844
  const dockedNav = navInFlow && flowSidebar?.surface === 'docked';
841
845
  const navRegion = navInFlow && flowSidebar ? doc ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
842
846
  testID: testID ? `${testID}-navigation` : undefined,
843
- style: (0, _layout.stickyRail)(dockedNav || plainDocumentFrame ? 0 : gutter),
847
+ style: (0, _layout.stickyRail)(dockedNav || plainFrame ? 0 : gutter),
844
848
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Sidebar, {
845
849
  ...flowSidebar
846
850
  })
@@ -908,9 +912,9 @@ function createAppShellEngine(ContentPanel, BloomColorScope) {
908
912
  paddingTop: 0,
909
913
  paddingBottom: 0,
910
914
  paddingInlineStart: 0,
911
- paddingInlineEnd: canvas || plainDocumentFrame ? 0 : gutter
915
+ paddingInlineEnd: canvas || plainFrame ? 0 : gutter
912
916
  } : {
913
- padding: canvas || plainDocumentFrame ? 0 : gutter
917
+ padding: canvas || plainFrame ? 0 : gutter
914
918
  }),
915
919
  backgroundColor: background
916
920
  };