@12-apps/ui 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -0,0 +1,121 @@
1
+ import { Box, Paper, Typography, useTheme } from '@mui/material';
2
+ import React from 'react';
3
+ import { Legend, ResponsiveContainer, Tooltip } from 'recharts';
4
+
5
+ /**
6
+ * Raw chart composables (Squire's ChartConfig pattern, MUI-themed): a
7
+ * responsive container plus themed tooltip/legend content renderers. The
8
+ * prop-driven `Chart` uses these internally; consumers building bespoke
9
+ * Recharts compositions can reuse them directly.
10
+ */
11
+
12
+ /** Recharts' Tooltip/Legend re-exported so bespoke compositions can pair them
13
+ * with the themed content renderers below. */
14
+ export const ChartTooltip = Tooltip;
15
+ export const ChartLegend = Legend;
16
+
17
+ export interface ChartContainerProps {
18
+ height: number;
19
+ width?: number | string;
20
+ responsive?: boolean;
21
+ children: React.ReactElement;
22
+ 'data-testid'?: string;
23
+ }
24
+
25
+ /** Responsive wrapper for a Recharts chart element. */
26
+ export const ChartContainer: React.FC<ChartContainerProps> = ({
27
+ height,
28
+ width = '100%',
29
+ responsive = true,
30
+ children,
31
+ 'data-testid': dataTestId,
32
+ }) => {
33
+ if (!responsive) {
34
+ return (
35
+ <Box sx={{ width, height }} data-testid={dataTestId}>
36
+ {children}
37
+ </Box>
38
+ );
39
+ }
40
+ return (
41
+ <ResponsiveContainer width="100%" height={height} data-testid={dataTestId}>
42
+ {children}
43
+ </ResponsiveContainer>
44
+ );
45
+ };
46
+
47
+ interface TooltipEntry {
48
+ name?: string | number;
49
+ value?: string | number;
50
+ color?: string;
51
+ }
52
+
53
+ export interface ChartTooltipContentProps {
54
+ active?: boolean;
55
+ label?: string | number;
56
+ payload?: TooltipEntry[];
57
+ /** Formats numeric values (e.g. centavos → BRL). */
58
+ valueFormatter?: (value: number) => string;
59
+ }
60
+
61
+ /** Theme-aware tooltip content (light/dark correct, semantic colors only). */
62
+ export const ChartTooltipContent: React.FC<ChartTooltipContentProps> = ({
63
+ active,
64
+ label,
65
+ payload,
66
+ valueFormatter,
67
+ }) => {
68
+ const theme = useTheme();
69
+ if (!active || !payload || payload.length === 0) return null;
70
+ const formatValue = (value: TooltipEntry['value']): string | number => {
71
+ if (typeof value === 'number' && valueFormatter) return valueFormatter(value);
72
+ return value ?? '';
73
+ };
74
+ return (
75
+ <Paper elevation={4} sx={{ px: 1.5, py: 1, border: `1px solid ${theme.palette.divider}` }}>
76
+ {label !== undefined && label !== '' && (
77
+ <Typography variant="caption" sx={{ color: 'text.secondary', display: 'block', mb: 0.5 }}>
78
+ {label}
79
+ </Typography>
80
+ )}
81
+ {payload.map((entry, index) => (
82
+ <Box key={index} sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
83
+ <Box
84
+ component="span"
85
+ sx={{ width: 10, height: 10, borderRadius: '2px', backgroundColor: entry.color, flexShrink: 0 }}
86
+ />
87
+ <Typography variant="body2" sx={{ color: 'text.secondary' }}>
88
+ {entry.name}
89
+ </Typography>
90
+ <Typography variant="body2" sx={{ ml: 'auto', fontWeight: 600 }}>
91
+ {formatValue(entry.value)}
92
+ </Typography>
93
+ </Box>
94
+ ))}
95
+ </Paper>
96
+ );
97
+ };
98
+
99
+ export interface ChartLegendContentProps {
100
+ payload?: Array<{ value?: string | number; color?: string }>;
101
+ }
102
+
103
+ /** Theme-aware legend content matching the tooltip's swatch styling. */
104
+ export const ChartLegendContent: React.FC<ChartLegendContentProps> = ({ payload }) => {
105
+ if (!payload || payload.length === 0) return null;
106
+ return (
107
+ <Box sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 2, pt: 1 }}>
108
+ {payload.map((entry, index) => (
109
+ <Box key={index} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
110
+ <Box
111
+ component="span"
112
+ sx={{ width: 10, height: 10, borderRadius: '2px', backgroundColor: entry.color, flexShrink: 0 }}
113
+ />
114
+ <Typography variant="caption" sx={{ color: 'text.secondary' }}>
115
+ {entry.value}
116
+ </Typography>
117
+ </Box>
118
+ ))}
119
+ </Box>
120
+ );
121
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * JSON-serializable chart specification — the declarative surface of the raw
3
+ * chart library. A `ChartSpec` plus plain data rows fully describes a rendered
4
+ * chart, so specs can be persisted, transmitted and authored by report
5
+ * builders or LLMs without touching component code. Colors are semantic theme
6
+ * tokens (never raw hex) so light/dark rendering stays correct.
7
+ */
8
+
9
+ /** Built-in chart types. New types can be added via the renderer registry. */
10
+ export type ChartSpecType = 'line' | 'bar' | 'area' | 'pie' | 'donut';
11
+
12
+ /**
13
+ * Semantic color token resolved against the MUI palette at render time.
14
+ * Specs must not carry raw color values.
15
+ */
16
+ export type ChartSemanticColor =
17
+ | 'primary'
18
+ | 'secondary'
19
+ | 'success'
20
+ | 'warning'
21
+ | 'error'
22
+ | 'info';
23
+
24
+ /**
25
+ * Number formatting applied to tooltip values and the y axis.
26
+ * `brl` treats values as integer centavos (the repo-wide money convention)
27
+ * and renders them as reais, e.g. `123456` → `R$ 1.234,56`.
28
+ * `percent` treats values as fractions, e.g. `0.153` → `15,3%`.
29
+ */
30
+ export type ChartNumberFormat = 'brl' | 'percent' | 'compact' | 'integer' | 'decimal';
31
+
32
+ export interface ChartSpecSeries {
33
+ /** Row property holding this series' value. */
34
+ key: string;
35
+ /** Legend/tooltip label; defaults to `key`. */
36
+ label?: string;
37
+ /** Semantic color token; defaults to cycling the spec's color scheme. */
38
+ color?: ChartSemanticColor;
39
+ }
40
+
41
+ export interface ChartSpecAxis {
42
+ /** Row property plotted on the category (x) axis — for pie/donut, the slice name. */
43
+ key: string;
44
+ label?: string;
45
+ }
46
+
47
+ export interface ChartSpec {
48
+ type: ChartSpecType;
49
+ title?: string;
50
+ subtitle?: string;
51
+ xAxis: ChartSpecAxis;
52
+ yAxis?: { label?: string };
53
+ /** At least one series. Pie/donut charts read slice values from the first series. */
54
+ series: ChartSpecSeries[];
55
+ /** Stack cartesian series instead of grouping them side by side. */
56
+ stacked?: boolean;
57
+ /** Show the legend (default true). */
58
+ legend?: boolean;
59
+ /** Show the tooltip (default true). */
60
+ tooltip?: boolean;
61
+ numberFormat?: ChartNumberFormat;
62
+ /** Palette cycled across series without an explicit color. */
63
+ colorScheme?: ChartSemanticColor[];
64
+ /** Smooth (monotone) lines/areas (default true). */
65
+ curved?: boolean;
66
+ /** Chart height in px; defaults to the host component's size. */
67
+ height?: number;
68
+ /** Center label rendered inside a donut chart. */
69
+ centerLabel?: string | { label: string; value: string | number };
70
+ }
@@ -0,0 +1,150 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import React from 'react';
3
+
4
+ import { SpecChart } from './SpecChart';
5
+ import type { ChartSpec } from './ChartSpec.types';
6
+
7
+ const meta: Meta<typeof SpecChart> = {
8
+ title: 'DataDisplay/SpecChart',
9
+ component: SpecChart,
10
+ parameters: {
11
+ layout: 'padded',
12
+ docs: {
13
+ description: {
14
+ component:
15
+ 'Renders a chart from a JSON-serializable ChartSpec plus plain data rows. ' +
16
+ 'The spec API is layered over the prop-driven Chart — same implementation, ' +
17
+ 'declarative surface for report builders and LLM authoring.',
18
+ },
19
+ },
20
+ },
21
+ tags: ['autodocs', 'component:Chart'],
22
+ };
23
+
24
+ export default meta;
25
+ type Story = StoryObj<typeof meta>;
26
+
27
+ const salesByDay = [
28
+ { day: 'Seg', total: 125000, perdas: 4500 },
29
+ { day: 'Ter', total: 98000, perdas: 1200 },
30
+ { day: 'Qua', total: 143500, perdas: 0 },
31
+ { day: 'Qui', total: 110200, perdas: 7300 },
32
+ { day: 'Sex', total: 189900, perdas: 2100 },
33
+ ];
34
+
35
+ const paymentMethods = [
36
+ { method: 'PIX', total: 420000 },
37
+ { method: 'Cartão', total: 310000 },
38
+ { method: 'Garçom', total: 86000 },
39
+ ];
40
+
41
+ const lineSpec: ChartSpec = {
42
+ type: 'line',
43
+ title: 'Vendas por dia',
44
+ subtitle: 'Receita líquida (BRL)',
45
+ xAxis: { key: 'day' },
46
+ series: [{ key: 'total', label: 'Total', color: 'primary' }],
47
+ numberFormat: 'brl',
48
+ };
49
+
50
+ export const Line: Story = {
51
+ args: { spec: lineSpec, data: salesByDay },
52
+ };
53
+
54
+ export const StackedBars: Story = {
55
+ args: {
56
+ spec: {
57
+ type: 'bar',
58
+ title: 'Vendas vs perdas',
59
+ xAxis: { key: 'day' },
60
+ series: [
61
+ { key: 'total', label: 'Vendas', color: 'primary' },
62
+ { key: 'perdas', label: 'Perdas', color: 'error' },
63
+ ],
64
+ stacked: true,
65
+ numberFormat: 'brl',
66
+ },
67
+ data: salesByDay,
68
+ },
69
+ };
70
+
71
+ export const Area: Story = {
72
+ args: {
73
+ spec: { ...lineSpec, type: 'area', title: 'Tendência de vendas' },
74
+ data: salesByDay,
75
+ },
76
+ };
77
+
78
+ export const Pie: Story = {
79
+ args: {
80
+ spec: {
81
+ type: 'pie',
82
+ title: 'Formas de pagamento',
83
+ xAxis: { key: 'method' },
84
+ series: [{ key: 'total' }],
85
+ numberFormat: 'brl',
86
+ },
87
+ data: paymentMethods,
88
+ },
89
+ };
90
+
91
+ export const Donut: Story = {
92
+ args: {
93
+ spec: {
94
+ type: 'donut',
95
+ title: 'Formas de pagamento',
96
+ xAxis: { key: 'method' },
97
+ series: [{ key: 'total' }],
98
+ numberFormat: 'brl',
99
+ centerLabel: { label: 'Total', value: 'R$ 8.160' },
100
+ },
101
+ data: paymentMethods,
102
+ },
103
+ };
104
+
105
+ export const PercentFormat: Story = {
106
+ args: {
107
+ spec: {
108
+ type: 'bar',
109
+ title: 'Margem por dia',
110
+ xAxis: { key: 'day' },
111
+ series: [{ key: 'margin', label: 'Margem', color: 'success' }],
112
+ numberFormat: 'percent',
113
+ legend: false,
114
+ },
115
+ data: salesByDay.map((row) => ({ day: row.day, margin: row.total > 0 ? 0.2 + row.perdas / row.total : 0 })),
116
+ },
117
+ };
118
+
119
+ export const CustomColorScheme: Story = {
120
+ args: {
121
+ spec: {
122
+ ...lineSpec,
123
+ type: 'bar',
124
+ title: 'Esquema de cores custom',
125
+ series: [
126
+ { key: 'total', label: 'Total' },
127
+ { key: 'perdas', label: 'Perdas' },
128
+ ],
129
+ colorScheme: ['info', 'warning'],
130
+ },
131
+ data: salesByDay,
132
+ },
133
+ };
134
+
135
+ export const FromJsonString: Story = {
136
+ render: () => {
137
+ const json =
138
+ '{"type":"area","title":"Spec vinda de JSON","xAxis":{"key":"day"},' +
139
+ '"series":[{"key":"total","label":"Total","color":"secondary"}],"numberFormat":"compact"}';
140
+ return <SpecChart spec={JSON.parse(json) as ChartSpec} data={salesByDay} />;
141
+ },
142
+ };
143
+
144
+ export const Loading: Story = {
145
+ args: { spec: lineSpec, data: [], loading: true },
146
+ };
147
+
148
+ export const Empty: Story = {
149
+ args: { spec: { ...lineSpec, title: 'Sem dados' }, data: [] },
150
+ };
@@ -0,0 +1,56 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { expect, within } from 'storybook/test';
3
+
4
+ import { SpecChart } from './SpecChart';
5
+
6
+ const meta: Meta<typeof SpecChart> = {
7
+ title: 'DataDisplay/SpecChart/Tests',
8
+ component: SpecChart,
9
+ parameters: { layout: 'padded' },
10
+ tags: ['autodocs', 'test', 'component:Chart'],
11
+ };
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ const data = [
17
+ { day: 'Seg', total: 125000 },
18
+ { day: 'Ter', total: 98000 },
19
+ ];
20
+
21
+ export const RendersFromSpec: Story = {
22
+ args: {
23
+ spec: {
24
+ type: 'bar',
25
+ title: 'Spec Render',
26
+ xAxis: { key: 'day' },
27
+ series: [{ key: 'total', label: 'Total', color: 'primary' }],
28
+ numberFormat: 'brl',
29
+ },
30
+ data,
31
+ },
32
+ play: async ({ canvasElement }) => {
33
+ const canvas = within(canvasElement);
34
+ await expect(canvas.getByTestId('spec-chart')).toBeInTheDocument();
35
+ await expect(canvas.getByText('Spec Render')).toBeInTheDocument();
36
+ },
37
+ };
38
+
39
+ export const DonutCenterLabel: Story = {
40
+ args: {
41
+ spec: {
42
+ type: 'donut',
43
+ xAxis: { key: 'method' },
44
+ series: [{ key: 'total' }],
45
+ centerLabel: { label: 'Total', value: 'R$ 100' },
46
+ },
47
+ data: [
48
+ { method: 'PIX', total: 60 },
49
+ { method: 'Cartão', total: 40 },
50
+ ],
51
+ },
52
+ play: async ({ canvasElement }) => {
53
+ const canvas = within(canvasElement);
54
+ await expect(canvas.getByTestId('spec-chart')).toBeInTheDocument();
55
+ },
56
+ };
@@ -0,0 +1,53 @@
1
+ import { useTheme } from '@mui/material';
2
+ import React from 'react';
3
+
4
+ import { Chart } from './Chart';
5
+ import type { ChartDataPoint } from './Chart.types';
6
+ import type { ChartSemanticColor, ChartSpec } from './ChartSpec.types';
7
+ import { CHART_SEMANTIC_COLORS, specToChartProps } from './chart-spec';
8
+
9
+ export interface SpecChartProps {
10
+ /** Validated spec — parse untrusted JSON with `parseChartSpec` first. */
11
+ spec: ChartSpec;
12
+ data: ChartDataPoint[];
13
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
14
+ loading?: boolean;
15
+ className?: string;
16
+ onClick?: (point: ChartDataPoint) => void;
17
+ 'data-testid'?: string;
18
+ }
19
+
20
+ /**
21
+ * Renders a chart from a JSON-serializable {@link ChartSpec} plus plain data
22
+ * rows. Layered over the prop-driven `Chart` (one implementation); semantic
23
+ * color tokens resolve against the active MUI theme at render time.
24
+ */
25
+ export const SpecChart: React.FC<SpecChartProps> = ({
26
+ spec,
27
+ data,
28
+ size,
29
+ loading,
30
+ className,
31
+ onClick,
32
+ 'data-testid': dataTestId = 'spec-chart',
33
+ }) => {
34
+ const theme = useTheme();
35
+ const chartProps = React.useMemo(() => {
36
+ const scheme: readonly ChartSemanticColor[] =
37
+ spec.colorScheme && spec.colorScheme.length > 0 ? spec.colorScheme : CHART_SEMANTIC_COLORS;
38
+ const resolveColor = (token: ChartSemanticColor | undefined, index: number): string =>
39
+ theme.palette[token ?? scheme[index % scheme.length] ?? 'primary'].main;
40
+ return specToChartProps(spec, data, { resolveColor });
41
+ }, [spec, data, theme]);
42
+
43
+ return (
44
+ <Chart
45
+ {...chartProps}
46
+ size={size}
47
+ loading={loading}
48
+ className={className}
49
+ onClick={onClick}
50
+ data-testid={dataTestId}
51
+ />
52
+ );
53
+ };
@@ -0,0 +1,60 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { parseChartSpec } from '../chart-spec';
6
+ import { SpecChart } from '../SpecChart';
7
+
8
+ const json = JSON.stringify({
9
+ type: 'bar',
10
+ title: 'Vendas por dia',
11
+ subtitle: 'Últimos 7 dias',
12
+ xAxis: { key: 'day' },
13
+ series: [
14
+ { key: 'total', label: 'Total', color: 'primary' },
15
+ { key: 'perdas', label: 'Perdas', color: 'error' },
16
+ ],
17
+ numberFormat: 'brl',
18
+ });
19
+
20
+ const data = [
21
+ { day: 'seg', total: 1200, perdas: 100 },
22
+ { day: 'ter', total: 3400, perdas: 0 },
23
+ ];
24
+
25
+ describe('SpecChart', () => {
26
+ it('renders a chart from a pure JSON spec plus data rows', () => {
27
+ render(<SpecChart spec={parseChartSpec(JSON.parse(json))} data={data} />);
28
+ expect(screen.getByTestId('spec-chart')).toBeInTheDocument();
29
+ expect(screen.getByText('Vendas por dia')).toBeInTheDocument();
30
+ expect(screen.getByText('Últimos 7 dias')).toBeInTheDocument();
31
+ });
32
+
33
+ it('renders pie specs', () => {
34
+ render(
35
+ <SpecChart
36
+ spec={parseChartSpec({
37
+ type: 'pie',
38
+ xAxis: { key: 'method' },
39
+ series: [{ key: 'total' }],
40
+ })}
41
+ data={[
42
+ { method: 'PIX', total: 700 },
43
+ { method: 'Cartão', total: 300 },
44
+ ]}
45
+ />,
46
+ );
47
+ expect(screen.getByTestId('spec-chart')).toBeInTheDocument();
48
+ });
49
+
50
+ it('shows the loading state', () => {
51
+ render(
52
+ <SpecChart
53
+ spec={parseChartSpec({ type: 'line', xAxis: { key: 'x' }, series: [{ key: 'y' }] })}
54
+ data={[]}
55
+ loading
56
+ />,
57
+ );
58
+ expect(screen.getByTestId('spec-chart-loading')).toBeInTheDocument();
59
+ });
60
+ });
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { chartValueFormatter, formatChartValue } from '../chart-format';
4
+
5
+ describe('formatChartValue', () => {
6
+ it('formats brl from integer centavos', () => {
7
+ const formatted = formatChartValue(123456, 'brl');
8
+ expect(formatted).toContain('R$');
9
+ expect(formatted).toContain('1.234,56');
10
+ });
11
+
12
+ it('formats negative centavos', () => {
13
+ expect(formatChartValue(-500, 'brl')).toContain('5,00');
14
+ });
15
+
16
+ it('formats percent from a fraction', () => {
17
+ expect(formatChartValue(0.153, 'percent')).toBe('15,3%');
18
+ });
19
+
20
+ it('formats compact values', () => {
21
+ expect(formatChartValue(1500, 'compact')).toContain('1,5');
22
+ });
23
+
24
+ it('formats integers without decimals', () => {
25
+ expect(formatChartValue(1234.56, 'integer')).toBe('1.235');
26
+ });
27
+
28
+ it('defaults to decimal formatting', () => {
29
+ expect(formatChartValue(1234.567)).toBe('1.234,57');
30
+ });
31
+
32
+ it('renders non-finite values as an empty string', () => {
33
+ expect(formatChartValue(Number.NaN, 'brl')).toBe('');
34
+ expect(formatChartValue(Number.POSITIVE_INFINITY)).toBe('');
35
+ });
36
+ });
37
+
38
+ describe('chartValueFormatter', () => {
39
+ it('curries the format', () => {
40
+ const format = chartValueFormatter('brl');
41
+ expect(format(100)).toContain('1,00');
42
+ });
43
+ });
@@ -0,0 +1,119 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import type { ChartSpec } from '../ChartSpec.types';
4
+ import { ChartSpecError, parseChartSpec, specToChartProps } from '../chart-spec';
5
+ import {
6
+ getRegisteredChartSpecTypes,
7
+ registerChartSpecRenderer,
8
+ type ChartSpecRenderContext,
9
+ } from '../chart-spec-registry';
10
+
11
+ const ctx: ChartSpecRenderContext = {
12
+ resolveColor: (token, index) => `${token ?? 'auto'}-${index}`,
13
+ };
14
+
15
+ const lineSpec: ChartSpec = {
16
+ type: 'line',
17
+ title: 'Vendas',
18
+ xAxis: { key: 'day' },
19
+ series: [{ key: 'total', label: 'Total', color: 'primary' }, { key: 'count' }],
20
+ numberFormat: 'brl',
21
+ };
22
+
23
+ describe('parseChartSpec', () => {
24
+ it('accepts a valid spec round-tripped through JSON', () => {
25
+ const parsed = parseChartSpec(JSON.parse(JSON.stringify(lineSpec)));
26
+ expect(parsed.type).toBe('line');
27
+ expect(parsed.series).toHaveLength(2);
28
+ expect(parsed.xAxis.key).toBe('day');
29
+ });
30
+
31
+ it('rejects non-objects', () => {
32
+ expect(() => parseChartSpec('nope')).toThrow(ChartSpecError);
33
+ });
34
+
35
+ it('rejects unknown chart types and lists registered ones', () => {
36
+ expect(() => parseChartSpec({ ...lineSpec, type: 'sankey' })).toThrow(/registered chart types/);
37
+ expect(() => parseChartSpec({ ...lineSpec, type: 'sankey' })).toThrow(/line/);
38
+ });
39
+
40
+ it('rejects a missing xAxis key', () => {
41
+ expect(() => parseChartSpec({ ...lineSpec, xAxis: {} })).toThrow(/"xAxis"/);
42
+ });
43
+
44
+ it('rejects empty series', () => {
45
+ expect(() => parseChartSpec({ ...lineSpec, series: [] })).toThrow(/"series"/);
46
+ });
47
+
48
+ it('rejects raw color values with an actionable message', () => {
49
+ expect(() => parseChartSpec({ ...lineSpec, series: [{ key: 'total', color: '#ff0000' }] })).toThrow(
50
+ /semantic color token/,
51
+ );
52
+ });
53
+
54
+ it('rejects invalid number formats', () => {
55
+ expect(() => parseChartSpec({ ...lineSpec, numberFormat: 'usd' })).toThrow(/"numberFormat"/);
56
+ });
57
+
58
+ it('rejects invalid colorScheme entries', () => {
59
+ expect(() => parseChartSpec({ ...lineSpec, colorScheme: ['primary', 'magenta'] })).toThrow(
60
+ /"colorScheme\[1\]"/,
61
+ );
62
+ });
63
+ });
64
+
65
+ describe('specToChartProps', () => {
66
+ it('maps cartesian specs onto Chart props', () => {
67
+ const props = specToChartProps(lineSpec, [{ day: 'seg', total: 100, count: 2 }], ctx);
68
+ expect(props.type).toBe('line');
69
+ expect(props.xAxisKey).toBe('day');
70
+ expect(props.series).toEqual([
71
+ { dataKey: 'total', name: 'Total', color: 'primary-0' },
72
+ { dataKey: 'count', name: 'count', color: 'auto-1' },
73
+ ]);
74
+ expect(props.valueFormatter?.(100)).toContain('1,00');
75
+ });
76
+
77
+ it('honors stacked bars and legend/tooltip toggles', () => {
78
+ const props = specToChartProps(
79
+ { ...lineSpec, type: 'bar', stacked: true, legend: false, tooltip: false },
80
+ [],
81
+ ctx,
82
+ );
83
+ expect(props.type).toBe('bar');
84
+ expect(props.stacked).toBe(true);
85
+ expect(props.showLegend).toBe(false);
86
+ expect(props.showTooltip).toBe(false);
87
+ });
88
+
89
+ it('renders donut as pie with an inner radius and center label', () => {
90
+ const props = specToChartProps(
91
+ {
92
+ type: 'donut',
93
+ xAxis: { key: 'method' },
94
+ series: [{ key: 'total' }],
95
+ centerLabel: { label: 'Total', value: 'R$ 10' },
96
+ },
97
+ [],
98
+ ctx,
99
+ );
100
+ expect(props.type).toBe('pie');
101
+ expect(props.innerRadius).toBeGreaterThan(0);
102
+ expect(props.centerLabel).toEqual({ label: 'Total', value: 'R$ 10' });
103
+ });
104
+
105
+ it('supports registering new chart types without touching consumers', () => {
106
+ registerChartSpecRenderer('sparkline', (spec) => ({
107
+ type: 'line',
108
+ series: spec.series.map((s) => ({ dataKey: s.key })),
109
+ }));
110
+ expect(getRegisteredChartSpecTypes()).toContain('sparkline');
111
+ const spec = parseChartSpec({
112
+ type: 'sparkline',
113
+ xAxis: { key: 'x' },
114
+ series: [{ key: 'y' }],
115
+ });
116
+ const props = specToChartProps(spec, [], ctx);
117
+ expect(props.type).toBe('line');
118
+ });
119
+ });