pixelize-design-library 2.4.2-beta.67 → 2.4.2-beta.68

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 (299) hide show
  1. package/CHANGELOG.md +61 -4
  2. package/COMPONENT-GOTCHAS.md +98 -59
  3. package/DESIGN-GUIDE.md +18 -6
  4. package/README.md +14 -11
  5. package/dist/Components/Accordion/AccordionProps.d.ts +10 -0
  6. package/dist/Components/AddressCard/AddressCardProps.d.ts +15 -0
  7. package/dist/Components/Apexcharts/ApexAreaChart/ApexAreaChartProps.d.ts +11 -0
  8. package/dist/Components/Apexcharts/ApexBarChart/ApexBarChartProps.d.ts +17 -1
  9. package/dist/Components/Apexcharts/ApexLineChart/ApexLineChartProps.d.ts +10 -0
  10. package/dist/Components/Apexcharts/ApexPieChart/ApexPieChartProps.d.ts +14 -0
  11. package/dist/Components/Apexcharts/ApexPolarCharts/ApexPolarChartsProps.d.ts +9 -0
  12. package/dist/Components/Apexcharts/ApexRadialChart/ApexRadialChartProps.d.ts +10 -0
  13. package/dist/Components/AppSwitcher/AppSwitcher.d.ts +1 -0
  14. package/dist/Components/AppSwitcher/AppSwitcher.js +1 -0
  15. package/dist/Components/AppSwitcher/AppSwitcherProps.d.ts +23 -0
  16. package/dist/Components/AppSwitcher/pixelizeSuite.d.ts +1 -0
  17. package/dist/Components/AppearanceSettings/AppearanceSettings.d.ts +1 -0
  18. package/dist/Components/AppearanceSettings/AppearanceSettings.js +1 -0
  19. package/dist/Components/AppearanceSettings/AppearanceSettingsProps.d.ts +11 -0
  20. package/dist/Components/AudioRecorder/AudioRecorder.d.ts +1 -0
  21. package/dist/Components/AudioRecorder/AudioRecorder.js +1 -0
  22. package/dist/Components/AudioRecorder/AudioRecorderProps.d.ts +6 -0
  23. package/dist/Components/Avatar/AvatarGroup.d.ts +1 -0
  24. package/dist/Components/Avatar/AvatarGroup.js +1 -0
  25. package/dist/Components/Avatar/AvatarGroupProps.d.ts +2 -0
  26. package/dist/Components/Avatar/AvatarProps.d.ts +2 -2
  27. package/dist/Components/Avatar/avatarColorway.d.ts +1 -0
  28. package/dist/Components/BagBar/BagBarProps.d.ts +8 -0
  29. package/dist/Components/BulkSelectionBar/BulkSelectionBar.d.ts +1 -0
  30. package/dist/Components/BulkSelectionBar/BulkSelectionBar.js +1 -0
  31. package/dist/Components/BulkSelectionBar/BulkSelectionBarProps.d.ts +6 -0
  32. package/dist/Components/Button/Button.js +1 -0
  33. package/dist/Components/Button/ButtonProps.d.ts +3 -0
  34. package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.d.ts +1 -0
  35. package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -0
  36. package/dist/Components/ButtonGroupIcon/ButtonGroupIconProps.d.ts +19 -0
  37. package/dist/Components/CalendarGrid/CalendarGrid.d.ts +1 -0
  38. package/dist/Components/CalendarGrid/CalendarGrid.js +1 -0
  39. package/dist/Components/CalendarGrid/CalendarGridProps.d.ts +11 -0
  40. package/dist/Components/CalendarGrid/calendarMath.d.ts +13 -0
  41. package/dist/Components/Card/CardProps.d.ts +4 -0
  42. package/dist/Components/Card/PaymentCard/PaymentCard.d.ts +1 -0
  43. package/dist/Components/Card/PaymentCard/PaymentCard.js +1 -0
  44. package/dist/Components/Card/PaymentCard/PaymentCardProps.d.ts +19 -0
  45. package/dist/Components/CartItem/CartItemProps.d.ts +10 -0
  46. package/dist/Components/Checkbox/CheckboxProps.d.ts +1 -0
  47. package/dist/Components/ChoiceCard/ChoiceCard.d.ts +1 -0
  48. package/dist/Components/ChoiceCard/ChoiceCard.js +1 -0
  49. package/dist/Components/ChoiceCard/ChoiceCardGroup.d.ts +1 -0
  50. package/dist/Components/ChoiceCard/ChoiceCardGroup.js +1 -0
  51. package/dist/Components/ChoiceCard/ChoiceCardProps.d.ts +3 -0
  52. package/dist/Components/ConfirmDialog/ConfirmDialog.d.ts +1 -0
  53. package/dist/Components/ConfirmDialog/ConfirmDialog.js +1 -0
  54. package/dist/Components/ConfirmDialog/ConfirmDialogProps.d.ts +5 -0
  55. package/dist/Components/ContactForm/ContactFormProps.d.ts +13 -0
  56. package/dist/Components/CouponField/CouponFieldProps.d.ts +16 -0
  57. package/dist/Components/CustomModulesTable/CustomModulesTable.d.ts +1 -0
  58. package/dist/Components/CustomModulesTable/CustomModulesTable.js +1 -0
  59. package/dist/Components/CustomModulesTable/CustomModulesTableProps.d.ts +17 -0
  60. package/dist/Components/CustomModulesTable/DeleteModuleModal.d.ts +1 -0
  61. package/dist/Components/CustomModulesTable/DeleteModuleModal.js +1 -0
  62. package/dist/Components/CustomModulesTable/EditModuleModal.d.ts +1 -0
  63. package/dist/Components/CustomModulesTable/EditModuleModal.js +1 -0
  64. package/dist/Components/DatePicker/DatePickerProps.d.ts +7 -1
  65. package/dist/Components/DetailSections/DetailSectionsProps.d.ts +22 -0
  66. package/dist/Components/Drawer/DrawerProps.d.ts +1 -1
  67. package/dist/Components/Dropdown/DropdownProps.d.ts +1 -0
  68. package/dist/Components/Editor/EditorProps.d.ts +33 -0
  69. package/dist/Components/Editor/editorTokens.d.ts +3 -0
  70. package/dist/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtpProps.d.ts +8 -0
  71. package/dist/Components/FilePreview/FilePreviewProps.d.ts +4 -0
  72. package/dist/Components/FileUploader/FileUploaderProps.d.ts +1 -0
  73. package/dist/Components/FilterBar/FilterBarProps.d.ts +2 -0
  74. package/dist/Components/FormDrawer/FormDrawer.d.ts +1 -0
  75. package/dist/Components/FormDrawer/FormDrawer.js +1 -0
  76. package/dist/Components/FormDrawer/FormDrawerProps.d.ts +3 -0
  77. package/dist/Components/FormField/FormField.d.ts +1 -0
  78. package/dist/Components/FormField/FormField.js +1 -0
  79. package/dist/Components/FormField/FormFieldProps.d.ts +4 -0
  80. package/dist/Components/Header/Header.d.ts +1 -0
  81. package/dist/Components/Header/Header.js +1 -0
  82. package/dist/Components/Header/HeaderActions.d.ts +16 -0
  83. package/dist/Components/Header/HeaderActions.js +1 -0
  84. package/dist/Components/Header/HeaderProps.d.ts +22 -0
  85. package/dist/Components/Header/components/desktopMenu.d.ts +1 -0
  86. package/dist/Components/Header/components/desktopMenu.js +1 -0
  87. package/dist/Components/Header/components/mobileMenu.d.ts +1 -0
  88. package/dist/Components/Header/components/mobileMenu.js +1 -0
  89. package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.d.ts +1 -1
  90. package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -1
  91. package/dist/Components/KanbanBoard/KanbanBoardProps.d.ts +11 -0
  92. package/dist/Components/Kbd/Kbd.d.ts +1 -0
  93. package/dist/Components/Kbd/Kbd.js +1 -0
  94. package/dist/Components/Kbd/KbdProps.d.ts +4 -0
  95. package/dist/Components/LauncherTrigger/LauncherTrigger.d.ts +1 -0
  96. package/dist/Components/LauncherTrigger/LauncherTrigger.js +1 -0
  97. package/dist/Components/LauncherTrigger/LauncherTriggerProps.d.ts +1 -0
  98. package/dist/Components/LimitReachedModal/LimitReachedModal.d.ts +1 -0
  99. package/dist/Components/LimitReachedModal/LimitReachedModal.js +1 -0
  100. package/dist/Components/LimitReachedModal/LimitReachedModalProps.d.ts +7 -0
  101. package/dist/Components/Loading/LoadingProps.d.ts +2 -0
  102. package/dist/Components/MediaGallery/MediaGalleryProps.d.ts +7 -1
  103. package/dist/Components/MediaGallery/MediaLightboxProps.d.ts +5 -0
  104. package/dist/Components/MediaViewer/components/MediaAudioPlayer.d.ts +1 -0
  105. package/dist/Components/MediaViewer/components/MediaAudioPlayer.js +1 -0
  106. package/dist/Components/MediaViewer/components/MediaDocumentStage.d.ts +1 -0
  107. package/dist/Components/MediaViewer/components/MediaDocumentStage.js +1 -0
  108. package/dist/Components/MediaViewer/components/MediaImageViewer.d.ts +1 -0
  109. package/dist/Components/MediaViewer/components/MediaImageViewer.js +1 -0
  110. package/dist/Components/MediaViewer/components/MediaVideoPlayer.d.ts +1 -0
  111. package/dist/Components/MediaViewer/components/MediaVideoPlayer.js +1 -0
  112. package/dist/Components/MediaViewer/components/MediaVideoPlayerProps.d.ts +1 -0
  113. package/dist/Components/MediaViewer/hooks/useFileViewer.d.ts +1 -0
  114. package/dist/Components/MediaViewer/mediaItems.d.ts +25 -0
  115. package/dist/Components/MediaViewer/mediaItems.js +5 -0
  116. package/dist/Components/Modal/Modal.d.ts +3 -0
  117. package/dist/Components/Modal/Modal.js +3 -0
  118. package/dist/Components/Modal/ModalProps.d.ts +6 -1
  119. package/dist/Components/MoreItems/MoreItemsProps.d.ts +2 -0
  120. package/dist/Components/MultiSelect/MultiSelect.d.ts +1 -0
  121. package/dist/Components/MultiSelect/MultiSelect.js +1 -0
  122. package/dist/Components/MultiSelect/MultiSelectProps.d.ts +13 -0
  123. package/dist/Components/NavLauncher/NavLauncherProps.d.ts +58 -0
  124. package/dist/Components/NavLauncher/engine/engine.d.ts +19 -0
  125. package/dist/Components/NavLauncher/match.d.ts +34 -0
  126. package/dist/Components/NavigationBar/NavigationBar.d.ts +1 -0
  127. package/dist/Components/NavigationBar/NavigationBar.js +1 -0
  128. package/dist/Components/NavigationBar/NavigationBarProps.d.ts +15 -0
  129. package/dist/Components/NoteTextArea/NoteTextAreaProps.d.ts +2 -1
  130. package/dist/Components/NotificationBell/NotificationBellProps.d.ts +27 -0
  131. package/dist/Components/NotificationBell/notificationHelpers.d.ts +13 -0
  132. package/dist/Components/NumberInput/NumberInputProps.d.ts +1 -1
  133. package/dist/Components/OffersList/OffersListProps.d.ts +12 -1
  134. package/dist/Components/OptionChip/OptionChipProps.d.ts +5 -0
  135. package/dist/Components/OrderStatusTimeline/OrderStatusTimelineProps.d.ts +10 -0
  136. package/dist/Components/OrderSummary/OrderSummaryProps.d.ts +10 -0
  137. package/dist/Components/OrgSwitcher/OrgSwitcher.d.ts +1 -0
  138. package/dist/Components/OrgSwitcher/OrgSwitcher.js +11 -3
  139. package/dist/Components/OrgSwitcher/OrgSwitcherProps.d.ts +1 -0
  140. package/dist/Components/OrganizationDetails/OrganizationDetailsProps.d.ts +52 -0
  141. package/dist/Components/PageHeader/PageHeaderProps.d.ts +1 -0
  142. package/dist/Components/Pagination/PaginationProps.d.ts +4 -0
  143. package/dist/Components/PaymentOption/PaymentOptionProps.d.ts +9 -0
  144. package/dist/Components/PincodeChecker/PincodeCheckerProps.d.ts +13 -0
  145. package/dist/Components/PlanPill/PlanPill.d.ts +1 -0
  146. package/dist/Components/PlanPill/PlanPill.js +1 -0
  147. package/dist/Components/PlanPill/PlanPillProps.d.ts +1 -0
  148. package/dist/Components/PriceBlock/PriceBlockProps.d.ts +6 -0
  149. package/dist/Components/ProductBadges/ProductBadgesProps.d.ts +3 -0
  150. package/dist/Components/ProductCard/ProductCardProps.d.ts +10 -0
  151. package/dist/Components/ProductCard/QuickAddSheetProps.d.ts +8 -0
  152. package/dist/Components/ProductDetails/ProductDetailsProps.d.ts +25 -1
  153. package/dist/Components/ProfileCard/ProfileCardProps.d.ts +1 -1
  154. package/dist/Components/QuantityStepper/QuantityStepperProps.d.ts +9 -0
  155. package/dist/Components/QueryState/QueryStateProps.d.ts +2 -0
  156. package/dist/Components/RadioButton/RadioButtonProps.d.ts +1 -1
  157. package/dist/Components/Rating/RatingProps.d.ts +2 -0
  158. package/dist/Components/Reorder/ReorderProps.d.ts +6 -0
  159. package/dist/Components/ReviewList/ReviewListProps.d.ts +21 -0
  160. package/dist/Components/ReviewSummary/ReviewSummaryProps.d.ts +8 -1
  161. package/dist/Components/RolesPermission/RolesPermissionProps.d.ts +59 -1
  162. package/dist/Components/SearchSelect/SearchSelect.js +17 -5
  163. package/dist/Components/SearchSelect/SearchSelectProps.d.ts +12 -0
  164. package/dist/Components/SectionRail/SectionRail.d.ts +1 -0
  165. package/dist/Components/SectionRail/SectionRail.js +1 -0
  166. package/dist/Components/SectionRail/SectionRailProps.d.ts +4 -0
  167. package/dist/Components/SegmentedControl/SegmentedControlProps.d.ts +4 -0
  168. package/dist/Components/Select/Select.styles.js +25 -0
  169. package/dist/Components/Select/SelectNative.d.ts +10 -0
  170. package/dist/Components/Select/SelectNative.js +11 -4
  171. package/dist/Components/Select/SelectPopup.js +45 -14
  172. package/dist/Components/Select/SelectProps.d.ts +46 -2
  173. package/dist/Components/Select/selectKeyboardRing.d.ts +2 -0
  174. package/dist/Components/Select/selectKeyboardRing.js +7 -0
  175. package/dist/Components/Select/selectRowInk.d.ts +14 -0
  176. package/dist/Components/Select/selectRowInk.js +41 -0
  177. package/dist/Components/SelectSearch/SelectSearch.js +8 -2
  178. package/dist/Components/SelectSearch/SelectSearchProps.d.ts +9 -0
  179. package/dist/Components/SelectV2/SelectV2Props.d.ts +7 -0
  180. package/dist/Components/SideBar/SecondaryBar.d.ts +1 -0
  181. package/dist/Components/SideBar/SecondaryBar.js +1 -0
  182. package/dist/Components/SideBar/SideBar.d.ts +1 -0
  183. package/dist/Components/SideBar/SideBar.js +1 -0
  184. package/dist/Components/SideBar/SideBarProps.d.ts +32 -0
  185. package/dist/Components/SideBar/sidebarAccentColors.d.ts +2 -0
  186. package/dist/Components/SignInActivityTable/SignInActivityTable.d.ts +1 -0
  187. package/dist/Components/SignInActivityTable/SignInActivityTable.js +1 -0
  188. package/dist/Components/SignInActivityTable/SignInActivityTableProps.d.ts +2 -0
  189. package/dist/Components/SpecTable/SpecTableProps.d.ts +9 -0
  190. package/dist/Components/StageProgress/StageProgressProps.d.ts +2 -0
  191. package/dist/Components/StageProgress/StepperStage.d.ts +1 -0
  192. package/dist/Components/StageProgress/StepperStage.js +1 -0
  193. package/dist/Components/StatCard/StatCardProps.d.ts +1 -0
  194. package/dist/Components/StatusTag/StatusTagProps.d.ts +4 -0
  195. package/dist/Components/StickyBuyBar/StickyBuyBar.d.ts +1 -0
  196. package/dist/Components/StickyBuyBar/StickyBuyBar.js +1 -0
  197. package/dist/Components/StickyBuyBar/StickyBuyBarProps.d.ts +6 -0
  198. package/dist/Components/StockStatus/StockStatusProps.d.ts +2 -0
  199. package/dist/Components/Switch/SwitchProps.d.ts +4 -0
  200. package/dist/Components/Table/TableProps.d.ts +19 -0
  201. package/dist/Components/Table/variants/tokens.d.ts +4 -0
  202. package/dist/Components/Tabs/TabsContext.d.ts +14 -0
  203. package/dist/Components/Tabs/TabsProps.d.ts +18 -0
  204. package/dist/Components/Tabs/components/CountBadge.d.ts +4 -0
  205. package/dist/Components/Tabs/components/TabPanels.d.ts +1 -0
  206. package/dist/Components/Tabs/components/TabPanels.js +1 -0
  207. package/dist/Components/Tabs/tabStyles.d.ts +4 -0
  208. package/dist/Components/Tag/TagProps.d.ts +3 -0
  209. package/dist/Components/TagInput/TagInput.d.ts +1 -0
  210. package/dist/Components/TagInput/TagInput.js +1 -0
  211. package/dist/Components/TagInput/TagInputProps.d.ts +2 -0
  212. package/dist/Components/TimePicker/TimePicker.d.ts +1 -0
  213. package/dist/Components/TimePicker/TimePicker.js +1 -0
  214. package/dist/Components/TimePicker/TimePickerProps.d.ts +2 -0
  215. package/dist/Components/Timeline/TimelineProps.d.ts +7 -1
  216. package/dist/Components/Toggle/TableToggleProps.d.ts +2 -0
  217. package/dist/Components/ToggleSwitch/ToggleSwitchProps.d.ts +2 -0
  218. package/dist/Components/ToolTip/OverflowToolTip.d.ts +1 -0
  219. package/dist/Components/ToolTip/OverflowToolTip.js +1 -1
  220. package/dist/Components/ToolTip/ToolTipProps.d.ts +1 -0
  221. package/dist/Components/TrustBadges/TrustBadgesProps.d.ts +4 -0
  222. package/dist/Components/UpgradeButton/UpgradeButton.d.ts +1 -0
  223. package/dist/Components/UpgradeButton/UpgradeButton.js +1 -0
  224. package/dist/Components/UpgradeButton/UpgradeButtonProps.d.ts +4 -1
  225. package/dist/Components/UserDetails/UserDetailsProps.d.ts +58 -0
  226. package/dist/Components/VariantSelector/VariantSelectorProps.d.ts +4 -0
  227. package/dist/Components/WishlistToggle/WishlistToggleProps.d.ts +4 -0
  228. package/dist/Components/WizardDialog/WizardDialogProps.d.ts +15 -0
  229. package/dist/Components/WizardDialog/wizardSteps.d.ts +17 -5
  230. package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.d.ts +1 -0
  231. package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.js +1 -1
  232. package/dist/Components/WorkspaceWindow/WorkspaceWindow.d.ts +2 -0
  233. package/dist/Components/WorkspaceWindow/WorkspaceWindow.js +2 -1
  234. package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts +13 -0
  235. package/dist/Theme/tokens/brands/index.d.ts +1 -1
  236. package/dist/Theme/tokens/brands/index.js +1 -1
  237. package/dist/Theme/tokens/builders/rowStates.d.ts +6 -0
  238. package/dist/Theme/tokens/builders/rowStates.js +19 -1
  239. package/dist/Theme/tokens/builders/scrollShadow.d.ts +1 -0
  240. package/dist/Theme/tokens/builders/scrollShadow.js +16 -0
  241. package/dist/esm/Components/AppSwitcher/AppSwitcher.js +1 -0
  242. package/dist/esm/Components/AppearanceSettings/AppearanceSettings.js +1 -0
  243. package/dist/esm/Components/AudioRecorder/AudioRecorder.js +1 -0
  244. package/dist/esm/Components/Avatar/AvatarGroup.js +1 -0
  245. package/dist/esm/Components/BulkSelectionBar/BulkSelectionBar.js +1 -0
  246. package/dist/esm/Components/Button/Button.js +1 -0
  247. package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -0
  248. package/dist/esm/Components/CalendarGrid/CalendarGrid.js +1 -0
  249. package/dist/esm/Components/Card/PaymentCard/PaymentCard.js +1 -0
  250. package/dist/esm/Components/ChoiceCard/ChoiceCard.js +1 -0
  251. package/dist/esm/Components/ChoiceCard/ChoiceCardGroup.js +1 -0
  252. package/dist/esm/Components/ConfirmDialog/ConfirmDialog.js +1 -0
  253. package/dist/esm/Components/CustomModulesTable/CustomModulesTable.js +1 -0
  254. package/dist/esm/Components/CustomModulesTable/DeleteModuleModal.js +1 -0
  255. package/dist/esm/Components/CustomModulesTable/EditModuleModal.js +1 -0
  256. package/dist/esm/Components/FormDrawer/FormDrawer.js +1 -0
  257. package/dist/esm/Components/FormField/FormField.js +1 -0
  258. package/dist/esm/Components/Header/Header.js +1 -0
  259. package/dist/esm/Components/Header/HeaderActions.js +1 -0
  260. package/dist/esm/Components/Header/components/desktopMenu.js +1 -0
  261. package/dist/esm/Components/Header/components/mobileMenu.js +1 -0
  262. package/dist/esm/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -1
  263. package/dist/esm/Components/Kbd/Kbd.js +1 -0
  264. package/dist/esm/Components/LauncherTrigger/LauncherTrigger.js +1 -0
  265. package/dist/esm/Components/LimitReachedModal/LimitReachedModal.js +1 -0
  266. package/dist/esm/Components/MediaViewer/components/MediaAudioPlayer.js +1 -0
  267. package/dist/esm/Components/MediaViewer/components/MediaDocumentStage.js +1 -0
  268. package/dist/esm/Components/MediaViewer/components/MediaImageViewer.js +1 -0
  269. package/dist/esm/Components/MediaViewer/components/MediaVideoPlayer.js +1 -0
  270. package/dist/esm/Components/MediaViewer/mediaItems.js +5 -0
  271. package/dist/esm/Components/Modal/Modal.js +3 -0
  272. package/dist/esm/Components/MultiSelect/MultiSelect.js +1 -0
  273. package/dist/esm/Components/NavigationBar/NavigationBar.js +1 -0
  274. package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +13 -5
  275. package/dist/esm/Components/PlanPill/PlanPill.js +1 -0
  276. package/dist/esm/Components/SearchSelect/SearchSelect.js +19 -7
  277. package/dist/esm/Components/SectionRail/SectionRail.js +1 -0
  278. package/dist/esm/Components/Select/Select.styles.js +26 -1
  279. package/dist/esm/Components/Select/SelectNative.js +12 -5
  280. package/dist/esm/Components/Select/SelectPopup.js +47 -16
  281. package/dist/esm/Components/Select/selectKeyboardRing.js +3 -0
  282. package/dist/esm/Components/Select/selectRowInk.js +33 -0
  283. package/dist/esm/Components/SelectSearch/SelectSearch.js +10 -4
  284. package/dist/esm/Components/SideBar/SecondaryBar.js +1 -0
  285. package/dist/esm/Components/SideBar/SideBar.js +1 -0
  286. package/dist/esm/Components/SignInActivityTable/SignInActivityTable.js +1 -0
  287. package/dist/esm/Components/StageProgress/StepperStage.js +1 -0
  288. package/dist/esm/Components/StickyBuyBar/StickyBuyBar.js +1 -0
  289. package/dist/esm/Components/Tabs/components/TabPanels.js +1 -0
  290. package/dist/esm/Components/TagInput/TagInput.js +1 -0
  291. package/dist/esm/Components/TimePicker/TimePicker.js +1 -0
  292. package/dist/esm/Components/ToolTip/OverflowToolTip.js +1 -1
  293. package/dist/esm/Components/UpgradeButton/UpgradeButton.js +1 -0
  294. package/dist/esm/Components/WorkspaceWindow/WorkspaceTrayPreview.js +1 -1
  295. package/dist/esm/Components/WorkspaceWindow/WorkspaceWindow.js +2 -1
  296. package/dist/esm/Theme/tokens/brands/index.js +1 -1
  297. package/dist/esm/Theme/tokens/builders/rowStates.js +18 -1
  298. package/dist/esm/Theme/tokens/builders/scrollShadow.js +15 -0
  299. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -13,11 +13,15 @@ line below names its issue number.
13
13
 
14
14
  ## [Unreleased] — 2.4.2-beta.x
15
15
 
16
- The theme-tokens/dark-mode line. Still in beta; the breaking items below land together in the
17
- next major.
16
+ The theme-tokens/dark-mode line. Every entry below has shipped in a `2.4.2-beta.N` prerelease, the latest
17
+ being `2.4.2-beta.67` (the `beta` dist-tag); betas carry no per-version headings, and "Unreleased" means not yet in
18
+ a stable release. The breaking items below land together in the next major.
18
19
 
19
20
  ### Added
20
21
 
22
+ - **`Select` Playground gains `native` and `variant` controls.** The `/select` demo page can now switch between native and popup
23
+ mode and between the four native variants, and its native examples keep the option you pick.
24
+
21
25
  - **Development warning for an unthemed `colorScheme`.** `Tag` (dot), `RadioButton` and every style that resolves a scale
22
26
  by name now log one `console.warn` per unknown name outside production, then fall back exactly as before (gray, or
23
27
  primary for `RadioButton`). Nothing throws and production is silent.
@@ -428,6 +432,12 @@ next major.
428
432
  - **Repo tooling, no package change.** `scripts/verify-consumers.sh` now covers `lfour/frontend`, finds consumers from a git
429
433
  worktree (`CONSUMERS_ROOT`), writes nothing in a consumer, and exits non-zero when nothing was compared or `tsc` rejected
430
434
  its own config, instead of printing a clean pass.
435
+ - **`Select` popup rows: `renderOptionEnd`, `optionAction` and `checkPlacement`.** `renderOptionEnd(option, state)` puts
436
+ non-interactive content (a badge) between the row and its check. `optionAction={{ icon, label, onAction }}` adds one
437
+ pointer-only, `aria-hidden` row button whose click calls `onAction(option)` and never selects the row, which a button
438
+ placed inside `renderOption` could not do (it bubbled to the row and failed axe `nested-interactive`).
439
+ `checkPlacement="start"` moves the single-select check to the leading column the multi checkbox uses. Omitted, the
440
+ output is exactly as before.
431
441
 
432
442
  ### Changed
433
443
 
@@ -562,6 +572,46 @@ next major.
562
572
 
563
573
  ### Changed (visual)
564
574
 
575
+ - **`OrgSwitcher` rows match the `Select` popup (screenshots pending).** Rows take the option radius and a 4px side inset, the
576
+ active org gets the selected fill (hover and focus on it the stacked rung), keyboard focus draws the neutral 1px inset ring
577
+ instead of the browser outline, the name weight is 500 for the active org and 400 otherwise (was 600/500), and names and roles
578
+ use `Select`'s ink ladder (dark unchanged). Props, ids and ARIA are unchanged.
579
+ - **`SelectSearch` rows match the `Select` popup (screenshots pending).** The keyboard-focused row (real DOM focus, `:focus-visible`
580
+ only) draws the neutral 1px inset ring instead of the browser's outline; a reopened single selection gets the selected fill,
581
+ and hover or focus on it the stacked rung. Light labels and `email` lines use `Select`'s neutral ink ladder (dark unchanged).
582
+ Uncontrolled model, multi's removal of picked options, ids and ARIA are unchanged.
583
+ - **`SearchSelect` rows match the `Select` popup (screenshots pending).** Checked or selected rows get the selected fill, the
584
+ cursor on a selected row the stacked rung, and Arrow/Home/End draw the same neutral 1px inset ring (also on Select All and
585
+ Add New); the mouse clears it. Labels use `Select`'s neutral ink ladder in light (dark unchanged). Selected-label weight,
586
+ radius, `activeIndex` sentinels, `insideSelect` and every prop, id and ARIA attribute are unchanged.
587
+ - **`Select` popup, light: the selected row gets a fill (screenshots pending).** Hover stays today's faint brand tint
588
+ (lavender `#f1edf6`, emerald `#ebefef`). Selected is the next deeper step of the same tint (lavender `#e7e0f0`, emerald
589
+ `#dde4e4`, about 1.29:1 on the panel) and selected+hover one more (`#dfd6eb`, `#d2dbdb`), so hover, selected and both
590
+ read as one family and every adjacent pair is at least 1.10:1 (selected vs stacked 1.08:1). Arrow-key navigation now
591
+ also draws the neutral 1px inset ring in light (`#7b7b7b`, 3:1 on all four fills), because keyboard-on-selected is only
592
+ 1.08:1 from a plain selected row; the mouse never draws it. Multi checked rows get the same fill (checkbox fill stays
593
+ at least 3.2:1). The text ladder holds on the new fills.
594
+ - **Native `Select` `filled`, `flushed` and `unstyled` variants are themed.** They had no keyboard focus indicator, `filled` had
595
+ square corners at `xs`/`sm`, and `flushed` rested on a 1.2:1 hairline. Each now shows the brand border plus glow on `:focus-visible`
596
+ (`unstyled` gets the two-tone ring), `filled`/`unstyled` use the field radius, and `flushed` uses the outline border rung. `outline` is unchanged.
597
+
598
+ - **`Select` popup layout polish, light and dark (screenshots pending).** Fills are unchanged. The single-select check sits
599
+ in a reserved 16px slot so long labels no longer shift by the check's width; Select All has a hairline rule under it; the
600
+ list is padded by the row inset (6px at `sm`, was 4px) so rows sit evenly from the panel edge; the scrolling list shows top
601
+ and bottom scroll shadows (`scrollShadowStylesVertical`, a vertical twin of the Table helper); and a disabled row no longer
602
+ dims as a whole (was opacity 0.4), so its cursor fill and the dark keyboard ring stay visible: light sets its content to a
603
+ solid `#868686` (3.6:1), dark dims the content to 0.55.
604
+ - **`Select` popup, light: row text is one neutral grey ladder, identical on all nine brands (screenshots pending).** The
605
+ brand-derived `text[700]`/`text[900]`/`textMuted` read as soft purple, green or brown. Now (built with `neutralStep` from
606
+ the panel, no mode argument) the label is `#323232` (12.8:1), the selected label `#242424` at weight 500 beside its
607
+ check, the description `#595959` (7:1), and the filter input's placeholder `#757575` (4.6:1, filter only; every other
608
+ field keeps `placeholderInk`). Dark text is unchanged, and `Menu`, `DropDown`, `SearchSelect`, `SelectSearch`,
609
+ `OrgSwitcher` and `CompactSelect` keep reading `optionRowInk`, so their light rows stay brand-tinted.
610
+ - **`Select` popup, dark: selected, hover, stacked and keyboard states are four neutral rungs (screenshots pending).** Hover
611
+ stays `#363636`; the selected row now fills `#3d3d3d`, hovering it `#424242`, and arrow-key navigation draws a 1px
612
+ `#8d8d8d` inset ring (never under the mouse), identical on all nine brands and derived from the panel,
613
+ not a mode. The description line is lifted against the busiest rung. Light follows in the entry below. `SelectPopup` only; `listRowBackgrounds`, `optionRowFill` and the
614
+ other readers of the shared helpers are untouched.
565
615
  - **`Table` rows with `onRowClick` show a keyboard focus ring.** A focused row draws the library's two-tone ring inset around its
566
616
  cells (sticky cells included), on `:focus-visible` only, so a mouse click draws nothing. It clears 3:1 on every row plane in light and dark.
567
617
 
@@ -813,6 +863,13 @@ next major.
813
863
 
814
864
  ### Fixed
815
865
 
866
+ - **`SearchSelect` Select All row now highlights under the mouse.** Only the keyboard reached it before; hover filled every other row.
867
+ - **Native `Select` without a `value` snapped back to the placeholder, and `defaultValue` did nothing.** A native `Select` that never
868
+ received `value` was pinned to `""`, so picking an option reverted at once unless `onChange` stored it. It now keeps its own
869
+ selection, seeded by `defaultValue`, until a defined `value` is passed; after that `value` controls it as before.
870
+
871
+ - **`OrgSwitcher`'s open popup now has an accessible name.** The dialog carried no name (axe `aria-dialog-name`, serious); it
872
+ now reads the existing `ariaLabel` prop ("Switch organization" by default). No new prop, no DOM id changes.
816
873
  - **`FileUploader` revokes its `blob:` preview URLs on unmount.** Images still listed when the component unmounted kept their
817
874
  object URLs alive for the life of the page; removal, `maxFiles` overflow and `maxTotalSize` rejection already revoked.
818
875
  - **`SearchSelect`'s "Clear all" button no longer opens the menu.** Its click bubbled to the control, so Enter, Space or a
@@ -1358,8 +1415,8 @@ than copied here where it can drift.
1358
1415
 
1359
1416
  Get the current number from `scripts/verify-consumers.sh check`, which typechecks every consumer
1360
1417
  against a real build — **do not estimate it by grep.** A grep conflates names that were removed
1361
- outright (`ChakraModal*`, `CardBody`, `ModalContent`, the `Slider*` sub-parts, `TabList`/`TabPanel`)
1362
- with names that still resolve but narrowed (`Avatar`, `AvatarGroup`, `Tabs`, `RangeSlider`), and
1418
+ outright (`ChakraModal*`, `CardBody`, `ModalContent`, the `Slider*` sub-parts)
1419
+ with names that still resolve but narrowed (`Avatar`, `AvatarGroup`, `Tabs`, `Tab`, `TabList`, `TabPanel`, `TabPanels`, `RangeSlider`), and
1363
1420
  overcounts badly — that mistake has already been made twice in this repo's own planning docs.
1364
1421
 
1365
1422
  Layout and composition primitives with no owned equivalent stay exported: `Box`, `Flex`, `Stack`,
@@ -122,6 +122,12 @@ fully-React popup — searchable, `isMulti` with chips, grouped options, `isClea
122
122
  `isMulti` always forces the popup — there is no native multi-select — and dev-warns if you
123
123
  also passed `native`.
124
124
 
125
+ **Native `Select` is uncontrolled until you pass a `value`.** With no `value` it keeps its own selection
126
+ (seeded by `defaultValue`), so `onChange={() => {}}` still lets the user pick. Once a defined `value` has been
127
+ passed it is controlled: an `onChange` that does not store the value snaps the field back, and `value` going
128
+ back to `undefined` shows the placeholder, not the earlier pick. `variant` (`outline`, `filled`, `flushed`,
129
+ `unstyled`) is native-only and inert in popup mode.
130
+
125
131
  **Only `SelectV2` is `@deprecated`. None was deleted; every existing call site still works.**
126
132
 
127
133
  | Deprecated | Status | Migration |
@@ -135,11 +141,11 @@ also passed `native`.
135
141
 
136
142
  | Doing | Component |
137
143
  | --- | --- |
138
- | Typing free-text tags (e.g. email addresses), no options list | `MultiSelect` — despite the name there is nothing to pick from; see gotcha below |
144
+ | Typing free-text tags, no options list | `TagInput` (any text, your own `validate`). `MultiSelect` is the email-only variant — despite the name there is nothing to pick from; see its gotcha below |
139
145
  | Choosing which fields/columns to include, in a modal, from a checkbox grid | `FieldSelectModal` |
140
146
 
141
- `onChange` is the change prop on `Select` and `SelectV2` (`SearchSelect.onSelect` is the one it
142
- actually uses; its `onChange` is passed almost nowhere). `Search` uses `onSearch`/`onClear`
147
+ `onChange` is the change prop on `Select`, `SelectV2` and `SearchSelect` (`SearchSelect.onSelect` is
148
+ `@deprecated`, same payload; `onChange` wins when both are set). `Search` uses `onSearch`/`onClear`
143
149
  (`onclose` is `@deprecated`).
144
150
 
145
151
  ### `Dropdown`'s `handleOptionSelect` takes TWO arguments and TypeScript will not tell you
@@ -148,8 +154,8 @@ The prop is `(id, label) => void`. TypeScript accepts a one-argument function an
148
154
  two-argument one is expected, so `handleOptionSelect={handleSelect}` where `handleSelect`
149
155
  is `(id: string | number) => void` compiles cleanly and silently never receives `label`.
150
156
 
151
- This is live in **10 call sites today** across crm-frontend and commerce — every one of them
152
- a bare function reference rather than an inline arrow.
157
+ Call sites across crm-frontend and commerce hit this, every one a bare function reference rather
158
+ than an inline arrow.
153
159
 
154
160
  **Apply:** pass an inline arrow (`(id, label) => handleSelect(id, label)`) so the arity is
155
161
  visible at the call site, or declare the handler with both parameters. Grep for
@@ -273,7 +279,7 @@ Four components open a file, and only one of them is the general answer.
273
279
  | Always-visible inline PDF panel in the page flow | `PdfViewer` | Non-modal, PDF-only, small open/download toolbar; `getBlob` for files behind auth |
274
280
  | Crop/preview a user avatar | `ProfilePhotoViewer` | Avatar-specific, not a general file viewer |
275
281
 
276
- `PdfViewer` shows a fallback when the browser cannot render a PDF inline (`navigator.pdfViewerEnabled === false`) or `getBlob` rejects; `FilePreview`'s `"pdf"` kind renders a bare `<embed type="application/pdf">` and tells you nothing. `MediaViewer` also handles it: formats a browser cannot decode (`.avi`, `.mkv`, `.m3u8`, `.heic`, `.tiff`) render an icon and a file-type chip with a download action instead of a blank frame.
282
+ `PdfViewer` shows a fallback when the browser cannot render a PDF inline (`navigator.pdfViewerEnabled === false`) or `getBlob` rejects; `FilePreview`'s `"pdf"` kind renders a bare `<embed type="application/pdf">` and tells you nothing. `MediaViewer` also handles it: formats a browser cannot decode (`.avi`, `.mkv`, `.m3u8`, `.heic`, `.heif`) render an icon and a file-type chip with a download action instead of a blank frame.
277
283
 
278
284
  `MediaViewer.labels` takes a `Partial<MediaViewerLabels>` — that type and `defaultMediaViewerLabels` are both exported from the package root, so you can merge rather than restate every string.
279
285
 
@@ -374,9 +380,9 @@ The wrapper is deliberately not a button; make the custom component a button, or
374
380
 
375
381
  | Component | beta.43 → beta.44 | Restore the old look |
376
382
  | --- | --- | --- |
377
- | Fields, selects, buttons (`Button`, `TextInput`, `InputTextArea`, `NumberInput`, DatePicker family, `Select`, `SelectV2`, `SearchSelect`, `SelectSearch`, `Search`, `Dropdown`, `SegmentedControl`) | Default size `md` → `sm` (38px). One scale for all: xs 24 / sm 38 / md 40 / lg 48 — the same height in every field, select and button. `TimePicker` has no `size` (fixed `sm`); `SegmentedControl` has no `xs`. **Since decoupled** — fields/selects now read `CONTROL_SIZES` (xs 24 / sm 38 / md 40 / lg 48 at the time of the split; xs later raised to 32px), `Button`/`SegmentedControl`/`Tabs`/`TableToggle`/`Dropdown`'s trigger read the separate `BUTTON_SIZES` (xs 24 / sm 32 / md 40 / lg 48, back to pre-regression) — see the gotcha below | `size="md"` |
383
+ | Fields, selects, buttons (`Button`, `TextInput`, `InputTextArea`, `NumberInput`, DatePicker family, `Select`, `SelectV2`, `SearchSelect`, `SelectSearch`, `Search`, `Dropdown`, `SegmentedControl`) | Default size `md` → `sm`. Fields/selects read `CONTROL_SIZES` (xs 32 / sm 38 / md 40 / lg 48); `Button`/`SegmentedControl`/`Tabs`/`TableToggle`/`Dropdown`'s trigger read the separate `BUTTON_SIZES` (xs 24 / sm 32 / md 40 / lg 48). `SegmentedControl` has no `xs` — see the gotcha below | `size="md"` |
378
384
  | `Button` | Text one step smaller (sm 14→13px, md 16→14, lg 18→16). Busy = spinner only, width kept (was "Loading" + spinner). Outline: 1px border, hover is a tint, not a fill | `loadingText="Loading"` |
379
- | `Tag` | `solid`/`md` → `subtle`/`sm`. Hover + pointer only with `onTagClick`; `maxW` truncates with the full text as a title. Exact heights 20/24/28/32, weight 500, 1px inset ring (never adds height); subtle is a light tint with ink ≥ 6.5:1 | `variant="solid" size="md"` |
385
+ | `Tag` | `solid`/`md` → `subtle`/`sm`. Hover + pointer only with `onTagClick`; `maxW` truncates with the full text as a title. Exact heights 20/24/28/32, weight 500, 1px inset ring (never adds height); subtle is a light tint with ink ≥ 6:1 | `variant="solid" size="md"` |
380
386
  | `resolveSoftTone` | `bg`/`border` are now translucent (alpha hex) — composite onto the surface before `contrastRatio`; optional 3rd `surface` arg; adds `hoverBg`/`activeBg`. Badge/Alert/Toaster/EmptyState follow | — |
381
387
  | `resolveFilledSurface` | Still white-first; when a white-labelled fill would vanish on the canvas (zinc dark primary) it falls back to a light fill with dark ink. Takes `background` in `colors` now | — |
382
388
  | `Checkbox` / `RadioButton` | Box 16/20/24 → 14/16/20; label 14px; 1px border; one fill rung for every `colorScheme`. **`RadioButton colorScheme` now applies** (was always primary) | — |
@@ -393,7 +399,7 @@ The wrapper is deliberately not a button; make the custom component a button, or
393
399
  | `Button` | Icon-only buttons are square | — |
394
400
  | `ProgressBar` | Fill lifted to ≥ 3:1 on its track — green/orange/blue/cyan are visibly darker in light mode | — |
395
401
  | `PhoneNumberInput` | Default `size` `md` → `sm`, so it matches the `TextInput`s beside it | `size="md"` |
396
- | `PhoneNumberInput` / `PinInput` / `NoteTextArea` | `ref` now attaches; labels bound; PIN digits grouped and named | — |
402
+ | `PhoneNumberInput` / `PinInput` / `NoteTextArea` | `ref` now attaches on `PhoneNumberInput` and `NoteTextArea` (`PinInput` takes none); labels bound; PIN digits grouped and named | — |
397
403
  | `RangeDatePicker` | Outside click keeps a fully picked range (was discarded) | — |
398
404
  | `FilePreview` / `ContactForm` | Radius `2xl` → `xl` | — |
399
405
  | `Avatar` / `Timeline` / `Table` | Generated avatar fills now guarantee ≥ 4.5:1 initials (a name may get a different shade); Timeline rail lifted to 3:1; Table status/filter chips use the soft recipe; stray radii → `lg`/`xl`/`full` | — |
@@ -405,11 +411,11 @@ The wrapper is deliberately not a button; make the custom component a button, or
405
411
  | `DatePicker` (no `pickerType`) | Inference is case-sensitive: `MM` is month, `mm` minutes. `dd/MM/yyyy` was misread as date+time and showed time selects; it is now date-only | `pickerType="datetime"` |
406
412
  | `EmptyState` | Title is an `h3`; image is decorative (`alt=""`, was the title) | `titleAs`, `imageAlt` |
407
413
  | Theme `Badge` / `Card` / field labels | Badge: pill, no uppercase, default `sm`. Card: default variant `elevated` (borderless, `shadows.card`). Label colour `text[700]`; helper/error row 12px | `size`/`variant` props |
408
- | `Header` | `position: sticky; top: 0`, z-index `sticky` (1100, was 1000); `rightSlot` mounts once, not per layout | — |
414
+ | `Header` | `position: sticky; top: 0`, z-index `sticky` (1100); `rightSlot` mounts once, not per layout | — |
409
415
  | `Table` | Radius `xl`; row height 32/40/52 by density; filter button is named "Filter {label}" (tests querying "Search" break); client pagination resets to page 1 when `data.length` changes | — |
410
416
  | `KanbanBoard` | `height`/`maxH` props replace the clipping wrapper; `height="100%"` needs a parent with a definite height | — |
411
417
  | `ProfileCard` / `SideBar` | `variant="outlein"` now draws an outline; header divider 1px `boxborder[200]` / mobile backdrop uses the shared scrim | — |
412
- | `SideBar` | Scroll-container and submenu ids are generated (`useId`) — `#sidebar-scroll-container` / `#submenu-<label>` no longer exist; row heights fixed 20/32/48; count badges use soft tone | — |
418
+ | `SideBar` | Scroll-container and submenu ids are generated (`useId`) — `#sidebar-scroll-container` / `#submenu-<label>` no longer exist; rail rows 32px (44px in the mobile overlay), submenu rows 28px; count badges use soft tone | — |
413
419
  | `ToggleSwitch` | No `aria-required` on the switch (invalid for `role=switch`); `isRequired` still shows `*` | — |
414
420
  | `KanbanBoard` / `PdfViewer` / `UserDetails` | Cards, drag handles and toolbar links get accessible names; scroll panels are focusable regions; `UserDetails` badges 12px | — |
415
421
  | `NumberInput` / `FileUpload` | Steppers exactly half the field height; drop-zone border 1px (was 2px) | — |
@@ -421,7 +427,7 @@ The wrapper is deliberately not a button; make the custom component a button, or
421
427
  | `Tag` | Label line-height 1.45 so descenders (`p`, `g`, `y`) are no longer clipped by the ellipsis overflow | — |
422
428
  | `Toaster` | `error` toasts announce assertively (`role="alert"`); status icons have a text equivalent | — |
423
429
  | `FeedbackForm` | Built on `TextInput`/`InputTextArea`/`RadioButtonGroup`; required fields show `*` in the label | — |
424
- | `PinInput` | `size` now works (square cells 24 / 38 / 40 / 48, default `sm`) — it was silently ignored | `size="md"` |
430
+ | `PinInput` | `size` now works (square cells 32 / 38 / 40 / 48 today, default `sm`) — it was silently ignored | `size="md"` |
425
431
  | `Tag` | New `leadingIcon` (decorative, before the label) and `isDisabled` (sets `aria-disabled` + native `disabled` on the clickable/remove buttons, so they leave the tab order — not just dimmed) | — |
426
432
  | `ToolTip` | Defaults a Popper `preventOverflow` padding of 8px, so a bubble near the right edge no longer overhangs by a subpixel and raises page scrollbars. A caller-supplied `preventOverflow` modifier still wins | pass your own `modifiers` |
427
433
  | `Table` / `KanbanBoard` | Column sort buttons and draggable cards now show the library focus ring on keyboard focus (was an opacity flicker / the browser default outline). Kanban card wrappers render as Chakra `Box`; keyboard drag (Space, arrows, Space) is unchanged | — |
@@ -527,7 +533,7 @@ never mutate what they return.
527
533
  ### Reduced motion is per component unless the app passes `reducedMotion="global"`
528
534
 
529
535
  The library's own animations honour `prefers-reduced-motion` one component at a time. For one
530
- document-wide rule, pass `reducedMotion="global"` to `PixelizeThemeProvider` (or `createBrandTheme`);
536
+ document-wide rule, pass `reducedMotion="global"` to `PixelizeThemeProvider`;
531
537
  transitions and animations then collapse to one near-instant pass. Add `pz-motion-keep`
532
538
  (`MOTION_KEEP_CLASS`) to any loop that is essential feedback; Chakra spinners and progress bars are
533
539
  kept automatically.
@@ -568,8 +574,8 @@ For an accent icon on the gradient, use `resolved.ink` unless the accent clears
568
574
 
569
575
  All three match children by exact type (`child.type === XHeader/XBody/XFooter`) and render only
570
576
  those matches — nothing else in `children` is ever read. A sibling among the slots (a nested
571
- `Modal`, `AlertDialog`, a confirm dialog, a live region) silently never mounts; `Drawer` and `Modal`
572
- `ProfileCard` now warn once per dropped child type in development. All three
577
+ `Modal`, `AlertDialog`, a confirm dialog, a live region) silently never mounts; dev builds of all three
578
+ warn once per dropped child type. All three
573
579
  look through `<>...</>` Fragments around a slot, at any depth (so `<>{cond && <DrawerFooter>...}</>` still renders)
574
580
  and spread styling props (`padding`, `borderBottom`, `sx`, …) from the matched slot onto the real
575
581
  header/body/footer — any other wrapper element still drops the slot.
@@ -616,14 +622,14 @@ green. Pass `onClick` for a clickable card (it renders its own `<button>`); neve
616
622
 
617
623
  ### `CircularProgress` `tone="info"` is the brand primary, not blue
618
624
 
619
- Unlike `Tag` and `StatCard`, where `info` is blue, the default `tone="info"` here paints the brand
625
+ Unlike `Tag` (`tone`) and `StatCard` (`iconTone`), where `info` is blue, the default `tone="info"` here paints the brand
620
626
  primary scale. `aria-label` is required — the ring has no visible caption.
621
627
 
622
628
  ### `TextInput variant="filled"` has no border, only a fill that barely separates it
623
629
 
624
630
  `filled` draws no resting border (`borderColor: "transparent"`), so the field's edge is the fill
625
- alone. That fill measures 1.01-1.06:1 against a card in light mode on the nine brands, well under
626
- the 3:1 that WCAG 1.4.11 asks of a control boundary, and about 1.19:1 in dark mode. The focus ring
631
+ alone. That fill sits well under
632
+ the 3:1 that WCAG 1.4.11 asks of a control boundary, in light and dark. The focus ring
627
633
  and the invalid border still show, but a resting empty field can be hard to find.
628
634
 
629
635
  **Apply:** use the default `variant="outline"` for any form a person must find and fill in. Keep
@@ -680,6 +686,13 @@ server there.
680
686
 
681
687
  **Apply:** a client-side table that looked like it had "no matches" past page 1 now finds them.
682
688
 
689
+ ### A button inside a `Select` `renderOption` row selects the row — use `optionAction`
690
+
691
+ `renderOption` output sits inside `role="option"`, whose click selects. A `<button>` you place in it bubbles to the row
692
+ (and fails axe `nested-interactive`, since options are presentational children). Pass `optionAction={{ icon, label, onAction }}`
693
+ instead: it renders a pointer-only, `aria-hidden` control that calls `onAction(option)` and stops the click. It is not
694
+ focusable, so give keyboard users the same action elsewhere.
695
+
683
696
  ### `Select`'s `onChange` never fires for the built-in placeholder
684
697
 
685
698
  `Select` resolves the changed value against its `options` list and calls `onChange` only on a hit.
@@ -725,13 +738,13 @@ It decides whether each row gets a chevron, so an inline function re-renders eve
725
738
  `row.content` + `isContent` expander (chevron before the checkbox, index-based); both can coexist,
726
739
  but only `row.content` still disables grouped virtualisation.
727
740
 
728
- ### `error` without `errorMessage` renders the literal word "Error" — and erases `helperText`
741
+ ### `error` without `errorMessage` shows no message — and erases `helperText`
729
742
 
730
743
  Every field that shows validation errors (`TextInput`, `InputTextArea`, `Select`, `MultiSelect`,
731
744
  `SelectV2`, `SearchSelect`, `SelectSearch`, `Search`, `Checkbox`, the `DatePicker` variants,
732
- `PhoneNumberInput`) falls back to the literal word **"Error"** when `error` is `true` but
733
- `errorMessage` is empty. Worse, `helperText` only renders when `!error` — so the guidance
734
- disappears exactly when it's needed.
745
+ `PhoneNumberInput`) turns the border red and sets `aria-invalid` when `error` is `true` but renders
746
+ no message when `errorMessage` is empty. Worse, `helperText` only renders when `!error` — so the
747
+ guidance disappears exactly when it's needed, leaving a red field with no text.
735
748
 
736
749
  **Apply:** never pass `error` without `errorMessage`. Gate `error` on a `touched` flag so a field
737
750
  whose defaults arrive asynchronously doesn't open already red.
@@ -758,24 +771,26 @@ receives nothing, and `children` is not type-matched.
758
771
 
759
772
  ### `ContactForm`'s `apiKey` prop is a POST URL, not an auth token
760
773
 
761
- Despite the name, `apiKey` is passed straight into `fetch(apiKey, { method: "POST" })` as the submit
762
- endpoint — never sent as a header or credential. A real API key/secret fails silently as an invalid
763
- URL, surfaced only as a generic "Failed to send message" alert. There's no `headers` prop, so an
764
- authenticated endpoint can't be reached through this component at all.
774
+ Despite the name, `apiKey` is the fallback submit endpoint: only when no `onSubmit` is given, the form
775
+ does `fetch(apiKey, { method: "POST", headers: { "Content-Type": "application/json" }, body })` — never a
776
+ credential header. With both set, `onSubmit` wins and `apiKey` is never fetched. With neither, submit
777
+ shows an inline "API key missing" alert. A real API key/secret fails as an invalid URL or a non-OK
778
+ response, surfaced only as a generic "Failed to send message" alert, and there is no `headers` prop.
765
779
 
766
- **Apply:** pass the full POST URL, never a token. If the endpoint needs auth headers, proxy through
767
- your own backend instead.
780
+ **Apply:** pass the full POST URL, never a token. If the endpoint needs auth headers, pass `onSubmit`
781
+ and make the request yourself.
768
782
 
769
783
  ### `ContactForm` can't tell its parent the submission result
770
784
 
771
- It does its own internal `fetch` and renders its own success/error alert from local state — there is
772
- no `onSuccess`, `onSubmit`, or `onError` prop (a dead `// onSubmit(formData)` line is the only trace
773
- one ever existed). A call site can't redirect, toast, or update its own state when the enquiry sends.
774
- Separately, the email field is validated for format but its "required" check is commented out, so a
775
- blank email submits successfully with no error shown.
785
+ It renders its own success/error alert from local state and has no `onSuccess` or `onError` prop. The
786
+ only hook is `onSubmit(payload)`, which replaces the `apiKey` fetch: it is awaited, a resolve shows the
787
+ success alert and clears the form, a throw shows "Failed to send message". The `apiKey` path tells the
788
+ parent nothing. Separately, the email field is validated for format but its "required" check is
789
+ commented out, so a blank email submits successfully with no error shown.
776
790
 
777
- **Apply:** if the parent needs to react to success, this component can't provide it. Don't rely on
778
- `email` being enforced as required — validate it yourself first if that matters.
791
+ **Apply:** to redirect, toast or update state when the enquiry sends, pass `onSubmit` and do it there
792
+ (rethrow to show the failure alert). Don't rely on `email` being enforced as required — validate it
793
+ yourself first if that matters.
779
794
 
780
795
  ### `VerifyEmailOtp` can't accept alphanumeric codes, and appends "your new Pixel Account"
781
796
 
@@ -865,9 +880,9 @@ three color overrides with `showStatus`; don't use `status` to drive dot color.
865
880
  Both props are optional, and when neither is provided, submit still falls through to the success
866
881
  toast and form reset — validation, spinner, and reset all work end-to-end while the payload is never
867
882
  sent or captured anywhere. Separately, `defaultValues` only seeds state at mount (no resync if it
868
- arrives later from an async fetch), and its toast is Chakra's raw `useToast`, not this library's
869
- `Toaster` — the same portal issue documented for `Toaster`/`Modal` can silently hide it when this
870
- form is embedded in a `Modal`.
883
+ arrives later from an async fetch), and its toast comes from `useToaster`, so it throws outside a
884
+ `ToasterProvider` (`PixelizeThemeProvider` and `withTheme` mount one) — the same portal issue
885
+ documented for `Toaster`/`Modal` can still hide the toast when this form is embedded in a `Modal`.
871
886
 
872
887
  **Apply:** always pass `onSubmit` or `submitUrl` — treat a bare `<FeedbackForm />` as a bug, not a
873
888
  minimal valid usage. Key the element to force a remount if `defaultValues` arrives late. Verify the
@@ -875,7 +890,7 @@ toast actually appears if embedding inside a `Modal`.
875
890
 
876
891
  ### `Checkbox`'s `variant` is a no-op
877
892
 
878
- Typed and accepted, but `Checkbox.styles.ts` defines no `variants` key, so no value changes the
893
+ Typed and accepted (`@deprecated`), but `Checkbox.styles.ts` defines no `variants` key, so no value changes the
879
894
  look. (`error` now sets `isInvalid` and links its message — no need to pass both.)
880
895
 
881
896
  ### `Slider`'s pagination dots can desync from the visible slide
@@ -1106,8 +1121,9 @@ is no longer Chakra's style prop (omitted from the type) — use `p` for a raw v
1106
1121
  `options` must set every axis, or `findVariant` returns `undefined`.
1107
1122
 
1108
1123
  - **`layout="auto"` on `MediaGallery` and `ProductDetails` follows the container, not the window**
1109
- (560px / 960px). `ProductCard` and `QuickAddSheet` `auto` still read the window; pass `layout` /
1110
- `quickAddPresentation` explicitly inside a phone-width frame.
1124
+ (560px / 960px of their own width), falling back to the window query only until the first measure.
1125
+ `ProductCard`'s `layout` (`grid`/`list`/`rail`) has no `auto`. `QuickAddSheet`'s `presentation="auto"`
1126
+ (`ProductCard`'s `quickAddPresentation`) reads the window (modal from `48em`); pass it explicitly inside a phone-width frame.
1111
1127
  - **Drawers and modals portal to the window, never into your phone frame.** `ProductCard`'s quick-add
1112
1128
  sheet needs `quickAddPresentation="drawer"` and `quickAddDrawerProps={{ maxW: "390px !important", mx: "auto" }}`
1113
1129
  there; the `!important` is needed because Chakra's slide sets an inline `max-width: 100vw`.
@@ -1157,6 +1173,12 @@ reach it.
1157
1173
  **Apply:** don't depend on `onChange` firing for a repeat pick. There's no supported way to attach
1158
1174
  test hooks or a ref to the trigger.
1159
1175
 
1176
+ ### `OrgSwitcher`'s popup dialog is named by `ariaLabel`, and its rows follow `Select`'s state ladder
1177
+
1178
+ The open `role="dialog"` now has `aria-label={ariaLabel}` (it had none), so a translated app should pass `ariaLabel` in its own
1179
+ language; the trigger name still reads `${ariaLabel}, ${org name}`. Rows are 4px inset with the option radius, fill the active org,
1180
+ and ring on `:focus-visible` only.
1181
+
1160
1182
  ### `OrgSwitcher display="full"` still squeezes the navbar title on phones — use `display="auto"`
1161
1183
 
1162
1184
  Inside a `NavigationBar` `moreIcon` cluster, a full trigger needs about 88px (avatar + chevron) even
@@ -1171,8 +1193,11 @@ own icon buttons `flexShrink={0}` and let any label truncate.
1171
1193
 
1172
1194
  ### `UpgradeButton`'s gold icon accent silently falls back to the label color on low contrast
1173
1195
 
1174
- The gold accent is only used when it clears AA contrast against both gradient stops; a custom
1175
- `gradient` prop can flip it to the label's own ink color with no signal.
1196
+ Two different ratios apply. The label and subtitle ink clears **4.5:1** (AA text) on both gradient stops:
1197
+ `resolveGradient` darkens the stops until it does, so a custom `gradient` may paint darker than the
1198
+ colors you passed (the built-in variants are pinned per brand and mode in `upgradeButtonInk.test.ts`).
1199
+ The gold icon accent only needs **3:1** (non-text) against both of those painted stops; when it misses
1200
+ either, the icon silently switches to the label ink. An explicit `iconColor` is used as given, unchecked.
1176
1201
 
1177
1202
  **Apply:** don't assume the icon stays gold with a custom `gradient` — check contrast yourself if the
1178
1203
  gold accent is load-bearing for your design.
@@ -1360,15 +1385,27 @@ lights the Jodit frame while focus is inside it. Tab then walks toolbar, editing
1360
1385
  buttons (`config.statusbar: false` drops those). Inside a table cell Tab and Shift+Tab stay with Jodit (next
1361
1386
  cell, a new row after the last, a new row above the first): arrow out of the table before tabbing away.
1362
1387
 
1363
- ### `SelectV2`, `SearchSelect`, and `SelectSearch` all search `option.label` only
1388
+ ### `SearchSelect` and `SelectSearch` search `option.label` only (so does `Select` unless you widen it)
1364
1389
 
1365
- None of the three checks a rendered secondary field (`option.description`, a custom `view` node,
1366
- `option.email` on a profile row) — typing text that's visibly on-screen in a secondary field returns
1367
- no match.
1390
+ Neither checks a rendered secondary field (`option.description`, a custom `view` node, `option.email`
1391
+ on a profile row) — typing text that's visibly on-screen in a secondary field returns no match. `Select`
1392
+ and `SelectV2` (popup mode) match the label too, until you pass `searchFields={["label","description"]}`
1393
+ or a `filterOption(option, query)`.
1368
1394
 
1369
- **Apply:** if a secondary field needs to be searchable, fold it into `option.label` yourself, or
1395
+ **Apply:** on `SearchSelect`/`SelectSearch`, fold a secondary field into `option.label` yourself, or
1370
1396
  pre-filter `options` before passing them in.
1371
1397
 
1398
+ ### `SearchSelect` selected rows are filled now, and the ring is keyboard-only
1399
+
1400
+ Checked or selected option rows paint the `Select` selected fill; hover and keyboard cursor step it deeper, and
1401
+ Arrow/Home/End add a 1px neutral inset ring (the mouse clears it). A test or screenshot that expects an unfilled selected
1402
+ row, or reads the label colour from `text[700]`, now sees the neutral ink ladder in light. Behaviour, ids and ARIA are unchanged.
1403
+
1404
+ ### `SelectSearch` keyboard focus draws a neutral ring, not the browser outline
1405
+
1406
+ Rows are real focus targets; `:focus-visible` now paints the `Select` 1px inset ring (and `outline` stays transparent for forced-colors),
1407
+ and a reopened single selection is filled. A visual or E2E test that expects the UA outline on a focused row no longer sees it.
1408
+
1372
1409
  ### `SearchSelect` never virtualizes
1373
1410
 
1374
1411
  Despite the prop name, `virtualization` does nothing — every filtered option renders as a real DOM
@@ -1522,7 +1559,7 @@ identical data renders as a click-toggled accordion on mobile.
1522
1559
  ### `WorkspaceWindow`'s `state="maximized"` is indistinguishable from `"medium"`
1523
1560
 
1524
1561
  The component only branches on `state === "minimized"` — size is always the same fixed constant, and
1525
- `onMedium`/`onMaximize` are accepted callbacks that are never invoked anywhere in the component.
1562
+ `onMedium`/`onMaximize` are `@deprecated` callbacks that are never invoked anywhere in the component.
1526
1563
 
1527
1564
  **Apply:** treat `state` as effectively two-valued (open vs. `"minimized"`); don't wire a maximize
1528
1565
  control expecting `onMaximize` to fire.
@@ -1544,7 +1581,7 @@ none of them do anything.
1544
1581
 
1545
1582
  ### `Breadcrumbs`' `isLastChild` prop is accepted but never read
1546
1583
 
1547
- It's declared on the type but omitted from the component's destructure entirely.
1584
+ It's declared on the type (`@deprecated`) but omitted from the component's destructure entirely.
1548
1585
 
1549
1586
  **Apply:** don't pass it expecting it to mark or style the final crumb — there's nothing it can do.
1550
1587
 
@@ -1681,12 +1718,13 @@ keeps its `ol` role, so its `aria-label` names the list rather than a region.
1681
1718
 
1682
1719
  **Apply:** pass `aria-label` ("Deal stages") on every read-only `StageProgress` that can overflow.
1683
1720
 
1684
- ### `Table`'s `isVisiblity`, `tableSettings`, `handleExportChange`/`exportOptions`/`exportLabel`, and `onColumnFilter` are dead props — now `@deprecated`
1721
+ ### `Table`'s `isVisiblity`, `tableSettings`, `handleExportChange`/`exportOptions`/`exportLabel`, `onColumnFilter`, `headerBgColor`/`tableBorderColor`, and a column's `isSearch` are dead props — all `@deprecated`
1685
1722
 
1686
1723
  Grepped account-frontend, tickets, crm-frontend, hrms and social-frontend: zero consumers set any of
1687
- these six. All six are now marked `@deprecated` in `TableProps.tsx` rather than removed outright, in
1688
- case an app outside those five repos relies on one. None of these do anything in the current
1689
- implementation, despite being typed on `TableProps` (and some documented on the demo page):
1724
+ the `TableProps` ones. Every prop below carries `@deprecated` in `TableProps.tsx` (eight on `TableProps`,
1725
+ plus `isSearch` on the column definition `TableHeaderProps`) rather than being removed outright, in case
1726
+ an app outside those five repos relies on one. None of them does anything in the current implementation,
1727
+ despite being typed (and some documented on the demo page):
1690
1728
 
1691
1729
  - `isVisiblity` — `Table`'s own destructure never lists it, so a consumer's value is dropped. It's
1692
1730
  hardcoded `true` into both `Pagination` call sites regardless, and `Pagination` doesn't read it
@@ -1695,10 +1733,10 @@ implementation, despite being typed on `TableProps` (and some documented on the
1695
1733
  - `tableSettings` (`{filters, filterSelected, onFilterSelection}`) — `Table` passes it to
1696
1734
  `TableSettings`, but `TableSettings`'s function signature never destructures it.
1697
1735
  - `handleExportChange` / `exportOptions` / `exportLabel` — `Table` renders no export UI at all; none
1698
- of the three are read anywhere, despite `src/Pages/table.tsx` documenting them as if live.
1699
- - `onColumnFilter` — commented out of `Table`'s own destructure (`// onColumnFilter`).
1700
- - `headerBgColor` / `tableBorderColor` — also dead and `@deprecated`; the header paints the
1701
- variant's own background.
1736
+ of the three are read anywhere.
1737
+ - `onColumnFilter` — `Table.tsx` never references it.
1738
+ - `headerBgColor` / `tableBorderColor` — the header paints the variant's own background; neither is read.
1739
+ - column `isSearch` (on `TableHeaderProps`) — every column gets the filter popover regardless.
1702
1740
 
1703
1741
  **Apply:** don't reach for any of these expecting an effect. Column visibility is driven by
1704
1742
  `isTableSettings` (shows the Settings gear) + `preferences` (server persistence) + the Manage
@@ -1949,7 +1987,8 @@ from `optionRowDescriptionInk(theme.colors)` (exported from the package root) ra
1949
1987
  `listRowBackgrounds(colors).selected` and `.active` sit within 1.02:1 of each other on every brand
1950
1988
  and mode, so a list that fills both the selected row and the hovered row shows two identical fills
1951
1989
  and the user cannot tell which one is chosen. Library option lists paint one fill — the cursor's —
1952
- and mark selection with `optionRowWeight` plus a trailing `Check` in `colors.accentText`.
1990
+ and mark selection with `optionRowWeight` plus a trailing `Check` in `colors.accentText`. (`Select`'s own popup
1991
+ additionally fills the selected row (a deeper step of the hover tint in light, a neutral rung in dark; not exported); a custom list keeps one fill.)
1953
1992
 
1954
1993
  **Apply:** `bg={optionRowFill(listRowBackgrounds(colors), isActive)}` for an index-driven list, or
1955
1994
  `{...optionRowCursorSx(listRowBackgrounds(colors))}` for rows that take DOM focus; both are exported
package/DESIGN-GUIDE.md CHANGED
@@ -69,7 +69,7 @@ the four: `<Text textStyle="label">`. The ramp (`TEXT_STYLES`, also a root expor
69
69
 
70
70
  Chakra size keys only (`xs-minus xs xs-plus sm md lg xl 2xl`) — never `fontSize="14px"`.
71
71
  `xs-plus` (13px) is the control size; `xs-minus` (11px) is for chips, counts, keyboard hints and
72
- overlines only; nothing is smaller. Weights: 400 body, 500 labels, 600 titles, 700 KPI numbers only.
72
+ overlines only; nothing is smaller. Weights: 400 body, 500 labels, 600 titles, 700 KPI numbers and the `title` step only.
73
73
 
74
74
  **Radius and elevation come from the role, not the scale step.** `RADIUS_ROLE` (root export) names
75
75
  the radius a surface plays: `control`, `field`, `tooltip` and `media` 8px · `option` 6px · `card`,
@@ -117,11 +117,12 @@ utility scheme to tell two categories apart.
117
117
 
118
118
  ## 5. Controls — two scales, `sm` by default
119
119
 
120
- Fields (`TextInput`, `InputTextArea`, `NumberInput`, `Select`, `Search`, `RangeSlider`, the
120
+ Fields (`TextInput`, `InputTextArea`, `NumberInput`, `Select`, `Search`, the
121
121
  `DatePicker` family) sit on `CONTROL_SIZES` — `xs` 32px · `sm` 38px · `md` 40px · `lg` 48px.
122
122
  `Button` and every button-like trigger (`SegmentedControl`, `Tabs`, `TableToggle`, `Dropdown`)
123
123
  sit on the separate `BUTTON_SIZES` scale — `xs` 24px · `sm` 32px · `md` 40px · `lg` 48px. Both
124
- **default to `sm`**, so on a desktop page **don't pass `size`**. They line up at `md`/`lg`; at
124
+ **default to `sm`**, so on a desktop page **don't pass `size`**. `RangeSlider` takes the same
125
+ size names but keeps its own track and thumb values. They line up at `md`/`lg`; at
125
126
  `sm` a button reads 6px shorter than the field beside it.
126
127
 
127
128
  | Button role | Props |
@@ -193,6 +194,17 @@ sections are `Card` with the title in `header`.
193
194
  | Notification tray | `NotificationBell` (badge, needs `aria-label`) opening a `NotificationPanel` (zones, filters, all four states) |
194
195
  | Confirm that needs the name typed to arm it | `ConfirmDialog confirmationText="delete-me"` — `onConfirm` does **not** close; call `onClose` yourself |
195
196
  | Scrim over the page or one panel while something runs | `Backdrop open loader` — `variant="dim"` by default. Add `container` to scope it to the nearest positioned ancestor, `allowBackgroundInteraction` to let clicks through, `onClick` to dismiss |
197
+ | A short "saved" / "copied" / "failed" notice | `useToaster().showToast({ title, status })` (`PixelizeThemeProvider` and `withTheme` mount the provider) — not a `ToolTip`, not an `AlertDialog` |
198
+ | Page through a list that is not a `Table` | `Pagination` (controlled: numbered pages, previous / next, optional rows-per-page picker) |
199
+ | Faceted filter column (checkboxes, radios, ranges) | `FilterSidebar` (`sidebarOptions`; controlled only when both `selected` and `onChange` are set) |
200
+ | Pick one of a few options as cards | `ChoiceCardGroup` of `ChoiceCard`; payment methods are `PaymentOptionGroup` of `PaymentOption` |
201
+ | On / off setting | `ToggleSwitch` — `Switch` is deprecated, a two-option pill is `SegmentedControl` |
202
+ | One-time code | `PinInput` · free-text chips: `TagInput` · email chips: `MultiSelect` (it has no options list) |
203
+ | Copy a value to the clipboard | `CopyButton` (icon, button or menu-item layout) — not a hand-built `navigator.clipboard` button |
204
+ | Plan state and upsell | `PlanBadge` (resolves org plan data into a `PlanPill`), `UpgradeButton` for the CTA, `LimitReachedModal` when a limit is hit |
205
+ | Charts | `ApexBarChart` · `ApexLineChart` · `ApexAreaChart` · `ApexPieChart` · `ApexRadialChart` · `ApexPolarChart`, inside a `Card`; default series colours follow the theme, so don't pass hexes |
206
+ | Whole admin screens (roles matrix, user directory, org list, sign-in history) | `RolesPermission` · `UserDetails` · `OrganizationDetails` · `SignInActivityTable` — don't rebuild them |
207
+ | "+N more" on an overflowed list | `MoreItems` |
196
208
 
197
209
  **Reach for `Backdrop` in new work** — the `dim` scrim (black at 0.5, no blur, 225ms in /
198
210
  195ms out) replaces every hand-rolled `position: fixed` overlay. Never build your own
@@ -260,7 +272,7 @@ no-access panel between loading and error; `hasData` keeps content on screen dur
260
272
  | --- | --- |
261
273
  | Loading | `loadingFallback` of `Skeletons` shaped like the content (rows, cards, `StatCard isLoading`) — never a lone centered `Spinner` for a page |
262
274
  | Empty (first run) | `empty={{ icon, title, description, action }}` — the primary action as `action` |
263
- | Empty (filtered) | `EmptyState size="sm"` "No results for these filters" + a ghost "Clear filters" button |
275
+ | Empty (filtered) | `FilteredEmptyState` (`filterCount`, `onClearFilters`, `onRemoveLastFilter`; `scale="card"` inside a panel) — in the boundary pass `isEmpty` + `isFiltered` |
264
276
  | Error | `ErrorState` (the boundary's `errorTitle`/`errorDescription`/`onRetry`): what failed + an outline "Retry" (+ `action` "Back to …" on a detail page) |
265
277
 
266
278
  Page header stays visible in every state; only the content region swaps. Keep **one solid button
@@ -304,7 +316,7 @@ not shipped in this package). Start from the closest one:
304
316
  | Settings / long form | `settings.tsx` | `SectionRail` (rail from `lg`, `Select` below, dirty dots), `SettingsSection` + `SettingRow`, `SaveBar`, danger zone |
305
317
  | Board | `pipeline.tsx` | `KanbanBoard` with custom cards and column totals (`height`/`maxH` to size it) |
306
318
  | Inbox / master–detail | `inbox.tsx` | selectable list rows, conversation pane, composer, mobile list↔detail |
307
- | App launcher (browse, pins, recents, search with actions) | `launcher.tsx` (`/examples/launcher`) | `NavLauncher` + `LauncherTrigger` in `NavigationBar leading`, app-owned registry and permission filter, pinned / frequent / recent ids, `linkAs`, remote results via `extraResults`, `isLoading`, `SideBar pinnedItems`, Classic / Spotlight toggle, synonyms, scopes, quick actions, company facts with Copy, answers |
319
+ | App launcher (browse, pins, recents, search with actions) | `launcher.tsx` (`/examples/launcher`) | `NavLauncher` with an app-owned registry and role-based permission filter, pinned / frequent / recent ids, `linkAs`, remote results via `extraResults`, `isLoading`, Classic / Spotlight toggle, synonyms, scopes, quick actions, company facts with Copy, answers |
308
320
  | Wizard / multi-step dialog | `wizard.tsx` (`/examples/wizard`) | `WizardDialog`, inline `Wizard` and `WizardDialog chrome="inline"` in a `WorkspaceWindow`: per-step `validate` messages, locked future steps, error summary, `summary`-driven review, `isFinishing` |
309
321
  | Template editor with merge fields | `templateEditor.tsx` (`/examples/template-editor`) | `Editor mergeFields`: grouped Insert field, chips, unknown-field error chips and `onUnknownTokens`, Make dynamic, side preview, label / helper / error |
310
322
  | Shop front (home → listing → product → bag → checkout → order) | `storefront/` | `ProductCard` grid / rail / quick-add, `ProductDetails` + `StickyBuyBar`, `CartItem`, `OrderSummary`, `CouponField`, address/payment groups, `OrderStatusTimeline`, `BagBar`; mobile frame + desktop |
@@ -317,7 +329,7 @@ and rules: [COMPONENT-GOTCHAS.md](COMPONENT-GOTCHAS.md) "Commerce kit".
317
329
  - **Model the product once** as `axes` + `variants` (`OptionAxis[]`, `ProductVariant[]`) and hand the
318
330
  same objects to `ProductCard`, `QuickAddSheet`, `VariantSelector` and `ProductDetails`. Any vertical
319
331
  works — colour/size, pack size, storage, finish, shade — because the components only see axis ids.
320
- - **Mobile first.** Cards in a 2-up `ProductCardGrid` (`density="compact"`), a swipe `MediaGallery`,
332
+ - **Mobile first.** `ProductCard density="compact"` in a 2-up `ProductCardGrid`, a swipe `MediaGallery`,
321
333
  `StickyBuyBar` and `BagBar` pinned at the bottom, sheets (`QuickAddSheet`, filters) instead of popovers.
322
334
  - **One loud action per view:** the single brand-filled button is Add to bag / Place order. Wishlist,
323
335
  Buy now, Remove and Move-to-wishlist are soft or ghost.