@micha.bigler/ui-core-micha 3.14.3 → 4.0.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 (367) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -0
  3. package/dist/auth/UserMenu.js +1 -1
  4. package/dist/auth/apiClient.js +7 -6
  5. package/dist/chat/ChatList.js +1 -1
  6. package/dist/chat/ChatThread.js +2 -1
  7. package/dist/chat/ChatWorkspace.js +1 -1
  8. package/dist/chat/ModelPicker.js +2 -5
  9. package/dist/chat/kitSxRegistry.js +9 -0
  10. package/dist/chat/useChatSocket.js +1 -1
  11. package/dist/components/LoginForm.js +1 -1
  12. package/dist/components/SecurityComponent.js +1 -1
  13. package/dist/components/UserListComponent.js +2 -8
  14. package/dist/components/charts/ChartFrame.js +1 -1
  15. package/dist/components/charts/ScatterChart.js +2 -1
  16. package/dist/components/charts/kitSxRegistry.js +6 -0
  17. package/dist/entries/charts.js +6 -0
  18. package/dist/entries/chat.js +8 -0
  19. package/dist/entries/markdown.js +1 -0
  20. package/dist/index.js +0 -14
  21. package/dist/layout/SectionNav.js +1 -1
  22. package/dist/messaging/AttachmentList.js +2 -2
  23. package/dist/messaging/Composer.js +2 -1
  24. package/dist/messaging/ConversationLaunchers.js +1 -4
  25. package/dist/messaging/ConversationList.js +1 -1
  26. package/dist/messaging/DirectMessageLauncher.js +1 -1
  27. package/dist/messaging/MessagingProvider.js +0 -0
  28. package/dist/messaging/PollCard.js +7 -5
  29. package/dist/messaging/ReadTicks.js +2 -2
  30. package/dist/messaging/Thread.js +5 -3
  31. package/dist/notifications/NotificationBell.js +4 -7
  32. package/dist/notifications/NotificationSettings.js +1 -1
  33. package/dist/onboarding/OnboardingProvider.js +3 -6
  34. package/dist/pages/AccountPage.js +1 -2
  35. package/dist/pages/LoginPage.js +2 -3
  36. package/dist/pages/PasswordChangePage.js +2 -3
  37. package/dist/pages/PasswordInvitePage.js +2 -3
  38. package/dist/pages/PasswordResetRequestPage.js +2 -3
  39. package/dist/pages/SignUpPage.js +2 -3
  40. package/dist/pages/SignupConfirmPage.js +2 -3
  41. package/dist/theme/createAppTheme.js +5 -4
  42. package/dist/theme/kitSxEntry.js +11 -0
  43. package/dist/theme/kitSxRegistry.js +2 -15
  44. package/dist/theme/themeCompleteness.js +3 -12
  45. package/dist/utils/auth-errors.js +4 -3
  46. package/package.json +41 -16
  47. package/.github/workflows/publish.yml +0 -126
  48. package/DESIGN.md +0 -60
  49. package/WORK_ORDERS.md +0 -148
  50. package/dev/entries.jsx +0 -721
  51. package/dev/fixtures.js +0 -26
  52. package/dev/main.jsx +0 -75
  53. package/dev/mockTransport.jsx +0 -128
  54. package/docs/CHART-LAYOUT.md +0 -157
  55. package/docs/DARK-TOKENS.md +0 -140
  56. package/docs/TYPE-SCALE.md +0 -111
  57. package/docs/messaging-deviations.md +0 -118
  58. package/index.html +0 -12
  59. package/renovate.json +0 -10
  60. package/scripts/chart-api-census.mjs +0 -415
  61. package/src/auth/AuthContext.jsx +0 -158
  62. package/src/auth/ReauthModal.jsx +0 -82
  63. package/src/auth/UserMenu.jsx +0 -121
  64. package/src/auth/apiClient.jsx +0 -232
  65. package/src/auth/authApi.jsx +0 -539
  66. package/src/auth/authConfig.jsx +0 -34
  67. package/src/auth/reauth.js +0 -47
  68. package/src/chat/ChatComposer.jsx +0 -36
  69. package/src/chat/ChatList.jsx +0 -87
  70. package/src/chat/ChatThread.jsx +0 -128
  71. package/src/chat/ChatWorkspace.jsx +0 -244
  72. package/src/chat/MarkdownReply.jsx +0 -22
  73. package/src/chat/ModelPicker.jsx +0 -85
  74. package/src/chat/api.js +0 -18
  75. package/src/chat/useChatSocket.js +0 -32
  76. package/src/chat/wire.js +0 -7
  77. package/src/components/AccessCodeManager.jsx +0 -288
  78. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  79. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  80. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  81. package/src/components/BulkInviteCsvTab.jsx +0 -198
  82. package/src/components/EmptyState.jsx +0 -38
  83. package/src/components/LoginForm.jsx +0 -159
  84. package/src/components/MFAComponent.jsx +0 -350
  85. package/src/components/MfaLoginComponent.jsx +0 -252
  86. package/src/components/MobileBottomNav.jsx +0 -82
  87. package/src/components/PasskeysComponent.jsx +0 -252
  88. package/src/components/PasswordChangeForm.jsx +0 -87
  89. package/src/components/PasswordResetRequestForm.jsx +0 -43
  90. package/src/components/PasswordSetForm.jsx +0 -97
  91. package/src/components/ProfileComponent.jsx +0 -348
  92. package/src/components/QrSignupManager.jsx +0 -404
  93. package/src/components/QrSignupValidityManager.jsx +0 -106
  94. package/src/components/RegistrationMethodsManager.jsx +0 -150
  95. package/src/components/SecurityComponent.jsx +0 -141
  96. package/src/components/SocialLoginButtons.jsx +0 -83
  97. package/src/components/SoftChip.jsx +0 -93
  98. package/src/components/StatTile.jsx +0 -39
  99. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  100. package/src/components/TurnstileWidget.jsx +0 -99
  101. package/src/components/UserInviteComponent.jsx +0 -76
  102. package/src/components/UserListComponent.jsx +0 -618
  103. package/src/components/charts/BarChart.jsx +0 -102
  104. package/src/components/charts/ChartFrame.jsx +0 -214
  105. package/src/components/charts/LineChart.jsx +0 -126
  106. package/src/components/charts/ScatterChart.jsx +0 -299
  107. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  108. package/src/components/charts/chartDefaults.js +0 -644
  109. package/src/components/charts/chartLabels.js +0 -36
  110. package/src/components/charts/exportChart.js +0 -258
  111. package/src/components/charts/formatters.js +0 -39
  112. package/src/components/charts/palette.js +0 -33
  113. package/src/components/charts/yearTickInterval.js +0 -7
  114. package/src/i18n/authTranslations.ts +0 -2651
  115. package/src/i18n/chartsTranslations.ts +0 -91
  116. package/src/i18n/chatTranslations.ts +0 -55
  117. package/src/i18n/messagingTranslations.ts +0 -120
  118. package/src/i18n/notificationsTranslations.ts +0 -32
  119. package/src/i18n/onboardingTranslations.ts +0 -29
  120. package/src/i18n/sectionNavTranslations.ts +0 -20
  121. package/src/i18n/uiCoreTranslations.js +0 -29
  122. package/src/i18n/userMenuTranslations.ts +0 -5
  123. package/src/index.js +0 -158
  124. package/src/layout/PageLayout.jsx +0 -36
  125. package/src/layout/SectionNav.jsx +0 -320
  126. package/src/messaging/AttachmentList.jsx +0 -145
  127. package/src/messaging/Composer.jsx +0 -197
  128. package/src/messaging/ConversationLaunchers.jsx +0 -51
  129. package/src/messaging/ConversationList.jsx +0 -109
  130. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  131. package/src/messaging/MessageBubble.jsx +0 -183
  132. package/src/messaging/MessagingProvider.jsx +0 -0
  133. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  134. package/src/messaging/PollCard.jsx +0 -163
  135. package/src/messaging/ReactionBar.jsx +0 -43
  136. package/src/messaging/ReadTicks.jsx +0 -82
  137. package/src/messaging/Thread.jsx +0 -195
  138. package/src/messaging/api.js +0 -48
  139. package/src/messaging/composerImageCompression.js +0 -35
  140. package/src/messaging/linkifyText.jsx +0 -37
  141. package/src/notifications/NotificationBell.jsx +0 -84
  142. package/src/notifications/NotificationSettings.jsx +0 -330
  143. package/src/notifications/NotificationsProvider.jsx +0 -224
  144. package/src/notifications/PopupSurface.jsx +0 -105
  145. package/src/notifications/api.js +0 -55
  146. package/src/notifications/feedApi.js +0 -18
  147. package/src/notifications/realtime.jsx +0 -138
  148. package/src/notifications/serviceWorker/sw.js +0 -50
  149. package/src/onboarding/OnboardingProvider.jsx +0 -326
  150. package/src/onboarding/OnboardingWizard.jsx +0 -61
  151. package/src/onboarding/WizardDialogShell.jsx +0 -51
  152. package/src/onboarding/api.js +0 -13
  153. package/src/onboarding/stepSelection.js +0 -16
  154. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  155. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  156. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  157. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  158. package/src/pages/AccountPage.jsx +0 -394
  159. package/src/pages/LoginPage.jsx +0 -343
  160. package/src/pages/PasswordChangePage.jsx +0 -62
  161. package/src/pages/PasswordInvitePage.jsx +0 -177
  162. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  163. package/src/pages/SignUpPage.jsx +0 -268
  164. package/src/pages/SignupConfirmPage.jsx +0 -155
  165. package/src/testing/checkKitIntegration.js +0 -233
  166. package/src/theme/createAppTheme.js +0 -423
  167. package/src/theme/fonts.js +0 -3
  168. package/src/theme/index.js +0 -21
  169. package/src/theme/kitSxRegistry.js +0 -285
  170. package/src/theme/themeCompleteness.js +0 -1045
  171. package/src/theme/tokens.js +0 -478
  172. package/src/utils/auth-errors.js +0 -76
  173. package/src/utils/authService.js +0 -223
  174. package/src/utils/resolveErrorText.js +0 -28
  175. package/src/utils/webauthn.js +0 -51
  176. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  177. package/tests/AccountPage.test.jsx +0 -200
  178. package/tests/AuthContext.test.jsx +0 -129
  179. package/tests/BarChart.test.jsx +0 -112
  180. package/tests/BrowserPushStep.test.jsx +0 -110
  181. package/tests/ChartFrame.test.jsx +0 -336
  182. package/tests/ConversationList.test.jsx +0 -144
  183. package/tests/CookieConsentStep.test.jsx +0 -69
  184. package/tests/EmptyState.test.jsx +0 -62
  185. package/tests/LineChart.test.jsx +0 -80
  186. package/tests/MessagingProvider.test.jsx +0 -50
  187. package/tests/MobileBottomNav.test.jsx +0 -319
  188. package/tests/NotificationBell.test.jsx +0 -60
  189. package/tests/NotificationSettings.test.jsx +0 -276
  190. package/tests/NotificationsProvider.test.jsx +0 -240
  191. package/tests/OnboardingProvider.test.jsx +0 -294
  192. package/tests/OnboardingWizard.test.jsx +0 -143
  193. package/tests/PasswordChangeForm.test.jsx +0 -70
  194. package/tests/PasswordInvitePage.test.jsx +0 -142
  195. package/tests/PasswordSetForm.test.jsx +0 -70
  196. package/tests/PopupSurface.test.jsx +0 -142
  197. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  198. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  199. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  200. package/tests/ScatterChart.test.jsx +0 -270
  201. package/tests/SectionNav.test.jsx +0 -363
  202. package/tests/SignUpPage.test.jsx +0 -208
  203. package/tests/SoftChip.test.jsx +0 -105
  204. package/tests/StatTile.test.jsx +0 -57
  205. package/tests/Thread.test.jsx +0 -151
  206. package/tests/TimeSeriesChart.test.jsx +0 -367
  207. package/tests/UserListComponent.test.jsx +0 -192
  208. package/tests/UserMenu.test.jsx +0 -171
  209. package/tests/apiClientLanguage.test.js +0 -33
  210. package/tests/apiClientPublicPaths.test.js +0 -178
  211. package/tests/authApiLogin.test.js +0 -42
  212. package/tests/authApiRegistration.test.js +0 -31
  213. package/tests/authErrorCodeRendering.test.jsx +0 -77
  214. package/tests/authErrors.test.js +0 -74
  215. package/tests/authTranslations.test.js +0 -74
  216. package/tests/chart-api-census.test.js +0 -366
  217. package/tests/chartAxisTickBand.test.jsx +0 -95
  218. package/tests/chartDefaults.test.js +0 -902
  219. package/tests/chartLabels.test.js +0 -50
  220. package/tests/chartsPalette.test.js +0 -99
  221. package/tests/chatApi.test.js +0 -48
  222. package/tests/chatDriverNames.test.jsx +0 -71
  223. package/tests/chatExports.test.js +0 -3
  224. package/tests/chatList.test.jsx +0 -84
  225. package/tests/chatPicker.test.jsx +0 -82
  226. package/tests/chatSocket.test.jsx +0 -26
  227. package/tests/chatThread.test.jsx +0 -116
  228. package/tests/chatTranslations.test.js +0 -47
  229. package/tests/chatWorkspace.test.jsx +0 -234
  230. package/tests/checkKitIntegration.test.jsx +0 -219
  231. package/tests/createAppTheme.test.js +0 -132
  232. package/tests/createAppThemeDark.test.js +0 -127
  233. package/tests/createAppThemeLightGuard.test.js +0 -40
  234. package/tests/createAppThemePageContrast.test.js +0 -108
  235. package/tests/createAppThemeTypography.test.js +0 -53
  236. package/tests/errorCallSiteGuard.test.js +0 -32
  237. package/tests/exportChart.test.js +0 -313
  238. package/tests/feedApi.test.js +0 -46
  239. package/tests/fixtures/light-theme-baseline.json +0 -2234
  240. package/tests/i18nAggregate.test.js +0 -120
  241. package/tests/i18nGermanVariant.test.js +0 -65
  242. package/tests/loginPageErrorResolution.test.jsx +0 -102
  243. package/tests/messagingApi.test.js +0 -32
  244. package/tests/messagingChunk6.test.jsx +0 -116
  245. package/tests/messagingCompactBubble.test.jsx +0 -64
  246. package/tests/messagingComposer.test.jsx +0 -136
  247. package/tests/messagingComposerChunk5.test.jsx +0 -113
  248. package/tests/messagingContractConformance.test.js +0 -69
  249. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  250. package/tests/messagingExports.test.js +0 -21
  251. package/tests/messagingInteractions.test.jsx +0 -136
  252. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  253. package/tests/messagingLinkify.test.jsx +0 -51
  254. package/tests/messagingMessageActions.test.jsx +0 -163
  255. package/tests/messagingMsg6.test.jsx +0 -105
  256. package/tests/messagingMsg6f.test.jsx +0 -155
  257. package/tests/messagingMsg6g.test.jsx +0 -166
  258. package/tests/messagingMsg6h.test.jsx +0 -136
  259. package/tests/messagingMsg6i.test.jsx +0 -129
  260. package/tests/messagingPollRendering.test.jsx +0 -142
  261. package/tests/messagingReactionMerge.test.jsx +0 -77
  262. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  263. package/tests/messagingThreadReceipts.test.jsx +0 -178
  264. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  265. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  266. package/tests/notificationsApi.test.js +0 -41
  267. package/tests/notificationsExports.test.js +0 -34
  268. package/tests/onboardingDescriptors.test.js +0 -132
  269. package/tests/packageTreeShaking.test.js +0 -126
  270. package/tests/realtime.test.jsx +0 -219
  271. package/tests/resolveErrorText.test.js +0 -72
  272. package/tests/stepSelection.test.js +0 -53
  273. package/tests/themeCompleteness.test.js +0 -626
  274. package/tests/timeSeriesLegend.test.js +0 -99
  275. package/tests/userScreenTranslations.test.jsx +0 -218
  276. package/tsconfig.build.json +0 -18
  277. package/vite.config.mjs +0 -6
  278. package/work-orders/AUTH-1.md +0 -74
  279. package/work-orders/AUTH-2.md +0 -74
  280. package/work-orders/AUTH-4.md +0 -183
  281. package/work-orders/AUTH-5.md +0 -154
  282. package/work-orders/AUTH-7.md +0 -181
  283. package/work-orders/AUTH-8.md +0 -184
  284. package/work-orders/CHART-1.md +0 -285
  285. package/work-orders/CHART-2.md +0 -222
  286. package/work-orders/CHART-3.md +0 -163
  287. package/work-orders/CHART-4.md +0 -203
  288. package/work-orders/CHART-5.md +0 -226
  289. package/work-orders/CHART-6.md +0 -428
  290. package/work-orders/CHART-7.md +0 -175
  291. package/work-orders/DX-1.md +0 -169
  292. package/work-orders/DX-2.md +0 -188
  293. package/work-orders/DX-3.md +0 -195
  294. package/work-orders/I18N-1.md +0 -254
  295. package/work-orders/I18N-3.md +0 -207
  296. package/work-orders/MSG-3.md +0 -375
  297. package/work-orders/MSG-3b.md +0 -1002
  298. package/work-orders/MSG-3c.md +0 -378
  299. package/work-orders/MSG-3d.md +0 -268
  300. package/work-orders/MSG-3e.md +0 -164
  301. package/work-orders/MSG-3f.md +0 -391
  302. package/work-orders/MSG-6e.md +0 -308
  303. package/work-orders/MSG-6f.md +0 -214
  304. package/work-orders/MSG-6g.md +0 -244
  305. package/work-orders/MSG-6h.md +0 -238
  306. package/work-orders/MSG-6i.md +0 -271
  307. package/work-orders/MSG-6j.md +0 -117
  308. package/work-orders/NOTIF-12.md +0 -214
  309. package/work-orders/NOTIF-13.md +0 -142
  310. package/work-orders/NOTIF-14.md +0 -151
  311. package/work-orders/PRIM-1.md +0 -177
  312. package/work-orders/SHELL-1.md +0 -255
  313. package/work-orders/SHELL-2.md +0 -197
  314. package/work-orders/SHELL-3.md +0 -359
  315. package/work-orders/SHELL-4.md +0 -351
  316. package/work-orders/SHELL-5.md +0 -345
  317. package/work-orders/SHELL-6.md +0 -210
  318. package/work-orders/THEME-1.md +0 -587
  319. package/work-orders/THEME-10.md +0 -303
  320. package/work-orders/THEME-11.md +0 -208
  321. package/work-orders/THEME-2.md +0 -339
  322. package/work-orders/THEME-3.md +0 -210
  323. package/work-orders/THEME-4.md +0 -271
  324. package/work-orders/THEME-5.md +0 -341
  325. package/work-orders/THEME-6.md +0 -247
  326. package/work-orders/THEME-7.md +0 -82
  327. package/work-orders/THEME-8.md +0 -211
  328. package/work-orders/THEME-9.md +0 -194
  329. package/work-orders/UCM-AUTH-10.md +0 -490
  330. package/work-orders/UCM-AUTH-11.md +0 -185
  331. package/work-orders/UCM-AUTH-12.md +0 -98
  332. package/work-orders/UCM-AUTH-13.md +0 -47
  333. package/work-orders/UCM-AUTH-9.md +0 -207
  334. package/work-orders/UCM-CHART-10.md +0 -150
  335. package/work-orders/UCM-CHART-11.md +0 -132
  336. package/work-orders/UCM-CHART-12.md +0 -348
  337. package/work-orders/UCM-CHART-13.md +0 -122
  338. package/work-orders/UCM-CHART-14.md +0 -198
  339. package/work-orders/UCM-CHART-15.md +0 -187
  340. package/work-orders/UCM-CHART-16.md +0 -169
  341. package/work-orders/UCM-CHART-17.md +0 -195
  342. package/work-orders/UCM-CHART-18.md +0 -200
  343. package/work-orders/UCM-CHART-8.md +0 -147
  344. package/work-orders/UCM-CHART-9.md +0 -265
  345. package/work-orders/UCM-CHAT-1.md +0 -190
  346. package/work-orders/UCM-CHAT-2.md +0 -75
  347. package/work-orders/UCM-DEP-1.md +0 -63
  348. package/work-orders/UCM-I18N-4.md +0 -226
  349. package/work-orders/UCM-I18N-5.md +0 -211
  350. package/work-orders/UCM-MSG-20.md +0 -192
  351. package/work-orders/UCM-PRIM-2.md +0 -114
  352. package/work-orders/UCM-SHELL-7.md +0 -134
  353. package/work-orders/UCM-SHELL-8.md +0 -125
  354. package/work-orders/UCM-TEST-1.md +0 -304
  355. package/work-orders/UCM-THEME-13.md +0 -69
  356. package/work-orders/UCM-THEME-14.md +0 -312
  357. package/work-orders/UCM-THEME-15.md +0 -356
  358. package/work-orders/UCM-THEME-16.md +0 -80
  359. package/work-orders/UCM-THEME-17.md +0 -111
  360. package/work-orders/UCM-THEME-18.md +0 -184
  361. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  362. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  363. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  364. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  365. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  366. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  367. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,428 +0,0 @@
1
- # CHART-6 — Chart-chrome defaults in the three wrappers, plus the two generic fixes hoisted up
2
-
3
- **Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
4
- **Tier:** 2 (shared core — `ui-core-micha` is named in AGENTS.md's Tier-2 forcing list)
5
- **Review:** independent `reviewer` (Sonnet, full) **and** `ui_reviewer` — spawned concurrently, both mandatory before commit
6
- **Decision record:** `webapp-management/DESIGN_SYSTEM_PROGRAM.md` (DS-4), plus the operator decisions of 2026-08-10 recorded below
7
- **Version target:** `2.31.0`
8
- **Hard precondition:** **THEME-1 must have landed and published as `2.30.0` first** — see Preconditions
9
-
10
- ---
11
-
12
- ## A. Envelope
13
-
14
- ### Goal
15
-
16
- Close the chart-chrome default surface in ucm's three chart wrappers, resolve
17
- `TimeSeriesChart`'s double legend, and hoist the two generic fixes that live in a consuming app
18
- today up into the kit.
19
-
20
- Expected outcome: a chart rendered through the kit looks deliberate without the caller setting
21
- anything, and the four props that today decide whether it looks deliberate stop being the
22
- caller's problem.
23
-
24
- ### Why
25
-
26
- Both hram and fitness-monitor import the **same** thin wrappers. There is no app-local chart
27
- module to promote — the quality gap is **three unset props plus one library default**. The
28
- wrappers are roughly 18 lines of logic each: they enforce axis labels, apply a `hideLegend`
29
- heuristic, force axis-trigger tooltips, and supply a palette fallback. Tick font, grid, margins
30
- and marker styling are simply absent, so MUI X-Charts' own visual language shows through
31
- untouched.
32
-
33
- ### Measured evidence (2026-08-08/09, verified)
34
-
35
- - **Hand discipline fails even in the exemplar.** hram sets `tickLabelStyle.fontSize` at only
36
- **4 of 9** wrapper call sites — absent in `ExpertTimelinePanel`, `ReferralMetricsPanel`,
37
- `ResultsTimelinePanel`, `TotalMetricsPanel` and `GenericAnalysisPlot`'s top chart. This is the
38
- argument for defaults at the chokepoint rather than a convention.
39
- - **The hollow-marker default is a library value, verified in source:**
40
- `@mui/x-charts/LineChart/MarkElement.js:27` sets `fill: theme.palette.background.paper` — a
41
- white-filled marker with a coloured stroke. hram avoids it by disabling markers globally;
42
- fitness-monitor turns them on and inherits it.
43
- - **`TimeSeriesChart` renders a double legend** whenever ≥2 series are visible: its toolbar toggle
44
- row names and toggles the series, and MUI draws its own legend underneath.
45
- - **The label-collapse workaround has two independent consumers** — fitness-monitor's
46
- `utils/chartLabels.js` (36 lines) and jg-ferien's `ActivitySection.jsx:10-16`, which documents
47
- the identical upstream issue. The promotion test is met.
48
- - **`TeachingRunDetailPanel` (hram) bypasses the wrapper entirely** with a direct
49
- `@mui/x-charts` import — noted, not fixed here.
50
- - **X-Charts `8.28.2` API limits, both verified in the installed types:** the legend's `position`
51
- is a 3×3 grid (`vertical: top|middle|bottom` × `horizontal: start|center|end`) and participates
52
- in layout — it reserves space rather than overlaying the plot. `skipAnimation` is a boolean per
53
- chart with **no separate enter/update control**.
54
-
55
- ### Scope
56
-
57
- #### A. Prop defaults in all three wrappers
58
-
59
- Applies to `LineChart`, `BarChart` **and `TimeSeriesChart`** — the third was overlooked when this
60
- strand was first written and is the kit's most mature preset.
61
-
62
- | Default | Value | Replaces |
63
- |---|---|---|
64
- | `tickLabelStyle.fontSize` | the baseline's tick size | MUI's ~12px, unstyled |
65
- | `showMark` | `false` | MUI's `true` |
66
- | marker style, when a caller opts markers back in | **filled** | MUI's hollow `background.paper` fill |
67
- | `grid` | `{ horizontal: true }` | MUI's default of no grid at all |
68
- | bottom margin | increased automatically when tick labels are rotated | hand-tuned per call site, or forgotten |
69
- | `legendPosition` | **new prop** over MUI's nine positions; default **bottom-start**, filled marks, aligned to `ChartFrame`'s `p: 2` | MUI's centered-top with dash marks |
70
-
71
- **Every one of these is a default, not an override.** A prop set by the caller always wins — hram's
72
- four tuned `tickLabelStyle` call sites must render exactly as they do today.
73
-
74
- #### B. `TimeSeriesChart`'s double legend
75
-
76
- Where the toolbar toggle row is present, **MUI's legend is switched off and the toolbar becomes
77
- the legend** (filled colour dots on the toggles). A row that both names and toggles the series is
78
- the more capable of the two, and two elements saying the same thing is one too many.
79
-
80
- The toggles must keep their accessible names — this must not become a row of unlabelled controls
81
- for keyboard or screen-reader users.
82
-
83
- #### C. Motion
84
-
85
- - **Charts animate on entry** (operator, 2026-08-10), at the baseline's `motion.chart` duration.
86
- - **Charts that poll or re-render on a timer get `skipAnimation`** — named concretely: cockpit's
87
- status board and hram's `CampaignMonitorPanel`. There the animation replays on every refresh and
88
- the value never comes to rest.
89
- - Because `skipAnimation` is all-or-nothing in 8.28.2, those two also lose their entry animation.
90
- **A library limit, documented as such — not a design choice.**
91
-
92
- #### D. The two hoists from fitness-monitor
93
-
94
- - **`chartLabels.js`** — the documented X-Charts label-collapse workaround, 36 lines. Two
95
- independent consumers already, so this is a promotion and not a bet.
96
- - **`yearTickInterval`** — hoisted **on its own merits**, not by association: it currently lives
97
- page-locally in fitness-monitor's `BodyHistoryPage` and is **not** part of `chartLabels.js`. The
98
- duplicated-year-tick defect it fixes hits any dense time axis, so it belongs to every
99
- `TimeSeriesChart` consumer. Ships as **its own export**, not mixed into `chartLabels.js`.
100
-
101
- Both apps keep working unchanged. **Removing their local copies is not part of this WO** — that
102
- happens in each app's own adoption WO, so this one stays reviewable in a single repo.
103
-
104
- #### E. Version
105
-
106
- `2.31.0` — minor: new props and new exports, nothing removed.
107
-
108
- ### Non-goals / do not touch
109
-
110
- - **The legend auto-placement heuristic.** The operator's idea — detect whether the top-right or
111
- bottom-right corner of the plot is empty and place the legend there, otherwise below — is good,
112
- but X-Charts' built-in legend reserves layout space instead of overlaying, so a true in-plot
113
- legend needs a custom overlay. **Own strand, once someone has verified that path.** Deliberately
114
- kept out of a Tier-2 shared-core WO in a repo with no staging net, so this one stays fully
115
- verifiable.
116
- - **The theme factory** — THEME-1.
117
- - **`useNeutralChartPalette`'s ramp transition** — owned by THEME-1 (decision 22). This WO must not
118
- touch `charts/palette.js`.
119
- - **The six hand-drawn hram plots** — DS-7/8/9.
120
- - **`TeachingRunDetailPanel`'s wrapper bypass** — its own small WO in hram.
121
- - **Removing the hoisted helpers' local copies** in fitness-monitor and jg-ferien.
122
- - **Per-app adoption** of any of this.
123
- - **No behaviour, permission or data-contract change.**
124
-
125
- ### Replaces / removes
126
-
127
- 1. MUI's **hollow marker** as the effective marker whenever a caller opts markers in.
128
- 2. MUI's **centered-top legend with dash marks** as the effective default.
129
- 3. **`TimeSeriesChart`'s second legend** — the MUI one, where the toolbar row exists.
130
- 4. Nothing is removed from the public API. No export disappears, no prop is dropped.
131
-
132
- ### Deliberately keeps
133
-
134
- - **The `hideLegend={series.length <= 1}` heuristic.** A one-series legend is noise, and giving the
135
- legend a good position does not change that.
136
- - **The required `xAxisLabel` / `yAxisLabel` contract** — the wrappers throw without them, and that
137
- is already generic and correct.
138
- - **The `palette=` convention** and the wrapper's palette fallback.
139
- - **`ChartFrame`'s `p: 2` padding and its foot row**, byte-for-byte — 16 panels depend on them.
140
- - **Every caller's explicit props.** A set prop beats a default; hram's four tuned call sites must
141
- be visually unchanged.
142
-
143
- ### Risks
144
-
145
- - **Adding a default is a behaviour change for every call site that did not set the prop**, and the
146
- effect is deliberately uneven: hram's four tuned `tickLabelStyle` sites stay identical, the other
147
- five change. That is the intended fix, but it means the rendered check must look at more than one
148
- chart.
149
- - **No staging net.** A push to `main` touching `src/**` publishes to npm at once; the independent
150
- review is the only gate and is not back-fillable.
151
- - **Ordering against THEME-1 is hard, not preferential.** Both WOs touch `src/index.js` and
152
- `src/components/charts/`, and decision 23 fixes the release order. Two implementers in this repo
153
- at once would race the version bump or ship half of this WO inside `2.30.0`.
154
- - **A chart-preset bump deserves the same treatment as a theme bump.** Decision 11's argument
155
- applies unchanged: the consumer's next pin bump is a visual verification event, not a dependency
156
- line.
157
- - **`skipAnimation` is all-or-nothing**, so the two polling charts lose entry animation too.
158
-
159
- ### Required tests to WRITE
160
-
161
- Narrow per AGENTS.md → "Test scope". Written as part of implementation; **run only by the
162
- Orchestrator**.
163
-
164
- **`tests/chartDefaults.test.js`** (new, parametrised across `LineChart` / `BarChart` /
165
- `TimeSeriesChart` where applicable)
166
-
167
- 1. A minimal call receives the tick font size, `grid: { horizontal: true }` and `showMark: false`.
168
- 2. A caller-set prop **beats** the default — asserted separately for each of tick font, grid,
169
- `showMark` and `legendPosition`.
170
- 3. Rotated tick labels increase the bottom margin; unrotated labels do not.
171
- 4. When a caller opts markers back in, the marker renders **filled** — not MUI's
172
- `background.paper` hollow default.
173
- 5. `legendPosition` defaults to bottom-start, and a caller-set position wins.
174
-
175
- **`tests/timeSeriesLegend.test.js`** (new)
176
-
177
- 6. With the toolbar row present and ≥2 series, MUI's legend is **absent** — assert the absence
178
- explicitly, this is a removal.
179
- 7. The toolbar toggles keep an accessible name.
180
- 8. With a single series, `hideLegend` still applies.
181
-
182
- **`tests/chartLabels.test.js`** (new, ported with the hoist)
183
-
184
- 9. The label-collapse workaround behaves as it does in fitness-monitor today — port its existing
185
- cases rather than inventing new ones.
186
- 10. `yearTickInterval` produces one tick per year across a dense multi-year range. **Prove
187
- non-vacuity** by removing it and confirming duplicate year labels reappear — this is the
188
- defect that started the whole investigation.
189
-
190
- Plus `tsc -p tsconfig.build.json --noEmit` clean.
191
-
192
- **No full-suite run.** The affected-areas set is the three new files plus the existing
193
- `tests/chartsPalette.test.js` if the hoist touches it.
194
-
195
- ### Verification
196
-
197
- - The **harness page** from THEME-1 gains chart specimens, so the defaults get a rendered
198
- acceptance rather than only assertions.
199
- - The Orchestrator runs the **rendered two-width side-by-side** before commit (DS-1's hard gate),
200
- and names the two screenshots in the register Notiz.
201
- - Because the effect is uneven, the rendered check must cover **at least one chart that set the
202
- props and one that did not** — otherwise it proves nothing about the change.
203
-
204
- ### Preconditions
205
-
206
- - **THEME-1 landed and published as `2.30.0`.** Not before: both WOs touch `src/index.js` and
207
- `src/components/charts/`, this repo publishes on push, and decision 23 fixes the order.
208
- - The baseline supplies `motion.chart` and the tick/grid token values this WO applies.
209
-
210
- ### Parity guardrail
211
-
212
- Visual/UX only. **No behaviour, permission or data-contract change.** The hard condition: a caller
213
- that already sets a prop sees **no change at all** — the defaults fill absence, they do not
214
- override intent.
215
-
216
- ### Operator decisions binding this WO
217
-
218
- - **2026-08-10:** charts animate on entry; polling charts get `skipAnimation` (light movement is
219
- wanted, and AAA is explicitly not the bar).
220
- - **2026-08-10:** the toolbar row becomes the legend in `TimeSeriesChart`; MUI's legend goes.
221
- - **2026-08-10:** `yearTickInterval` is hoisted, with its own justification and as its own export.
222
- - **2026-08-10:** `legendPosition` ships as a prop with a fixed default; the auto-placement
223
- heuristic becomes its own strand because the in-plot overlay path is unverified.
224
- - **Decision 23:** `2.31.0`, after THEME-1's `2.30.0`.
225
-
226
- ---
227
-
228
- ## B. Implementation map
229
-
230
- *Filled by the Orchestrator on `git pull` — see AGENTS.md → "Work Order".*
231
-
232
- ### Execution directive (read this first)
233
-
234
- > **If you are the implementer reading this work order as your own specification: this section is
235
- > NOT addressed to you.** It tells the Orchestrator how to invoke you. **You ARE that invocation —
236
- > do NOT shell out to `codex exec`.**
237
- >
238
- > Implement through `codex exec` in the background — invoked directly via Bash (never the
239
- > `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
240
- > `--dangerously-bypass-approvals-and-sandbox`. **Pass the WO via stdin, not as a positional
241
- > argument** — `cat work-orders/CHART-6.md | codex exec --skip-git-repo-check
242
- > --dangerously-bypass-approvals-and-sandbox -` — a positional arg hit Windows' command-line length
243
- > limit on THEME-1 ("Argument list too long" from the npm shim); stdin is the proven working
244
- > invocation for a WO this size on this platform. (Fallback to direct Claude implementation only on
245
- > Codex quota/rate-limit/non-zero exit.)
246
-
247
- ### Context package
248
-
249
- **Precondition verified 2026-08-10:** THEME-1 landed (`b329b39`, `96992cf`, `35f70b2`) and is live on
250
- npm as `2.30.0` (`npm view @micha.bigler/ui-core-micha version` initially showed the registry cache
251
- still at `2.29.2` right after push — the `Publish ui-core-micha to npm` GitHub Action had completed
252
- successfully in ~1m42s; this repo's `package.json` already reads `2.30.0`, which is the authoritative
253
- signal, not the possibly-cached registry response).
254
-
255
- **Named files to change:**
256
-
257
- - `src/components/charts/BarChart.jsx`, `src/components/charts/LineChart.jsx` — near-identical
258
- wrappers (currently 45 lines each, both shown in full above under "Named files"). Add: (1) default
259
- `tickLabelStyle` (merged into each axis entry, not replacing a caller's own `xAxis`/`yAxis` array
260
- entries — same "caller wins" pattern `labelledAxis` already uses for `label`); (2) default
261
- `showMark: false` on the wrapper's own `chartProps`-level default (only meaningful for `LineChart`
262
- — `BarChart` has no marks; skip it there or make it a shared no-op, your call, but do not add a
263
- prop MUI's `BarChart` doesn't accept); (3) default `grid={{ horizontal: true }}`; (4) an explicit
264
- `hideLegend` prop that DEFAULTS to today's `series.length <= 1` heuristic but is OVERRIDABLE by the
265
- caller — **this is a real gap, not cosmetic**: today `hideLegend={series.length <= 1}` is hardcoded
266
- after the `{...chartProps}` spread, so a caller-passed `hideLegend` in `chartProps` is silently
267
- discarded (JSX prop order: later wins, and the hardcoded one comes last). `TimeSeriesChart` (below)
268
- needs to force `hideLegend={true}` when it draws its own toolbar-as-legend, so this plumbing gap
269
- must close first; (5) a new `legendPosition` prop, default `{ vertical: 'bottom', horizontal:
270
- 'start' }` (MUI's `Position` type — verified in
271
- `node_modules/@mui/x-charts/models/position.d.ts`: `{ vertical?: 'top'|'middle'|'bottom',
272
- horizontal?: 'start'|'center'|'end' }`), passed as `slotProps={{ legend: { position:
273
- legendPosition } }}` merged with the existing `tooltip: { trigger: 'axis' }` slotProp (don't
274
- clobber one with the other); (6) automatic bottom-margin increase when tick labels are rotated —
275
- MUI X-Charts reads rotation from `xAxis[i].tickLabelStyle.angle` (or similar; verify the exact
276
- field in the installed types before relying on it) — when a caller's `xAxis` sets a non-zero
277
- angle, add `margin.bottom` (a `ChartContainer`-level prop, check exact prop name/shape in
278
- `node_modules/.pnpm/@mui+x-charts@8.29.2_.../node_modules/@mui/x-charts/ChartContainer` types)
279
- large enough for the rotated label height — don't hardcode a single magic number without deriving
280
- it from the tick font size/angle, and don't touch margin at all when no rotation is set (default
281
- MUI margin must survive unchanged, per the parity guardrail).
282
- **On-chart marker fill (LineChart only):** verified in
283
- `node_modules/@mui/x-charts/LineChart/MarkElement.js:26-31` — the hollow marker is `styled('path',
284
- {name:'MuiMarkElement', slot:'Root'})(({theme}) => ({fill: theme.palette.background.paper, ...}))`,
285
- a genuine MUI-theme-connected styled component (same mechanism as `MuiButton`/`MuiTableCell` etc.
286
- already overridden in THEME-1's `BASELINE_STATIC.components`). The cleanest fix, consistent with
287
- every other component default in this kit, is a `MuiMarkElement: { styleOverrides: { root: {
288
- fill: 'currentColor' } } }` entry (paired with `stroke: color` already set per-instance by
289
- MarkElement itself, `color` inherited via the mark's own `color` CSS from its parent — verify
290
- `currentColor` actually resolves to the series colour in the rendered DOM, since `MarkElementPath`
291
- doesn't explicitly set a `color` CSS property alongside `stroke`; if `currentColor` doesn't
292
- resolve, use `fill: 'inherit'` or accept a small amount of extra plumbing) added to
293
- **`src/theme/tokens.js`'s `BASELINE_STATIC.components`** (a THEME-1 file, but this is a
294
- theme-component-override, not a `charts/palette.js` change — the WO's non-goal only excludes
295
- `charts/palette.js`, not `src/theme/`). If that turns out infeasible, fall back to a per-wrapper
296
- `slotProps`/`sx` override targeting `.MuiMarkElement-root` and say so explicitly in the PR — do not
297
- silently ship the hollow default.
298
- **Legend swatch shape:** verified in `LineChart/seriesConfig/seriesProcessor.js:97` — LineChart
299
- series default to `labelMarkType: 'line'` (a short dash, matching the WO's "dash marks" default to
300
- replace); `BarChart/seriesConfig/bar/seriesProcessor.js:94` already defaults to `labelMarkType:
301
- 'square'` (already filled — nothing to change there). Fix: in `LineChart.jsx`'s series mapping,
302
- default each series entry's `labelMarkType` to `'square'` unless the caller's series object already
303
- sets one (`{ labelMarkType: 'square', ...series }` — caller key after the default wins the object
304
- spread, matching the "default, not override" invariant).
305
- - `src/components/charts/TimeSeriesChart.jsx` — (1) pass `hideLegend` explicitly to its internal
306
- `BarChart` call (currently absent, so `BarChart`'s own heuristic applies): `hideLegend` should be
307
- `true` whenever the toolbar's series-toggle row renders (`seriesConfig.length > 0`, same condition
308
- already used at line 214 to render `FormGroup`) — that removes MUI's own legend while the toolbar
309
- toggles take over as the visible legend, satisfying Scope B. The toggles already carry an
310
- accessible name via each `FormControlLabel`'s `label` prop (line 217-231) — verify this still holds
311
- after your change (test 7), no new work expected there. (2) Pass `motion.chart`-based
312
- animation/`skipAnimation` through unchanged — `TimeSeriesChart` doesn't currently accept or need a
313
- `skipAnimation` prop itself; a caller wanting a polling chart to skip animation calls the wrapper
314
- with `skipAnimation` in `chartProps`, which already passes through `BarChart`'s `{...chartProps}`
315
- spread untouched — **verify this passthrough still works after your `hideLegend`/`legendPosition`
316
- changes** (i.e. don't accidentally consume/strip `skipAnimation` while destructuring), there is
317
- likely nothing to build here beyond that verification.
318
- - `src/theme/tokens.js` — add the `MuiMarkElement` override described above (if that's the mechanism
319
- you land on), and a `chart` typography-adjacent tick-size reference if one doesn't already exist
320
- cleanly reachable (`BASELINE_STATIC.typography.caption` is `12px/400/1.4` — the natural fit for
321
- `tickLabelStyle.fontSize`; reference it directly via `theme.typography.caption.fontSize` inside the
322
- wrappers rather than inventing a new token, unless a dedicated token reads better — your call, but
323
- don't hardcode a bare `'12px'` string in the wrapper divorced from the theme).
324
- - **New: `src/components/charts/chartLabels.js`** — port `formatShortTime`/`formatShortDate`/
325
- `formatShortMonth`/`formatShortYear` from
326
- `fitness-monitor/frontend/src/utils/chartLabels.js` (read that file directly — 37 lines, shown in
327
- full above under "Named files"; also check `fitness-monitor/frontend/src/utils/chartLabels.test.js`
328
- for the existing test cases to port per test 9, "port its existing cases rather than inventing new
329
- ones"). This is a straight port, not a rewrite — keep the exact locale-fallback behaviour and the
330
- `hour12: false` comment/rationale intact (it documents a real upstream MUI bug, mui-x#18768).
331
- - **New: `src/components/charts/yearTickInterval.js`** (own export per the WO, not merged into
332
- `chartLabels.js`) — generalise
333
- `fitness-monitor/frontend/src/pages/BodyHistoryPage.jsx:39-43`'s `yearTickInterval(range, dates)`.
334
- That version is app-specific (gated on a literal `range !== "All"` string fitness-monitor owns) —
335
- the ucm export should NOT take a `range` string at all (this repo's own `TimeSeriesChart` uses
336
- different range keys, `'1y'` not `'All'`, and other callers may have yet another vocabulary). Ship
337
- it as `yearTickInterval(dates)`: always computes one Date per calendar year present in `dates` (the
338
- same `[...new Set(dates.map(d => d.getFullYear()))].sort().map(y => new Date(y, 0, 1))` logic,
339
- minus the range gate) — the CALLER decides when a dense-enough multi-year range warrants using it
340
- (as `xAxis[0].tickInterval`), matching the original's actual computation, not its app-specific gate.
341
- - `src/theme/index.js`, `src/index.js` — export `chartLabels`' functions and `yearTickInterval` (new
342
- entries near the existing `## 6. Charts` section in `src/index.js`, alongside `ChartFrame`/
343
- `BarChart`/`LineChart`/`TimeSeriesChart`/palette exports).
344
- - `package.json` — version `2.30.0` → `2.31.0` (minor).
345
- - **New: `tests/chartDefaults.test.js`, `tests/timeSeriesLegend.test.js`, `tests/chartLabels.test.js`**
346
- — per Required tests below. Follow the existing mock convention in `tests/BarChart.test.jsx`
347
- (shown in full above): `vi.mock('@mui/x-charts/BarChart', () => ({ BarChart: chartSpy }))` with a
348
- hoisted spy capturing props, assert on `chartSpy.mock.calls[...][0]` rather than deep-rendering the
349
- real chart. Mirror the same pattern for `@mui/x-charts/LineChart` where `LineChart.jsx` is under
350
- test.
351
- - `dev/entries.jsx` — the WO's Verification section requires the harness to gain "chart specimens"
352
- and the rendered check must cover **at least one chart that set the props and one that did not**.
353
- Add a small addition to the existing THEME-1 `ThemeBaselineEntry` (or a sibling entry) showing two
354
- `BarChart`/`LineChart` instances side by side: one with zero extra props (shows the new defaults —
355
- grid, filled marks, bottom-start legend) and one with an explicit caller override on at least
356
- `tickLabelStyle`/`legendPosition` (proves the override still wins, visually).
357
-
358
- ### Do-not-touch / invariants
359
-
360
- - **`src/components/charts/palette.js`** — untouched, THEME-1 owns the ramp transition.
361
- - **`ChartFrame`'s `p: 2` padding and its foot row** — untouched, 16 panels depend on them.
362
- - **hram's four tuned `tickLabelStyle` call sites** (not in this repo — nothing to verify directly
363
- here beyond making sure an explicit caller `tickLabelStyle` always wins the merge, which the new
364
- tests must prove per required test 2).
365
- - **No behaviour, permission, or data-contract change.**
366
- - **Removing fitness-monitor's/jg-ferien's local copies** of the hoisted helpers — explicitly not
367
- this WO; both keep working unchanged, on their own exact-pin versions.
368
- - **The legend auto-placement heuristic** — out of scope, `legendPosition` ships as a plain prop with
369
- a fixed default, not an auto-detecting overlay.
370
-
371
- ### Pitfalls (verified against landed code and installed `node_modules` 2026-08-10)
372
-
373
- - **The WO's Scope A table says X-Charts `8.28.2`; the actually installed version in this repo is
374
- `8.29.2`** (`node_modules/.pnpm/@mui+x-charts@8.29.2...`). Verify every API claim above against the
375
- INSTALLED source (`node_modules/.pnpm/@mui+x-charts@8.29.2.../node_modules/@mui/x-charts/`), not
376
- against the WO's prose or MUI's public docs for a different version.
377
- - `hideLegend`'s current hardcoded placement in both `BarChart.jsx` and `LineChart.jsx` (after the
378
- `{...chartProps}` spread) is the same class of bug CHART-1's R2/R3-style findings have caught
379
- before in this kit — don't just add a new prop next to it without checking whether other
380
- post-spread hardcoded props (`colors`, `slotProps`) have the same caller-cannot-override issue; the
381
- WO only asks you to fix `hideLegend` and add `legendPosition`, but note anything else you find
382
- rather than silently leaving it.
383
- - `MarkElementPath`'s `fill` comes from `theme.palette.background.paper` via `styled()` — this only
384
- resolves correctly if the chart is actually rendered under a `ThemeProvider` carrying
385
- `createAppTheme`'s output (or any MUI theme with the override). A consumer NOT using
386
- `createAppTheme` yet (all 14 today) still gets MUI's own theme with no `MuiMarkElement` override —
387
- confirm this is an acceptable, expected "you get it once you adopt THEME-1 + this bump" outcome
388
- (it is, per the WO's own "next pin bump is a visual verification event" framing), not a regression
389
- to chase further.
390
- - `src/index.js` already has a duplicate `// --- 9. ... ---` header comment (pre-existing, noted in
391
- THEME-1's WO too) — don't compound it.
392
-
393
- ### Target repo working directory (absolute)
394
-
395
- `C:\Users\biglmi\Documents\webapps\ui-core-micha`
396
-
397
- ### Required tests to WRITE (Codex writes them; the Orchestrator runs them)
398
-
399
- Exactly the 10 tests plus `tsc` check enumerated in Envelope § "Required tests to WRITE" above —
400
- `tests/chartDefaults.test.js` (5 tests, parametrised across `LineChart`/`BarChart`/`TimeSeriesChart`
401
- where applicable), `tests/timeSeriesLegend.test.js` (3 tests), `tests/chartLabels.test.js` (2 tests,
402
- test 9 ported from fitness-monitor's existing cases, test 10 proven non-vacuous by temporarily
403
- removing `yearTickInterval`'s effect and confirming duplicate year labels reappear, then restoring
404
- it), plus `tsc -p tsconfig.build.json --noEmit` clean. Do not add more, do not run the full suite —
405
- the affected-areas set additionally includes `tests/chartsPalette.test.js` ONLY if the hoist
406
- incidentally touches it (it shouldn't, since `charts/palette.js` is explicitly untouched).
407
-
408
- ### Preamble (append verbatim)
409
-
410
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
411
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
412
- > app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
413
- > unless the spec says so; do not update `MEMORY.md`. Do NOT `git add`/`commit`/`push` — leave every
414
- > change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
415
- > the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
416
- > and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
417
- > The orchestrator re-runs the authoritative set + does the independent review after you finish —
418
- > those are the gate; your own run does not count as the gate.
419
- >
420
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
421
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
422
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
423
- > `RESULT: DONE|BLOCKED <reason>`.
424
-
425
- ### Mini-handover
426
-
427
- Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`. WO:
428
- `work-orders/CHART-6.md`. Follow `orchestrate-codex`.
@@ -1,175 +0,0 @@
1
- # CHART-7 — `ChartFrame` gains a `titleVariant` prop
2
-
3
- **Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
4
- **Tier:** 2 (shared core)
5
- **Review:** independent `reviewer` **and** `ui_reviewer` — spawned concurrently, both mandatory before commit
6
- **Version target:** `2.32.0` — minor: a new public prop is additive API under semver, consistent with how `SHELL-2` classified `extraTabs` gaining a field
7
- **Precondition of:** `fitness-monitor`'s `FM-12` (DS-10)
8
-
9
- Short-form WO: one prop, one default, no design question.
10
-
11
- ---
12
-
13
- ## A. Envelope
14
-
15
- ### Goal
16
-
17
- `ChartFrame` hard-codes its title as `<Typography variant="h6">` (`src/components/charts/ChartFrame.jsx:74`)
18
- and exposes no way to change it. Add a `titleVariant` prop, defaulting to `'h6'` so nothing changes for
19
- any existing caller.
20
-
21
- ### Why this is a kit gap and not one app's problem
22
-
23
- A card title and a **panel-grid** title are different typographic jobs. In a dense grid the titles must
24
- recede so they do not compete with the one chart that matters; at `h6` they do not. Concretely:
25
- fitness-monitor renders six body-composition panels next to one hero chart, and its accepted prototype
26
- specifies `13px/600` for those six against `15px/600` for the hero
27
- (`fitness-monitor/work-orders/assets/FM-8-redesign.html:237` vs `:184`). Today all seven render at the
28
- same `h6`, and **six oversized titles beside a hero chart was one of the original "reads heavier and
29
- older" findings** that started this programme.
30
-
31
- The app cannot reach it: there is no prop, and `ChartFrame`'s title is not exposed through `slotProps`
32
- either. Any app with a dense panel grid hits the same wall — hram's results tabs are the obvious next
33
- one — so this belongs in the kit rather than being worked around per app.
34
-
35
- ### Scope
36
-
37
- - `ChartFrame` accepts `titleVariant`, forwarded to the title `Typography`. **Default `'h6'`.**
38
- - Keep it minimal: **one prop, not a `slotProps.title` system.** There is one known need; a general slot
39
- mechanism for one consumer is the speculative generality this estate's promotion discipline rejects.
40
- If a second, different need appears, that is when the shape gets revisited.
41
-
42
- ### Non-goals / do not touch
43
-
44
- - The subtitle, toolbar, controls, loading/error/empty slots and the export footer — untouched.
45
- - `ChartFrame`'s `p: 2` padding and its foot row: **byte-for-byte unchanged.** 16 panels depend on them.
46
- - The baseline's `h6` value (16px/600). This WO changes *which* variant a caller may pick, not what the
47
- variants are.
48
- - The chart wrappers. No `LineChart`/`BarChart`/`TimeSeriesChart` change.
49
- - No behaviour, permission or data-contract change.
50
-
51
- ### Risks
52
-
53
- - **`ChartFrame` is the estate's most-used chart primitive** — five of hram's six hand-drawn panels use
54
- it, plus every wrapper chart. The default must remain `'h6'`; a changed default would silently restyle
55
- every title in the estate on the next pin bump.
56
- - **No staging net.** A push to `main` touching `src/**` publishes to npm at once; the independent review
57
- is the only gate and is not back-fillable.
58
-
59
- ### Required tests to WRITE
60
-
61
- Extend the existing `ChartFrame` spec rather than adding a file.
62
-
63
- 1. With no `titleVariant`, the title renders as `h6` — **prove non-vacuity** by changing the default and
64
- confirming this fails. This is the regression guard for all 16 existing panels.
65
- 2. `titleVariant="subtitle2"` renders the title at that variant.
66
- 3. The subtitle, toolbar and footer render unchanged in both cases.
67
-
68
- Plus `tsc -p tsconfig.build.json --noEmit` clean.
69
-
70
- **No full-suite run.** Affected-areas set is the `ChartFrame` spec.
71
-
72
- ### Verification
73
-
74
- The rendered two-width side-by-side per DS-1, showing a `ChartFrame` at the default and one with an
75
- overridden variant side by side — so the "default unchanged" claim is visible and not only asserted.
76
-
77
- ### Preconditions
78
-
79
- None. `THEME-2` (`2.31.1`) is the current published version.
80
-
81
- ### Parity guardrail
82
-
83
- Purely additive. Every existing caller must render identically — that is what test 1 guards.
84
-
85
- ---
86
-
87
- ## B. Implementation map
88
-
89
- *Filled by the Orchestrator on `git pull` — see AGENTS.md → "Work Order".*
90
-
91
- ### Execution directive (read this first)
92
-
93
- > **If you are the implementer reading this work order as your own specification: this section is
94
- > NOT addressed to you.** It tells the Orchestrator how to invoke you. **You ARE that invocation —
95
- > do NOT shell out to `codex exec`.**
96
- >
97
- > Implement through `codex exec` in the background — invoked directly via Bash (never the
98
- > `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
99
- > `--dangerously-bypass-approvals-and-sandbox`. **Pass the WO via stdin, not as a positional
100
- > argument** — `cat work-orders/CHART-7.md | codex exec --skip-git-repo-check
101
- > --dangerously-bypass-approvals-and-sandbox -` (a positional arg hits Windows' command-line length
102
- > limit — proven repeatedly in this repo). Fallback to direct Claude implementation only on Codex
103
- > quota/rate-limit/non-zero exit.
104
-
105
- ### Context package
106
-
107
- Verified 2026-08-10, current state: `src/components/charts/ChartFrame.jsx:17-35` (prop destructure)
108
- and `:74` (the hardcoded title):
109
- ```jsx
110
- export function ChartFrame({
111
- title,
112
- subtitle,
113
- toolbar,
114
- ...
115
- variant = 'outlined',
116
- sx,
117
- }) {
118
- ...
119
- <Typography id={titleId} variant="h6">{title}</Typography>
120
- ```
121
-
122
- **Named file to change:** add `titleVariant = 'h6'` to the destructured props (alongside `variant =
123
- 'outlined'`, same style) and change line 74 to `<Typography id={titleId} variant={titleVariant}>
124
- {title}</Typography>`. That is the entire implementation — no other file needs to change (the WO is
125
- explicit: no `slotProps` system, no wrapper changes).
126
-
127
- **Test file:** `tests/ChartFrame.test.jsx` — extend, don't create a new file. Read the file in full
128
- first (it already has an i18n/theme harness at the top, shown above) and follow its existing render
129
- helper/assertion style. Add the 3 required tests: (1) default renders `variant="h6"` on the title
130
- `Typography` — assert via the rendered DOM (e.g. the title element's tag is `<h6>` or its MUI class
131
- contains `MuiTypography-h6`), proven non-vacuous by temporarily changing the default to something
132
- else and confirming the test fails, then restoring it; (2) `titleVariant="subtitle2"` renders the
133
- title at that variant; (3) subtitle/toolbar/footer render unchanged in both the default and
134
- overridden case (a plain equality/snapshot-style check between the two renders' non-title markup, or
135
- explicit assertions that subtitle/toolbar/footer content and structure are present and identical —
136
- your call on the exact mechanism, the WO doesn't prescribe one).
137
-
138
- ### Do-not-touch / invariants
139
-
140
- - `ChartFrame`'s `p: 2` padding and its foot row — byte-for-byte unchanged.
141
- - The baseline's `h6` value itself (16px/600, from THEME-1) — untouched; this WO changes which
142
- variant a caller may pick, not what the variants are.
143
- - No `LineChart`/`BarChart`/`TimeSeriesChart` change.
144
- - Subtitle, toolbar, controls, loading/error/empty slots, export footer — untouched behaviour.
145
-
146
- ### Target repo working directory (absolute)
147
-
148
- `C:\Users\biglmi\Documents\webapps\ui-core-micha`
149
-
150
- ### Required tests to WRITE (Codex writes them; the Orchestrator runs them)
151
-
152
- Exactly the 3 tests above in `tests/ChartFrame.test.jsx`, plus `tsc -p tsconfig.build.json --noEmit`
153
- clean. No full-suite run — affected-areas set is the `ChartFrame` spec alone.
154
-
155
- ### Preamble (append verbatim)
156
-
157
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
158
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
159
- > app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
160
- > unless the spec says so; do not update `MEMORY.md`. Do NOT `git add`/`commit`/`push` — leave every
161
- > change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
162
- > the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
163
- > and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
164
- > The orchestrator re-runs the authoritative set + does the independent review after you finish —
165
- > those are the gate; your own run does not count as the gate.
166
- >
167
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
168
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
169
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
170
- > `RESULT: DONE|BLOCKED <reason>`.
171
-
172
- ### Mini-handover
173
-
174
- Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`. WO:
175
- `work-orders/CHART-7.md`. Follow `orchestrate-codex`.