@lerianstudio/sindarian-ui 2.0.0-beta.25 → 2.0.0-beta.26

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 (305) hide show
  1. package/dist/charts/chart.js +4 -231
  2. package/dist/charts/index.js +1 -11
  3. package/dist/components/breadcrumb/get-breadcrumb-paths.js +1 -18
  4. package/dist/components/breadcrumb/index.js +1 -37
  5. package/dist/components/card/account-card/index.js +1 -69
  6. package/dist/components/card/basic-card/index.js +1 -20
  7. package/dist/components/card/dashboard-card/index.js +1 -20
  8. package/dist/components/card/entity-card/index.js +1 -68
  9. package/dist/components/card/index.js +1 -20
  10. package/dist/components/dialog/confirmation-dialog/index.js +1 -96
  11. package/dist/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -55
  12. package/dist/components/dialog/index.js +1 -19
  13. package/dist/components/dialog/large-dialog/index.js +1 -21
  14. package/dist/components/entity-box/index.js +1 -67
  15. package/dist/components/entity-data-table/index.js +1 -20
  16. package/dist/components/form/combo-box-field/index.js +1 -35
  17. package/dist/components/form/country-field/index.js +1 -11
  18. package/dist/components/form/date-picker-field/index.js +1 -83
  19. package/dist/components/form/date-range-field/index.js +1 -58
  20. package/dist/components/form/date-time-picker-field/index.js +1 -114
  21. package/dist/components/form/file-upload-field/index.js +1 -69
  22. package/dist/components/form/index.js +1 -31
  23. package/dist/components/form/input-field/index.js +1 -96
  24. package/dist/components/form/otp-field/index.js +1 -19
  25. package/dist/components/form/pagination-limit-field/index.js +1 -10
  26. package/dist/components/form/password-field/index.js +1 -16
  27. package/dist/components/form/radio-group-field/index.js +1 -36
  28. package/dist/components/form/renderable-label.js +1 -57
  29. package/dist/components/form/select-field/index.js +1 -68
  30. package/dist/components/form/state-field/index.js +1 -42
  31. package/dist/components/form/switch-field/index.js +1 -16
  32. package/dist/components/form/textarea-field/index.js +1 -23
  33. package/dist/components/page/index.js +1 -20
  34. package/dist/components/page-header/index.js +1 -80
  35. package/dist/components/pagination/index.js +1 -10
  36. package/dist/components/table/id-table-cell.js +1 -109
  37. package/dist/components/table/index.js +1 -19
  38. package/dist/components/table/locked-table-actions.js +1 -41
  39. package/dist/components/table/name-table-cell.js +1 -58
  40. package/dist/components/ui/accordion/index.js +1 -62
  41. package/dist/components/ui/alert/index.js +1 -45
  42. package/dist/components/ui/alert-dialog/index.js +1 -84
  43. package/dist/components/ui/autocomplete/index.js +1 -440
  44. package/dist/components/ui/autosize-textarea/index.js +1 -89
  45. package/dist/components/ui/avatar/index.js +1 -51
  46. package/dist/components/ui/badge/index.js +1 -83
  47. package/dist/components/ui/breadcrumb/index.js +1 -35
  48. package/dist/components/ui/button/index.js +1 -65
  49. package/dist/components/ui/calendar/index.js +1 -118
  50. package/dist/components/ui/card/index.js +1 -32
  51. package/dist/components/ui/checkbox/index.js +1 -44
  52. package/dist/components/ui/collapsible/index.js +1 -50
  53. package/dist/components/ui/command/index.js +1 -95
  54. package/dist/components/ui/copy-field/index.js +1 -163
  55. package/dist/components/ui/dialog/index.js +1 -80
  56. package/dist/components/ui/dropdown-menu/index.js +1 -110
  57. package/dist/components/ui/field/index.js +1 -82
  58. package/dist/components/ui/file-upload/index.js +1 -574
  59. package/dist/components/ui/form.js +1 -162
  60. package/dist/components/ui/hover-card/index.js +1 -51
  61. package/dist/components/ui/icon-button/index.js +1 -35
  62. package/dist/components/ui/input/adornment.js +1 -21
  63. package/dist/components/ui/input/index.js +1 -99
  64. package/dist/components/ui/label/index.js +1 -45
  65. package/dist/components/ui/lerian-wordmark/index.js +1 -7
  66. package/dist/components/ui/loading-button/index.js +1 -9
  67. package/dist/components/ui/multiple-select/index.js +1 -235
  68. package/dist/components/ui/otp-input/index.js +1 -62
  69. package/dist/components/ui/paper/index.js +1 -8
  70. package/dist/components/ui/paper-collapsible/index.js +1 -24
  71. package/dist/components/ui/popover/index.js +1 -55
  72. package/dist/components/ui/progress/index.js +1 -66
  73. package/dist/components/ui/qr-code/index.js +1 -27
  74. package/dist/components/ui/radio-group/index.js +1 -48
  75. package/dist/components/ui/scroll-area/index.js +1 -49
  76. package/dist/components/ui/select/index.js +1 -119
  77. package/dist/components/ui/separator/index.js +1 -43
  78. package/dist/components/ui/sheet/index.js +1 -136
  79. package/dist/components/ui/sidebar/index.js +1 -27
  80. package/dist/components/ui/sidebar/next-router.cjs +1 -119
  81. package/dist/components/ui/sidebar/sidebar-back-button.js +1 -8
  82. package/dist/components/ui/sidebar/sidebar-components.js +1 -23
  83. package/dist/components/ui/sidebar/sidebar-expand-button.js +1 -49
  84. package/dist/components/ui/sidebar/sidebar-item-button.js +1 -21
  85. package/dist/components/ui/sidebar/sidebar-item-collapsible.js +1 -52
  86. package/dist/components/ui/sidebar/sidebar-item-icon-button.js +1 -18
  87. package/dist/components/ui/sidebar/sidebar-item.js +1 -44
  88. package/dist/components/ui/sidebar/sidebar-provider.js +1 -201
  89. package/dist/components/ui/sidebar/sidebar-root.js +1 -130
  90. package/dist/components/ui/sidebar/sidebar-router.js +1 -126
  91. package/dist/components/ui/sidebar/sidebar-trigger.js +1 -57
  92. package/dist/components/ui/skeleton/index.js +1 -8
  93. package/dist/components/ui/stepper/index.js +1 -29
  94. package/dist/components/ui/switch/index.js +1 -43
  95. package/dist/components/ui/table/index.js +1 -56
  96. package/dist/components/ui/tabs/index.js +1 -55
  97. package/dist/components/ui/textarea/index.js +1 -8
  98. package/dist/components/ui/time-picker/index.js +1 -85
  99. package/dist/components/ui/toast/index.js +1 -3
  100. package/dist/components/ui/toast/toaster.js +1 -16
  101. package/dist/components/ui/toggle-group/index.js +1 -156
  102. package/dist/components/ui/tooltip/index.js +1 -81
  103. package/dist/domain/blotter/index.js +1 -20
  104. package/dist/domain/delinquency-aging/aging-buckets.js +1 -120
  105. package/dist/domain/delinquency-aging/index.js +1 -222
  106. package/dist/domain/figure/index.js +1 -19
  107. package/dist/domain/format.js +1 -137
  108. package/dist/domain/index.js +1 -43
  109. package/dist/domain/key-id/index.js +1 -174
  110. package/dist/domain/ledger-sheet/index.js +1 -28
  111. package/dist/domain/money-diff.js +1 -48
  112. package/dist/domain/money-math.js +1 -104
  113. package/dist/domain/money-text/index.js +1 -123
  114. package/dist/domain/section-label/index.js +1 -17
  115. package/dist/domain/status-rail/index.js +1 -76
  116. package/dist/domain/threshold-gauge/index.js +1 -161
  117. package/dist/enterprise/alert-banner/index.js +1 -24
  118. package/dist/enterprise/app-shell/index.js +1 -87
  119. package/dist/enterprise/cursor-pager/index.js +1 -26
  120. package/dist/enterprise/data-table/column-size.js +1 -103
  121. package/dist/enterprise/data-table/index.js +1 -345
  122. package/dist/enterprise/date-range-picker/index.js +1 -115
  123. package/dist/enterprise/detail-panel/index.js +1 -20
  124. package/dist/enterprise/empty-state/index.js +1 -14
  125. package/dist/enterprise/index.js +1 -39
  126. package/dist/enterprise/number-input/index.js +1 -252
  127. package/dist/enterprise/search-input/index.js +1 -121
  128. package/dist/enterprise/stat-card/index.js +1 -75
  129. package/dist/enterprise/status-badge/index.js +1 -120
  130. package/dist/enterprise/use-is-mobile.js +1 -68
  131. package/dist/enterprise/virtualized-table/index.js +1 -141
  132. package/dist/esm/charts/chart.js +4 -190
  133. package/dist/esm/charts/index.js +1 -3
  134. package/dist/esm/components/breadcrumb/get-breadcrumb-paths.js +1 -12
  135. package/dist/esm/components/breadcrumb/index.js +1 -30
  136. package/dist/esm/components/card/account-card/index.js +1 -53
  137. package/dist/esm/components/card/basic-card/index.js +1 -14
  138. package/dist/esm/components/card/dashboard-card/index.js +1 -14
  139. package/dist/esm/components/card/entity-card/index.js +1 -52
  140. package/dist/esm/components/card/index.js +1 -4
  141. package/dist/esm/components/dialog/confirmation-dialog/index.js +1 -60
  142. package/dist/esm/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -49
  143. package/dist/esm/components/dialog/index.js +1 -3
  144. package/dist/esm/components/dialog/large-dialog/index.js +1 -16
  145. package/dist/esm/components/entity-box/index.js +1 -56
  146. package/dist/esm/components/entity-data-table/index.js +1 -17
  147. package/dist/esm/components/form/combo-box-field/index.js +1 -28
  148. package/dist/esm/components/form/country-field/index.js +1 -7
  149. package/dist/esm/components/form/date-picker-field/index.js +1 -43
  150. package/dist/esm/components/form/date-range-field/index.js +1 -18
  151. package/dist/esm/components/form/date-time-picker-field/index.js +1 -74
  152. package/dist/esm/components/form/file-upload-field/index.js +1 -65
  153. package/dist/esm/components/form/index.js +1 -15
  154. package/dist/esm/components/form/input-field/index.js +1 -92
  155. package/dist/esm/components/form/otp-field/index.js +1 -15
  156. package/dist/esm/components/form/pagination-limit-field/index.js +1 -6
  157. package/dist/esm/components/form/password-field/index.js +1 -10
  158. package/dist/esm/components/form/radio-group-field/index.js +1 -32
  159. package/dist/esm/components/form/renderable-label.js +1 -54
  160. package/dist/esm/components/form/select-field/index.js +1 -64
  161. package/dist/esm/components/form/state-field/index.js +1 -35
  162. package/dist/esm/components/form/switch-field/index.js +1 -12
  163. package/dist/esm/components/form/textarea-field/index.js +1 -19
  164. package/dist/esm/components/page/index.js +1 -15
  165. package/dist/esm/components/page-header/index.js +1 -71
  166. package/dist/esm/components/pagination/index.js +1 -6
  167. package/dist/esm/components/table/id-table-cell.js +1 -105
  168. package/dist/esm/components/table/index.js +1 -3
  169. package/dist/esm/components/table/locked-table-actions.js +1 -37
  170. package/dist/esm/components/table/name-table-cell.js +1 -54
  171. package/dist/esm/components/ui/accordion/index.js +1 -24
  172. package/dist/esm/components/ui/alert/index.js +1 -38
  173. package/dist/esm/components/ui/alert-dialog/index.js +1 -39
  174. package/dist/esm/components/ui/autocomplete/index.js +1 -392
  175. package/dist/esm/components/ui/autosize-textarea/index.js +1 -51
  176. package/dist/esm/components/ui/avatar/index.js +1 -14
  177. package/dist/esm/components/ui/badge/index.js +1 -79
  178. package/dist/esm/components/ui/breadcrumb/index.js +1 -27
  179. package/dist/esm/components/ui/button/index.js +1 -60
  180. package/dist/esm/components/ui/calendar/index.js +1 -82
  181. package/dist/esm/components/ui/card/index.js +1 -24
  182. package/dist/esm/components/ui/checkbox/index.js +1 -9
  183. package/dist/esm/components/ui/collapsible/index.js +1 -13
  184. package/dist/esm/components/ui/command/index.js +1 -51
  185. package/dist/esm/components/ui/copy-field/index.js +1 -127
  186. package/dist/esm/components/ui/dialog/index.js +1 -36
  187. package/dist/esm/components/ui/dropdown-menu/index.js +1 -60
  188. package/dist/esm/components/ui/field/index.js +1 -71
  189. package/dist/esm/components/ui/file-upload/index.js +1 -536
  190. package/dist/esm/components/ui/form.js +1 -118
  191. package/dist/esm/components/ui/hover-card/index.js +1 -14
  192. package/dist/esm/components/ui/icon-button/index.js +1 -31
  193. package/dist/esm/components/ui/input/adornment.js +1 -17
  194. package/dist/esm/components/ui/input/index.js +1 -60
  195. package/dist/esm/components/ui/label/index.js +1 -10
  196. package/dist/esm/components/ui/lerian-wordmark/index.js +1 -4
  197. package/dist/esm/components/ui/loading-button/index.js +1 -7
  198. package/dist/esm/components/ui/multiple-select/index.js +1 -196
  199. package/dist/esm/components/ui/otp-input/index.js +1 -21
  200. package/dist/esm/components/ui/paper/index.js +1 -5
  201. package/dist/esm/components/ui/paper-collapsible/index.js +1 -19
  202. package/dist/esm/components/ui/popover/index.js +1 -17
  203. package/dist/esm/components/ui/progress/index.js +1 -31
  204. package/dist/esm/components/ui/qr-code/index.js +1 -24
  205. package/dist/esm/components/ui/radio-group/index.js +1 -12
  206. package/dist/esm/components/ui/scroll-area/index.js +1 -13
  207. package/dist/esm/components/ui/select/index.js +1 -74
  208. package/dist/esm/components/ui/separator/index.js +1 -8
  209. package/dist/esm/components/ui/sheet/index.js +1 -92
  210. package/dist/esm/components/ui/sidebar/index.js +1 -11
  211. package/dist/esm/components/ui/sidebar/next-router.cjs +1 -119
  212. package/dist/esm/components/ui/sidebar/sidebar-back-button.js +1 -5
  213. package/dist/esm/components/ui/sidebar/sidebar-components.js +1 -15
  214. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +1 -42
  215. package/dist/esm/components/ui/sidebar/sidebar-item-button.js +1 -18
  216. package/dist/esm/components/ui/sidebar/sidebar-item-collapsible.js +1 -44
  217. package/dist/esm/components/ui/sidebar/sidebar-item-icon-button.js +1 -14
  218. package/dist/esm/components/ui/sidebar/sidebar-item.js +1 -40
  219. package/dist/esm/components/ui/sidebar/sidebar-provider.js +1 -193
  220. package/dist/esm/components/ui/sidebar/sidebar-root.js +1 -126
  221. package/dist/esm/components/ui/sidebar/sidebar-router.js +1 -89
  222. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +1 -53
  223. package/dist/esm/components/ui/skeleton/index.js +1 -6
  224. package/dist/esm/components/ui/stepper/index.js +1 -20
  225. package/dist/esm/components/ui/switch/index.js +1 -8
  226. package/dist/esm/components/ui/table/index.js +1 -44
  227. package/dist/esm/components/ui/tabs/index.js +1 -17
  228. package/dist/esm/components/ui/textarea/index.js +1 -6
  229. package/dist/esm/components/ui/time-picker/index.js +1 -49
  230. package/dist/esm/components/ui/toast/index.js +1 -2
  231. package/dist/esm/components/ui/toast/toaster.js +1 -13
  232. package/dist/esm/components/ui/toggle-group/index.js +1 -120
  233. package/dist/esm/components/ui/tooltip/index.js +1 -43
  234. package/dist/esm/domain/blotter/index.js +1 -16
  235. package/dist/esm/domain/delinquency-aging/aging-buckets.js +1 -115
  236. package/dist/esm/domain/delinquency-aging/index.js +1 -218
  237. package/dist/esm/domain/figure/index.js +1 -15
  238. package/dist/esm/domain/format.js +1 -128
  239. package/dist/esm/domain/index.js +1 -19
  240. package/dist/esm/domain/key-id/index.js +1 -169
  241. package/dist/esm/domain/ledger-sheet/index.js +1 -24
  242. package/dist/esm/domain/money-diff.js +1 -45
  243. package/dist/esm/domain/money-math.js +1 -98
  244. package/dist/esm/domain/money-text/index.js +1 -118
  245. package/dist/esm/domain/section-label/index.js +1 -14
  246. package/dist/esm/domain/status-rail/index.js +1 -71
  247. package/dist/esm/domain/threshold-gauge/index.js +1 -157
  248. package/dist/esm/enterprise/alert-banner/index.js +1 -21
  249. package/dist/esm/enterprise/app-shell/index.js +1 -51
  250. package/dist/esm/enterprise/cursor-pager/index.js +1 -23
  251. package/dist/esm/enterprise/data-table/column-size.js +1 -97
  252. package/dist/esm/enterprise/data-table/index.js +1 -342
  253. package/dist/esm/enterprise/date-range-picker/index.js +1 -112
  254. package/dist/esm/enterprise/detail-panel/index.js +1 -17
  255. package/dist/esm/enterprise/empty-state/index.js +1 -11
  256. package/dist/esm/enterprise/index.js +1 -22
  257. package/dist/esm/enterprise/number-input/index.js +1 -214
  258. package/dist/esm/enterprise/search-input/index.js +1 -85
  259. package/dist/esm/enterprise/stat-card/index.js +1 -72
  260. package/dist/esm/enterprise/status-badge/index.js +1 -116
  261. package/dist/esm/enterprise/use-is-mobile.js +1 -31
  262. package/dist/esm/enterprise/virtualized-table/index.js +1 -138
  263. package/dist/esm/hooks/use-click-away.js +1 -22
  264. package/dist/esm/hooks/use-pagination.js +1 -38
  265. package/dist/esm/hooks/use-stepper.js +1 -22
  266. package/dist/esm/hooks/use-time.js +1 -13
  267. package/dist/esm/hooks/use-toast.js +1 -107
  268. package/dist/esm/index.js +1 -77
  269. package/dist/esm/lib/storage/get-storage-object.js +1 -17
  270. package/dist/esm/lib/storage/get-storage.js +1 -14
  271. package/dist/esm/lib/storage/index.js +1 -2
  272. package/dist/esm/lib/typography.js +1 -31
  273. package/dist/esm/lib/utils.js +1 -41
  274. package/dist/esm/theme/get-theme-script.js +1 -41
  275. package/dist/esm/theme/index.js +1 -4
  276. package/dist/esm/theme/mode-toggle.js +1 -45
  277. package/dist/esm/theme/theme-provider.js +1 -122
  278. package/dist/esm/toast/helpers.js +1 -36
  279. package/dist/esm/toast/index.js +1 -4
  280. package/dist/esm/types/metadata-type.js +1 -1
  281. package/dist/esm/utils/countries.cjs +1 -17
  282. package/dist/esm/utils/country-utils.js +1 -18
  283. package/dist/esm/utils/currency-codes.js +1 -181
  284. package/dist/hooks/use-click-away.js +1 -29
  285. package/dist/hooks/use-pagination.js +1 -41
  286. package/dist/hooks/use-stepper.js +1 -26
  287. package/dist/hooks/use-time.js +1 -20
  288. package/dist/hooks/use-toast.js +1 -111
  289. package/dist/index.js +1 -96
  290. package/dist/lib/storage/get-storage-object.js +1 -23
  291. package/dist/lib/storage/get-storage.js +1 -17
  292. package/dist/lib/storage/index.js +1 -18
  293. package/dist/lib/typography.js +1 -34
  294. package/dist/lib/utils.js +1 -45
  295. package/dist/theme/get-theme-script.js +1 -44
  296. package/dist/theme/index.js +1 -11
  297. package/dist/theme/mode-toggle.js +1 -48
  298. package/dist/theme/theme-provider.js +1 -160
  299. package/dist/toast/helpers.js +1 -41
  300. package/dist/toast/index.js +1 -10
  301. package/dist/types/metadata-type.js +1 -2
  302. package/dist/utils/countries.cjs +1 -17
  303. package/dist/utils/country-utils.js +1 -25
  304. package/dist/utils/currency-codes.js +1 -184
  305. package/package.json +4 -3
@@ -1,156 +1 @@
1
- 'use client';
2
- "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
- Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.ToggleGroup = ToggleGroup;
38
- exports.ToggleGroupItem = ToggleGroupItem;
39
- const jsx_runtime_1 = require("react/jsx-runtime");
40
- const React = __importStar(require("react"));
41
- const ToggleGroupPrimitive = __importStar(require("@radix-ui/react-toggle-group"));
42
- const class_variance_authority_1 = require("class-variance-authority");
43
- const utils_1 = require("../../../lib/utils");
44
- /**
45
- * Item styling for the group. Kept local: sindarian-ui has no standalone
46
- * `Toggle` primitive and the retirement census does not ask for one, so the
47
- * variants live with their only consumer instead of leaking a new export.
48
- */
49
- const toggleVariants = (0, class_variance_authority_1.cva)("hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
50
- variants: {
51
- variant: {
52
- default: 'bg-transparent',
53
- outline: 'border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs'
54
- },
55
- size: {
56
- default: 'h-9 min-w-9 px-2',
57
- sm: 'h-8 min-w-8 px-1.5',
58
- lg: 'h-10 min-w-10 px-2.5'
59
- }
60
- },
61
- defaultVariants: {
62
- variant: 'default',
63
- size: 'default'
64
- }
65
- });
66
- const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
67
- /**
68
- * Is an arrow key down right now?
69
- *
70
- * This is how an item tells keyboard navigation apart from a pointer press or a
71
- * programmatic focus, and it is the seam Radix uses for the same job in its own
72
- * `RadioGroup`. It works because `RovingFocusGroup` defers the focus move to a
73
- * `setTimeout`: the keydown has already bubbled to `document` and set the flag
74
- * by the time the item receives `focus`.
75
- *
76
- * The distinction is not cosmetic. A pointer press focuses BEFORE the click
77
- * lands, so selecting on every focus would turn one click into
78
- * select-then-deselect and break mouse selection outright.
79
- *
80
- * Returns null when disabled, so `type="multiple"` carries no flag to read.
81
- */
82
- function useArrowKeyPressed(enabled) {
83
- const arrowKeyPressed = React.useRef(false);
84
- React.useEffect(() => {
85
- if (!enabled)
86
- return;
87
- const onKeyDown = (event) => {
88
- if (ARROW_KEYS.includes(event.key))
89
- arrowKeyPressed.current = true;
90
- };
91
- const onKeyUp = () => {
92
- arrowKeyPressed.current = false;
93
- };
94
- document.addEventListener('keydown', onKeyDown);
95
- document.addEventListener('keyup', onKeyUp);
96
- window.addEventListener('blur', onKeyUp);
97
- return () => {
98
- document.removeEventListener('keydown', onKeyDown);
99
- document.removeEventListener('keyup', onKeyUp);
100
- window.removeEventListener('blur', onKeyUp);
101
- // A group unmounted mid-keystroke never sees the keyup.
102
- arrowKeyPressed.current = false;
103
- };
104
- }, [enabled]);
105
- return enabled ? arrowKeyPressed : null;
106
- }
107
- const ToggleGroupContext = React.createContext({
108
- size: 'default',
109
- variant: 'default',
110
- spacing: 0,
111
- arrowKeyPressed: null
112
- });
113
- function ToggleGroup({ className, variant, size, spacing = 0, children, style, ...props }) {
114
- // Read, never destructured: `type` is the discriminant of the Radix props
115
- // union, and pulling it out then spreading it back widens the union so the
116
- // single/multiple props stop resolving.
117
- const arrowKeyPressed = useArrowKeyPressed(props.type === 'single');
118
- return ((0, jsx_runtime_1.jsx)(ToggleGroupPrimitive.Root, { "data-slot": "toggle-group", "data-variant": variant, "data-size": size, "data-spacing": spacing,
119
- // Caller style first: `--gap` is ours and must survive, but everything
120
- // else the caller passes has to reach the element.
121
- style: { ...style, '--gap': spacing }, className: (0, utils_1.cn)(
122
- // Legacy carried a `data-[spacing=default]:...:shadow-xs` rule here that
123
- // never matched — `data-spacing` is always a number. Removed rather than
124
- // activated, so the rendered pixels stay identical to sindarian-x.
125
- 'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md', className), ...props, children: (0, jsx_runtime_1.jsx)(ToggleGroupContext.Provider, { value: { variant, size, spacing, arrowKeyPressed }, children: children }) }));
126
- }
127
- function ToggleGroupItem({ className, children, variant, size, onFocus, ...props }) {
128
- const context = React.useContext(ToggleGroupContext);
129
- /**
130
- * Selection follows focus, which is what `role="radio"` promises.
131
- *
132
- * With `type="single"` Radix puts the group on the ARIA radio pattern: the
133
- * root is a `radiogroup`, each item a `radio` with `aria-checked`. Under that
134
- * pattern an arrow key both moves focus and checks the item it lands on.
135
- * Radix only moves focus, so a screen-reader operator used to arrow across
136
- * "radio, not checked, 2 of 3" with nothing ever selected.
137
- *
138
- * `type="multiple"` is a `toolbar` of `aria-pressed` buttons and keeps its
139
- * current behavior, where moving focus without pressing is correct: the flag
140
- * is null there.
141
- *
142
- * Clicking the element rather than writing the value keeps a single
143
- * activation path, so Radix's own toggle and any caller `onClick` both fire
144
- * exactly as they do for a real click.
145
- */
146
- const handleFocus = (event) => {
147
- onFocus?.(event);
148
- if (context.arrowKeyPressed?.current) {
149
- event.currentTarget.click();
150
- }
151
- };
152
- return ((0, jsx_runtime_1.jsx)(ToggleGroupPrimitive.Item, { "data-slot": "toggle-group-item", "data-variant": context.variant || variant, "data-size": context.size || size, "data-spacing": context.spacing, className: (0, utils_1.cn)(toggleVariants({
153
- variant: context.variant || variant,
154
- size: context.size || size
155
- }), 'w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10', 'data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l', className), ...props, onFocus: handleFocus, children: children }));
156
- }
1
+ "use client";"use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(a,e,r,t){if(t===void 0)t=r;var n=Object.getOwnPropertyDescriptor(e,r);if(!n||("get"in n?!e.__esModule:n.writable||n.configurable)){n={enumerable:true,get:function(){return e[r]}}}Object.defineProperty(a,t,n)}):(function(a,e,r,t){if(t===void 0)t=r;a[t]=e[r]}));var __setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(a,e){Object.defineProperty(a,"default",{enumerable:true,value:e})}):function(a,e){a["default"]=e});var __importStar=this&&this.__importStar||(function(){var a=function(e){a=Object.getOwnPropertyNames||function(r){var t=[];for(var n in r)if(Object.prototype.hasOwnProperty.call(r,n))t[t.length]=n;return t};return a(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null){for(var t=a(e),n=0;n<t.length;n++)if(t[n]!=="default")__createBinding(r,e,t[n])}__setModuleDefault(r,e);return r}})();Object.defineProperty(exports,"__esModule",{value:true});exports.ToggleGroup=ToggleGroup;exports.ToggleGroupItem=ToggleGroupItem;const jsx_runtime_1=require("react/jsx-runtime");const React=__importStar(require("react"));const ToggleGroupPrimitive=__importStar(require("@radix-ui/react-toggle-group"));const class_variance_authority_1=require("class-variance-authority");const utils_1=require("../../../lib/utils");const toggleVariants=(0,class_variance_authority_1.cva)("hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",{variants:{variant:{default:"bg-transparent",outline:"border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs"},size:{default:"h-9 min-w-9 px-2",sm:"h-8 min-w-8 px-1.5",lg:"h-10 min-w-10 px-2.5"}},defaultVariants:{variant:"default",size:"default"}});const ARROW_KEYS=["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];function useArrowKeyPressed(a){const e=React.useRef(false);React.useEffect(()=>{if(!a)return;const r=n=>{if(ARROW_KEYS.includes(n.key))e.current=true};const t=()=>{e.current=false};document.addEventListener("keydown",r);document.addEventListener("keyup",t);window.addEventListener("blur",t);return()=>{document.removeEventListener("keydown",r);document.removeEventListener("keyup",t);window.removeEventListener("blur",t);e.current=false}},[a]);return a?e:null}const ToggleGroupContext=React.createContext({size:"default",variant:"default",spacing:0,arrowKeyPressed:null});function ToggleGroup({className:a,variant:e,size:r,spacing:t=0,children:n,style:o,...i}){const s=useArrowKeyPressed(i.type==="single");return(0,jsx_runtime_1.jsx)(ToggleGroupPrimitive.Root,{"data-slot":"toggle-group","data-variant":e,"data-size":r,"data-spacing":t,style:{...o,"--gap":t},className:(0,utils_1.cn)("group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md",a),...i,children:(0,jsx_runtime_1.jsx)(ToggleGroupContext.Provider,{value:{variant:e,size:r,spacing:t,arrowKeyPressed:s},children:n})})}function ToggleGroupItem({className:a,children:e,variant:r,size:t,onFocus:n,...o}){const i=React.useContext(ToggleGroupContext);const s=u=>{n?.(u);if(i.arrowKeyPressed?.current){u.currentTarget.click()}};return(0,jsx_runtime_1.jsx)(ToggleGroupPrimitive.Item,{"data-slot":"toggle-group-item","data-variant":i.variant||r,"data-size":i.size||t,"data-spacing":i.spacing,className:(0,utils_1.cn)(toggleVariants({variant:i.variant||r,size:i.size||t}),"w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10","data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l",a),...o,onFocus:s,children:e})}
@@ -1,81 +1 @@
1
- 'use client';
2
- "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
- Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.Tooltip = Tooltip;
38
- exports.TooltipTrigger = TooltipTrigger;
39
- exports.TooltipContent = TooltipContent;
40
- exports.TooltipProvider = TooltipProvider;
41
- const jsx_runtime_1 = require("react/jsx-runtime");
42
- const React = __importStar(require("react"));
43
- const TooltipPrimitive = __importStar(require("@radix-ui/react-tooltip"));
44
- const utils_1 = require("../../../lib/utils");
45
- function TooltipProvider({ delayDuration = 0, ...props }) {
46
- return ((0, jsx_runtime_1.jsx)(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration: delayDuration, ...props }));
47
- }
48
- function Tooltip({ open: _open, onOpenChange, disabled, ...props }) {
49
- const [open, setOpen] = React.useState(_open ?? false);
50
- const handleOpenChange = (open) => {
51
- if (disabled) {
52
- onOpenChange?.(false);
53
- setOpen(false);
54
- return;
55
- }
56
- setOpen(open);
57
- onOpenChange?.(open);
58
- };
59
- return ((0, jsx_runtime_1.jsx)(TooltipProvider, { children: (0, jsx_runtime_1.jsx)(TooltipPrimitive.Root, { "data-slot": "tooltip", open: open, onOpenChange: handleOpenChange, ...props }) }));
60
- }
61
- function TooltipTrigger({ ...props }) {
62
- return (0, jsx_runtime_1.jsx)(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
63
- }
64
- /**
65
- * The fill is a RAW palette step, not a theme token: `--color-shadcn-600` is a
66
- * flat hex, so an inverted tooltip stays #27272A under both themes. The ink has
67
- * to be theme-fixed too, which rules out `--primary-foreground` and
68
- * `--background`: both invert, and both land on 1.00:1 against this fill in
69
- * dark.
70
- *
71
- * base/400 was not unreadable here (5.81:1 on this fill; the 2.56:1 figure that
72
- * class earns elsewhere is against a LIGHT ground, which this is not). It moved
73
- * one step to base/300 because base/400 is banned kit-wide in
74
- * `__tests__/ink-classes.test.ts`: its only safe ground is a fixed-dark fill,
75
- * and that narrow exception had already leaked into eight slots that were not
76
- * one. base/300 reads 10.08:1 here, and keeps this line quieter than the
77
- * `text-white` a consumer puts beside it (`page-header/index.tsx:226`).
78
- */
79
- function TooltipContent({ className, sideOffset = 0, children, ...props }) {
80
- return ((0, jsx_runtime_1.jsx)(TooltipPrimitive.Portal, { children: (0, jsx_runtime_1.jsxs)(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: (0, utils_1.cn)('bg-shadcn-600 text-shadcn-300 motion-safe:animate-in fade-in-0 zoom-in-95 motion-safe:data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 rounded-md px-3 py-1.5 text-sm shadow-md', className), ...props, children: [children, (0, jsx_runtime_1.jsx)(TooltipPrimitive.Arrow, { className: "bg-shadcn-600 fill-shadcn-600 z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })] }) }));
81
- }
1
+ "use client";"use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(e,t,o,r){if(r===void 0)r=o;var i=Object.getOwnPropertyDescriptor(t,o);if(!i||("get"in i?!t.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return t[o]}}}Object.defineProperty(e,r,i)}):(function(e,t,o,r){if(r===void 0)r=o;e[r]=t[o]}));var __setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}):function(e,t){e["default"]=t});var __importStar=this&&this.__importStar||(function(){var e=function(t){e=Object.getOwnPropertyNames||function(o){var r=[];for(var i in o)if(Object.prototype.hasOwnProperty.call(o,i))r[r.length]=i;return r};return e(t)};return function(t){if(t&&t.__esModule)return t;var o={};if(t!=null){for(var r=e(t),i=0;i<r.length;i++)if(r[i]!=="default")__createBinding(o,t,r[i])}__setModuleDefault(o,t);return o}})();Object.defineProperty(exports,"__esModule",{value:true});exports.Tooltip=Tooltip;exports.TooltipTrigger=TooltipTrigger;exports.TooltipContent=TooltipContent;exports.TooltipProvider=TooltipProvider;const jsx_runtime_1=require("react/jsx-runtime");const React=__importStar(require("react"));const TooltipPrimitive=__importStar(require("@radix-ui/react-tooltip"));const utils_1=require("../../../lib/utils");function TooltipProvider({delayDuration:e=0,...t}){return(0,jsx_runtime_1.jsx)(TooltipPrimitive.Provider,{"data-slot":"tooltip-provider",delayDuration:e,...t})}function Tooltip({open:e,onOpenChange:t,disabled:o,...r}){const[i,n]=React.useState(e??false);const s=a=>{if(o){t?.(false);n(false);return}n(a);t?.(a)};return(0,jsx_runtime_1.jsx)(TooltipProvider,{children:(0,jsx_runtime_1.jsx)(TooltipPrimitive.Root,{"data-slot":"tooltip",open:i,onOpenChange:s,...r})})}function TooltipTrigger({...e}){return(0,jsx_runtime_1.jsx)(TooltipPrimitive.Trigger,{"data-slot":"tooltip-trigger",...e})}function TooltipContent({className:e,sideOffset:t=0,children:o,...r}){return(0,jsx_runtime_1.jsx)(TooltipPrimitive.Portal,{children:(0,jsx_runtime_1.jsxs)(TooltipPrimitive.Content,{"data-slot":"tooltip-content",sideOffset:t,className:(0,utils_1.cn)("bg-shadcn-600 text-shadcn-300 motion-safe:animate-in fade-in-0 zoom-in-95 motion-safe:data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 rounded-md px-3 py-1.5 text-sm shadow-md",e),...r,children:[o,(0,jsx_runtime_1.jsx)(TooltipPrimitive.Arrow,{className:"bg-shadcn-600 fill-shadcn-600 z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"})]})})}
@@ -1,20 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Blotter = Blotter;
4
- exports.BlotterRow = BlotterRow;
5
- const jsx_runtime_1 = require("react/jsx-runtime");
6
- const skeleton_1 = require("../../components/ui/skeleton");
7
- const typography_1 = require("../../lib/typography");
8
- const utils_1 = require("../../lib/utils");
9
- function Blotter({ children, className }) {
10
- return (0, jsx_runtime_1.jsx)("dl", { className: (0, utils_1.cn)('divide-border divide-y', className), children: children });
11
- }
12
- function BlotterRow({ label, value, valueClassName, className, stacked = false, loading = false }) {
13
- // The skeleton stands in for the value slot's own shape: a full-width prose
14
- // line when stacked, the mono figure's width when inline.
15
- const shownValue = loading ? ((0, jsx_runtime_1.jsx)(skeleton_1.Skeleton, { className: (0, utils_1.cn)('h-4', stacked ? 'w-full' : 'w-24') })) : (value);
16
- if (stacked) {
17
- return ((0, jsx_runtime_1.jsxs)("div", { "aria-busy": loading || undefined, className: (0, utils_1.cn)('hover:bg-body-surface space-y-1 px-2 py-2 transition-colors duration-150 ease-out', className), children: [(0, jsx_runtime_1.jsx)("dt", { className: typography_1.LABEL_VOICE_CLASS, children: label }), (0, jsx_runtime_1.jsx)("dd", { className: (0, utils_1.cn)('text-foreground text-sm break-words whitespace-pre-wrap', valueClassName), children: shownValue })] }));
18
- }
19
- return ((0, jsx_runtime_1.jsxs)("div", { "aria-busy": loading || undefined, className: (0, utils_1.cn)('hover:bg-body-surface flex items-center justify-between gap-3 px-2 py-2 transition-colors duration-150 ease-out', className), children: [(0, jsx_runtime_1.jsx)("dt", { className: typography_1.LABEL_VOICE_CLASS, children: label }), (0, jsx_runtime_1.jsx)("dd", { className: (0, utils_1.cn)('font-mono text-sm font-medium tabular-nums', valueClassName), children: shownValue })] }));
20
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Blotter=Blotter;exports.BlotterRow=BlotterRow;const jsx_runtime_1=require("react/jsx-runtime");const skeleton_1=require("../../components/ui/skeleton");const typography_1=require("../../lib/typography");const utils_1=require("../../lib/utils");function Blotter({children:e,className:s}){return(0,jsx_runtime_1.jsx)("dl",{className:(0,utils_1.cn)("divide-border divide-y",s),children:e})}function BlotterRow({label:e,value:s,valueClassName:r,className:n,stacked:o=false,loading:t=false}){const i=t?(0,jsx_runtime_1.jsx)(skeleton_1.Skeleton,{className:(0,utils_1.cn)("h-4",o?"w-full":"w-24")}):s;if(o){return(0,jsx_runtime_1.jsxs)("div",{"aria-busy":t||void 0,className:(0,utils_1.cn)("hover:bg-body-surface space-y-1 px-2 py-2 transition-colors duration-150 ease-out",n),children:[(0,jsx_runtime_1.jsx)("dt",{className:typography_1.LABEL_VOICE_CLASS,children:e}),(0,jsx_runtime_1.jsx)("dd",{className:(0,utils_1.cn)("text-foreground text-sm break-words whitespace-pre-wrap",r),children:i})]})}return(0,jsx_runtime_1.jsxs)("div",{"aria-busy":t||void 0,className:(0,utils_1.cn)("hover:bg-body-surface flex items-center justify-between gap-3 px-2 py-2 transition-colors duration-150 ease-out",n),children:[(0,jsx_runtime_1.jsx)("dt",{className:typography_1.LABEL_VOICE_CLASS,children:e}),(0,jsx_runtime_1.jsx)("dd",{className:(0,utils_1.cn)("font-mono text-sm font-medium tabular-nums",r),children:i})]})}
@@ -1,120 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bucketBand = bucketBand;
4
- exports.sumBucketTotals = sumBucketTotals;
5
- exports.AgingBuckets = AgingBuckets;
6
- const jsx_runtime_1 = require("react/jsx-runtime");
7
- /**
8
- * AgingBuckets — an ordered, exhaustive bucketed distribution (the receivables
9
- * aging schedule: current / 1–30 / 31–60 / 61–90 / 90+), each bucket carrying a
10
- * count and a money total.
11
- *
12
- * INTERNAL to `DelinquencyAging`: not re-exported from `src/domain/index.ts`,
13
- * because the port census only lists the composite. It lives here as the
14
- * distribution half of that composite.
15
- *
16
- * INVARIANT: the buckets are ordered current → oldest and are exhaustive. The
17
- * ORDER carries the information — older money is worse money — so the ordinal
18
- * position and its label are the PRIMARY cue; the band glyph + sr-only word are
19
- * the accessible reinforcement (WCAG 1.4.1 — the escalation survives grayscale
20
- * and color-vision deficiency), and the color tint is reinforcement only, never
21
- * the sole carrier of severity. The caller supplies the order; the component
22
- * never reorders, because a sorted-by-amount view would destroy the one fact the
23
- * widget exists to show.
24
- *
25
- * THIRD RAIL (money): a zero bucket renders an explicit `0` — a zero in the 90+
26
- * bucket is information ("nothing slipped that far"), never an omission. When a
27
- * grand total is shown it is summed through `money-math` integer minor units
28
- * (BigInt, at the currency's CLDR scale) — never IEEE-754 — and rendered via
29
- * `MoneyText`. A single unparseable bucket total poisons the sum to NO_VALUE
30
- * rather than silently displaying a wrong number. The SAME currency scale that
31
- * drives the sum is also the print scale handed to `MoneyText`, so the digits on
32
- * screen are the digits that were summed — the printed total can never be a
33
- * re-rounding of the computed one.
34
- *
35
- * Pure display: no directive, no interactivity, server-safe for RSC.
36
- */
37
- const lucide_react_1 = require("lucide-react");
38
- const typography_1 = require("../../lib/typography");
39
- const utils_1 = require("../../lib/utils");
40
- const figure_1 = require("../figure");
41
- const format_1 = require("../format");
42
- const money_math_1 = require("../money-math");
43
- const money_text_1 = require("../money-text");
44
- /** Band → glyph + tint + accessible word. The glyph (and the sr-only word) is
45
- * the load-bearing severity cue; the tint only reinforces it, so the
46
- * escalation survives grayscale and color-vision deficiency.
47
- *
48
- * The tint is an INK token (`-h1a`). A load-bearing glyph answers to the 3:1
49
- * floor of SC 1.4.11, and the bare fill token `--system-alert` reads 1.78:1 on
50
- * `--card` and 1.62:1 on `--body-surface` in light — the cue was invisible on
51
- * the row it escalates. */
52
- const BAND = {
53
- current: {
54
- Icon: lucide_react_1.CircleDot,
55
- tint: 'text-system-success-h1a',
56
- word: 'Em dia'
57
- },
58
- recent: {
59
- Icon: lucide_react_1.Clock,
60
- tint: 'text-muted-foreground',
61
- word: 'Vencido recentemente'
62
- },
63
- aging: {
64
- Icon: lucide_react_1.AlertTriangle,
65
- tint: 'text-system-alert-h1a',
66
- word: 'Em atraso'
67
- },
68
- overdue: { Icon: lucide_react_1.AlertOctagon, tint: 'text-credit', word: 'Vencido' }
69
- };
70
- /**
71
- * Resolve a bucket's severity band from its ORDINAL POSITION, not its amount —
72
- * the order is the information (older = worse). The first bucket is `current`;
73
- * the LAST bucket (the oldest, the 90+ tail) is always `overdue`; the middle
74
- * escalates `recent` → `aging` toward the tail. A single-bucket list reads as
75
- * `current` (there is no escalation to show). Pure: no React, unit-tested.
76
- */
77
- function bucketBand(index, count) {
78
- if (count <= 1)
79
- return 'current';
80
- if (index === 0)
81
- return 'current';
82
- if (index === count - 1)
83
- return 'overdue';
84
- // Middle buckets: the second-oldest reads `aging`, the rest `recent`.
85
- return index === count - 2 ? 'aging' : 'recent';
86
- }
87
- /**
88
- * Sum the bucket totals through integer minor units (BigInt) at `scale`, then
89
- * render losslessly to a decimal string. Returns null if ANY bucket total is
90
- * unparseable (indeterminate) — the caller renders NO_VALUE rather than a wrong
91
- * grand total. Pure: the money-math third rail, unit-tested.
92
- */
93
- function sumBucketTotals(buckets, scale) {
94
- const total = (0, money_math_1.sumMinor)(buckets.map((b) => b.total), scale);
95
- return total === null ? null : (0, money_math_1.minorToDecimal)(total, scale);
96
- }
97
- function AgingBuckets({ buckets, currency, locale, showTotal = false, labels, healthyTone = 'success', className }) {
98
- const countLabel = labels?.count ?? 'Itens';
99
- const totalLabel = labels?.total ?? 'Total';
100
- const grandTotalLabel = labels?.grandTotal ?? 'Total geral';
101
- // THIRD RAIL: one scale for BOTH the arithmetic and the print. `MoneyText`
102
- // defaults to 2 fraction digits, so leaving it unset printed JPY (scale 0)
103
- // with two decimals the currency does not have, and re-rounded the exact BHD
104
- // (scale 3) grand total `1.005` to `1.01` — a printed total that disagreed
105
- // with the total that was actually summed.
106
- const scale = currency ? (0, money_math_1.minorDigitsOf)(currency) : 2;
107
- const grandTotal = showTotal ? sumBucketTotals(buckets, scale) : null;
108
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex flex-col', className), children: [(0, jsx_runtime_1.jsx)("ul", { className: "flex flex-col", children: buckets.map((bucket, i) => {
109
- const band = bucketBand(i, buckets.length);
110
- const { Icon, word } = BAND[band];
111
- // `ink` retones ONLY the healthy band — the escalated bands keep their
112
- // alert and credit-red tints, which are the whole point of the scale.
113
- const tint = healthyTone === 'ink' && band === 'current'
114
- ? 'text-foreground'
115
- : BAND[band].tint;
116
- // Shallow merge: an unlisted band keeps its pt-BR default.
117
- const bandWord = labels?.bands?.[band] ?? word;
118
- return ((0, jsx_runtime_1.jsxs)("li", { className: "border-border flex items-center gap-3 border-b py-2.5 last:border-b-0", children: [(0, jsx_runtime_1.jsx)(Icon, { "aria-hidden": true, className: (0, utils_1.cn)('size-4 shrink-0', tint) }), (0, jsx_runtime_1.jsxs)("span", { className: "sr-only", children: [bandWord, ": "] }), (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(typography_1.LABEL_VOICE_CLASS, 'text-foreground min-w-0 flex-1'), children: bucket.label }), (0, jsx_runtime_1.jsxs)("span", { className: "flex shrink-0 flex-col items-end leading-none", children: [(0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: "text-foreground", children: (0, format_1.formatCount)(bucket.count, locale) }), (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(typography_1.LABEL_VOICE_CLASS, 'mt-1 text-xs'), children: countLabel })] }), (0, jsx_runtime_1.jsxs)("span", { className: "flex w-32 shrink-0 flex-col items-end leading-none sm:w-40", children: [(0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: (0, utils_1.cn)(band === 'overdue' && 'text-credit'), children: (0, jsx_runtime_1.jsx)(money_text_1.MoneyText, { amount: bucket.total, currency: currency, fractionDigits: scale, locale: locale, signColor: false }) }), (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(typography_1.LABEL_VOICE_CLASS, 'mt-1 text-xs'), children: totalLabel })] })] }, `${bucket.label}-${i}`));
119
- }) }), showTotal ? ((0, jsx_runtime_1.jsxs)("div", { className: "border-border flex items-center gap-3 border-t-2 pt-2.5", children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": true, className: "size-4 shrink-0" }), (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(typography_1.LABEL_VOICE_CLASS, 'text-foreground min-w-0 flex-1'), children: grandTotalLabel }), (0, jsx_runtime_1.jsx)("span", { className: "w-32 shrink-0 text-right sm:w-40", children: grandTotal === null ? ((0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: "text-muted-foreground", children: format_1.NO_VALUE })) : ((0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: "text-foreground font-semibold", children: (0, jsx_runtime_1.jsx)(money_text_1.MoneyText, { amount: grandTotal, currency: currency, fractionDigits: scale, locale: locale, signColor: false }) })) })] })) : null] }));
120
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.bucketBand=bucketBand;exports.sumBucketTotals=sumBucketTotals;exports.AgingBuckets=AgingBuckets;const jsx_runtime_1=require("react/jsx-runtime");const lucide_react_1=require("lucide-react");const typography_1=require("../../lib/typography");const utils_1=require("../../lib/utils");const figure_1=require("../figure");const format_1=require("../format");const money_math_1=require("../money-math");const money_text_1=require("../money-text");const BAND={current:{Icon:lucide_react_1.CircleDot,tint:"text-system-success-h1a",word:"Em dia"},recent:{Icon:lucide_react_1.Clock,tint:"text-muted-foreground",word:"Vencido recentemente"},aging:{Icon:lucide_react_1.AlertTriangle,tint:"text-system-alert-h1a",word:"Em atraso"},overdue:{Icon:lucide_react_1.AlertOctagon,tint:"text-credit",word:"Vencido"}};function bucketBand(t,e){if(e<=1)return"current";if(t===0)return"current";if(t===e-1)return"overdue";return t===e-2?"aging":"recent"}function sumBucketTotals(t,e){const n=(0,money_math_1.sumMinor)(t.map(s=>s.total),e);return n===null?null:(0,money_math_1.minorToDecimal)(n,e)}function AgingBuckets({buckets:t,currency:e,locale:n,showTotal:s=false,labels:o,healthyTone:d="success",className:u}){const m=o?.count??"Itens";const x=o?.total??"Total";const g=o?.grandTotal??"Total geral";const i=e?(0,money_math_1.minorDigitsOf)(e):2;const c=s?sumBucketTotals(t,i):null;return(0,jsx_runtime_1.jsxs)("div",{className:(0,utils_1.cn)("flex flex-col",u),children:[(0,jsx_runtime_1.jsx)("ul",{className:"flex flex-col",children:t.map((a,l)=>{const r=bucketBand(l,t.length);const{Icon:f,word:h}=BAND[r];const p=d==="ink"&&r==="current"?"text-foreground":BAND[r].tint;const j=o?.bands?.[r]??h;return(0,jsx_runtime_1.jsxs)("li",{className:"border-border flex items-center gap-3 border-b py-2.5 last:border-b-0",children:[(0,jsx_runtime_1.jsx)(f,{"aria-hidden":true,className:(0,utils_1.cn)("size-4 shrink-0",p)}),(0,jsx_runtime_1.jsxs)("span",{className:"sr-only",children:[j,": "]}),(0,jsx_runtime_1.jsx)("span",{className:(0,utils_1.cn)(typography_1.LABEL_VOICE_CLASS,"text-foreground min-w-0 flex-1"),children:a.label}),(0,jsx_runtime_1.jsxs)("span",{className:"flex shrink-0 flex-col items-end leading-none",children:[(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:"text-foreground",children:(0,format_1.formatCount)(a.count,n)}),(0,jsx_runtime_1.jsx)("span",{className:(0,utils_1.cn)(typography_1.LABEL_VOICE_CLASS,"mt-1 text-xs"),children:m})]}),(0,jsx_runtime_1.jsxs)("span",{className:"flex w-32 shrink-0 flex-col items-end leading-none sm:w-40",children:[(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:(0,utils_1.cn)(r==="overdue"&&"text-credit"),children:(0,jsx_runtime_1.jsx)(money_text_1.MoneyText,{amount:a.total,currency:e,fractionDigits:i,locale:n,signColor:false})}),(0,jsx_runtime_1.jsx)("span",{className:(0,utils_1.cn)(typography_1.LABEL_VOICE_CLASS,"mt-1 text-xs"),children:x})]})]},`${a.label}-${l}`)})}),s?(0,jsx_runtime_1.jsxs)("div",{className:"border-border flex items-center gap-3 border-t-2 pt-2.5",children:[(0,jsx_runtime_1.jsx)("span",{"aria-hidden":true,className:"size-4 shrink-0"}),(0,jsx_runtime_1.jsx)("span",{className:(0,utils_1.cn)(typography_1.LABEL_VOICE_CLASS,"text-foreground min-w-0 flex-1"),children:g}),(0,jsx_runtime_1.jsx)("span",{className:"w-32 shrink-0 text-right sm:w-40",children:c===null?(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:"text-muted-foreground",children:format_1.NO_VALUE}):(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:"text-foreground font-semibold",children:(0,jsx_runtime_1.jsx)(money_text_1.MoneyText,{amount:c,currency:e,fractionDigits:i,locale:n,signColor:false})})})]}):null]})}
@@ -1,222 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.delinquencyRate = delinquencyRate;
4
- exports.DelinquencyAging = DelinquencyAging;
5
- const jsx_runtime_1 = require("react/jsx-runtime");
6
- /**
7
- * DelinquencyAging — a loan/receivable delinquency surface: the ordered overdue
8
- * aging distribution PLUS the headline delinquency rate (the share of portfolio
9
- * value that is past due).
10
- *
11
- * <DelinquencyAging
12
- * currency="BRL"
13
- * locale="pt-BR"
14
- * warn={0.05}
15
- * breach={0.1}
16
- * buckets={[
17
- * { label: 'A vencer', count: 312, total: '1840500.00', overdue: false },
18
- * { label: '1–30', count: 84, total: '402300.00', overdue: true },
19
- * { label: '31–60', count: 21, total: '118900.00', overdue: true },
20
- * { label: '61–90', count: 9, total: '54200.00', overdue: true },
21
- * { label: '90+', count: 4, total: '38100.00', overdue: true }
22
- * ]}
23
- * />
24
- *
25
- * The distribution is delegated whole to `AgingBuckets`: it owns the ordered
26
- * current → 90+ schedule, the per-bucket count/total, the ordinal band cue, and
27
- * the money-math-exact grand total. This composite adds only the one fact aging
28
- * alone does not state — the delinquency RATE.
29
- *
30
- * THIRD RAIL (money): the rate is overdueTotal / portfolioTotal, and BOTH totals
31
- * are summed in integer minor units (BigInt, at the currency's CLDR scale) via
32
- * `money-math` — never an IEEE-754 sum of decimals (0.1 + 0.2 ≠ 0.3 in float, a
33
- * silent basis-point error on a portfolio). The single floating-point operation
34
- * is the FINAL division of two already-exact integers, which is the correct,
35
- * lossless-enough place for it (a ratio is not money). A zero portfolio yields a
36
- * null rate — an explicit empty readout, never a NaN. A single unparseable
37
- * bucket total poisons the rate to indeterminate rather than reporting a wrong
38
- * share.
39
- *
40
- * NON-COLOR CUE (WCAG 1.4.1): the rate band (healthy / elevated / distressed) is
41
- * resolved through the gauge's strict-edge `gaugeBand` (higher-is-worse: more
42
- * overdue is worse) and named with a glyph + an sr-only word + a tint — the tint
43
- * is reinforcement only, so the band survives grayscale and color-vision
44
- * deficiency. A distressed rate reads loud (credit-red, role='alert').
45
- *
46
- * Pure display: no directive, no interactivity, server-safe for RSC.
47
- */
48
- const lucide_react_1 = require("lucide-react");
49
- const typography_1 = require("../../lib/typography");
50
- const utils_1 = require("../../lib/utils");
51
- const figure_1 = require("../figure");
52
- const format_1 = require("../format");
53
- const money_math_1 = require("../money-math");
54
- const section_label_1 = require("../section-label");
55
- const aging_buckets_1 = require("./aging-buckets");
56
- /** Fixed-point scale for the rate division: 1e12 keeps twelve decimal places of
57
- * a 0..1 ratio, and both it and any in-range scaled quotient stay well inside
58
- * the exact-integer range of a double (2^53), so the conversion is lossless. */
59
- const RATE_PRECISION = 1000000000000n;
60
- /**
61
- * THIRD RAIL: the delinquency rate = overdue total / portfolio total, with both
62
- * totals summed through integer minor units (BigInt) at `scale`. The only float
63
- * operation is the final division of two EXACT integers — never a float sum of
64
- * decimals. A zero portfolio gives a null rate (explicit empty, no NaN); an
65
- * unparseable total poisons everything to indeterminate. Pure: unit-tested.
66
- *
67
- * Internal: exported for its unit tests, never from `src/domain/index.ts`.
68
- */
69
- function delinquencyRate(buckets, scale) {
70
- // Parse each bucket exactly once: the sums and the per-bucket SIGN check both
71
- // come off the same pass, so the two can never disagree about the same input.
72
- const parsed = buckets.map((b) => (0, money_math_1.toMinor)(b.total, scale));
73
- if (parsed.some((m) => m === null)) {
74
- return {
75
- rate: null,
76
- overdueMinor: null,
77
- totalMinor: null,
78
- indeterminate: true
79
- };
80
- }
81
- let totalMinor = 0n;
82
- let overdueMinor = 0n;
83
- let hasNegativeBucket = false;
84
- parsed.forEach((m, i) => {
85
- const minor = m;
86
- if (minor < 0n)
87
- hasNegativeBucket = true;
88
- totalMinor += minor;
89
- if (buckets[i].overdue)
90
- overdueMinor += minor;
91
- });
92
- // A NEGATIVE bucket total is parseable but not interpretable as a share of a
93
- // portfolio: overdue/total stops being bounded by 0..1 the moment a component
94
- // is negative (a -50 current band against a 100 overdue band yields "200%
95
- // delinquent"), and it can also cancel the denominator toward zero. A credit
96
- // adjustment is real data, but it is not aging data, so the honest answer is
97
- // that the RATE cannot be determined — the sums stay, since they are still
98
- // correct, and the readout takes the no-value path. Legacy divided anyway and
99
- // printed the out-of-range percentage.
100
- if (hasNegativeBucket) {
101
- return { rate: null, overdueMinor, totalMinor, indeterminate: true };
102
- }
103
- // A zero portfolio has no rate to report — null, never overdueMinor/0 (NaN).
104
- if (totalMinor === 0n) {
105
- return { rate: null, overdueMinor, totalMinor, indeterminate: false };
106
- }
107
- // The division is done as a BOUNDED BigInt ratio first, then converted once.
108
- // Converting the two totals to Number separately overflowed on a large
109
- // portfolio: past ~1.8e308 each side becomes Infinity and Infinity/Infinity is
110
- // NaN — a portfolio big enough to matter reported no rate at all. Scaling the
111
- // numerator by RATE_PRECISION keeps the quotient the size of a ratio (not the
112
- // size of the money), so the single Number() sees a value it can hold exactly.
113
- const scaled = (overdueMinor * RATE_PRECISION) / totalMinor;
114
- const rate = Number(scaled) / Number(RATE_PRECISION);
115
- // A ratio that still cannot be represented is no rate at all — the readout
116
- // shows the no-value placeholder rather than a NaN/Infinity artifact.
117
- if (!Number.isFinite(rate)) {
118
- return { rate: null, overdueMinor, totalMinor, indeterminate: false };
119
- }
120
- return { rate, overdueMinor, totalMinor, indeterminate: false };
121
- }
122
- /** Fixed-point scale for comparing the ratio against a float threshold as exact
123
- * integers. 1e18 is well past the ~1e-16 relative precision a double carries,
124
- * so the comparison is exact to the limit of the threshold value itself. */
125
- const THRESHOLD_SCALE = 10n ** 18n;
126
- /**
127
- * THIRD RAIL: `overdue / total > threshold`, decided on EXACT integers.
128
- *
129
- * The float `rate` is a TRUNCATED view of the ratio — RATE_PRECISION drops every
130
- * digit past 1e-12 — so a rate a hair ABOVE a threshold rounds down onto it, and
131
- * the strict-edge rule then reads it as the calmer band. 500000000001 /
132
- * 10000000000000 is 0.0500000000001, genuinely past a 0.05 warn edge, and
133
- * truncates to exactly 0.05, which reported "Saudável" on a portfolio that had
134
- * crossed into "Elevada". Cross-multiplying keeps the comparison in integers,
135
- * where no digit is dropped.
136
- */
137
- function ratioExceeds(overdue, total, threshold) {
138
- // A non-finite threshold is no threshold: nothing can be past it.
139
- if (!Number.isFinite(threshold))
140
- return false;
141
- // Scaling overflows to ±Infinity for a threshold that is finite but huge —
142
- // 1e300 is enough, MAX_VALUE certainly — and `BigInt(Infinity)` throws a
143
- // RangeError, mid-render, taking the surface down. Both overflow directions
144
- // have an EXACT answer, so this degrades to the right result rather than a
145
- // merely safe one: an overflowed positive threshold is one no 0..1 ratio could
146
- // ever reach (not exceeded), an overflowed negative one sits below every ratio
147
- // (always exceeded).
148
- const scaled = Math.round(threshold * Number(THRESHOLD_SCALE));
149
- if (!Number.isFinite(scaled))
150
- return scaled < 0;
151
- let scaledInt = BigInt(scaled);
152
- // A threshold FINER than one unit of the scale rounds to zero, and a zero
153
- // threshold means "anything above zero is past it" — the exact opposite of what
154
- // a tiny positive threshold asks for. 4e-19 scaled to 0, so a ratio of 1e-19
155
- // was reported as exceeding it. Clamp to one unit instead, keeping the sign, so
156
- // a sub-scale threshold behaves as the finest one this comparison supports.
157
- //
158
- // ponytail: the floor is 1e-18 (THRESHOLD_SCALE), so a threshold between 0 and
159
- // 1e-18 is treated as 1e-18 and a ratio in that sliver reads calmer than the
160
- // literal number asks. Immaterial for a delinquency ratio — a portfolio would
161
- // need ~1e18 currency units for one minor unit to land there — and the honest
162
- // alternative is exact rational threshold conversion, which buys nothing real.
163
- // An EXACT zero is left alone: every positive ratio does exceed it.
164
- if (scaledInt === 0n && threshold !== 0) {
165
- scaledInt = threshold < 0 ? -1n : 1n;
166
- }
167
- return overdue * THRESHOLD_SCALE > scaledInt * total;
168
- }
169
- /**
170
- * The rate band, resolved from the exact minor-unit ratio. Mirrors `gaugeBand`'s
171
- * higher-is-worse STRICT-edge canon (a ratio exactly ON a threshold stays in the
172
- * calmer band) rather than calling it: `gaugeBand` takes a float, and handing it
173
- * the truncated rate is precisely the defect above.
174
- */
175
- function exactBand(overdue, total, warn, breach) {
176
- if (ratioExceeds(overdue, total, breach))
177
- return 'breach';
178
- if (ratioExceeds(overdue, total, warn))
179
- return 'warn';
180
- return 'low';
181
- }
182
- /** Band → glyph + tint + accessible word. The glyph and sr-only word are the
183
- * load-bearing cue; the tint only reinforces, so the band survives grayscale
184
- * and color-vision deficiency. Mirrors the gauge's three-band canon, renamed
185
- * to the delinquency vocabulary.
186
- *
187
- * The tint is an INK token (`-h1a`), because it is painted on the `Figure`
188
- * below as well as on the glyph. The bare fill tokens read 1.78:1
189
- * (`--system-alert`) and 3.35:1 (`--system-success`) on every light surface in
190
- * the kit — the alert one under even the 3:1 floor a glyph answers to. */
191
- const RATE_BAND = {
192
- low: { Icon: lucide_react_1.ShieldCheck, tint: 'text-system-success-h1a', word: 'Saudável' },
193
- warn: { Icon: lucide_react_1.TriangleAlert, tint: 'text-system-alert-h1a', word: 'Elevada' },
194
- breach: { Icon: lucide_react_1.AlertOctagon, tint: 'text-credit', word: 'Em estresse' }
195
- };
196
- function DelinquencyAging({ buckets, currency, locale, rateLabel = 'Inadimplência', rateBandLabels, emptyLabel = 'sem carteira', indeterminateLabel = 'indeterminada', bucketLabels, warn = 0.05, breach = 0.1, showTotal = false, healthyTone = 'success', className }) {
197
- // THIRD RAIL: the rate scale and the two totals come from money-math, never
198
- // float. The division below is of two exact BigInt-derived integers.
199
- const scale = currency ? (0, money_math_1.minorDigitsOf)(currency) : 2;
200
- const { rate, overdueMinor, totalMinor, indeterminate } = delinquencyRate(buckets, scale);
201
- // The band is only meaningful when there is a rate; an empty/indeterminate
202
- // portfolio has no band to name (rendered as the explicit no-value readout).
203
- const hasRate = rate !== null;
204
- // higher-is-worse: more value past due is worse. The band comes off the EXACT
205
- // minor-unit ratio, never `rate` — that float is truncated at 1e-12 and is for
206
- // DISPLAY only (one decimal place, where the truncation cannot show).
207
- const band = hasRate && overdueMinor !== null && totalMinor !== null
208
- ? exactBand(overdueMinor, totalMinor, warn, breach)
209
- : 'low';
210
- const { Icon, word } = RATE_BAND[band];
211
- // `ink` retones ONLY the healthy band; `warn`/`breach` keep their alarm tints.
212
- const tint = healthyTone === 'ink' && band === 'low'
213
- ? 'text-foreground'
214
- : RATE_BAND[band].tint;
215
- // Shallow merge: an unlisted band keeps its pt-BR default.
216
- const bandWord = rateBandLabels?.[band] ?? word;
217
- const distressed = band === 'breach';
218
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex flex-col gap-4', className), children: [(0, jsx_runtime_1.jsxs)("header", { className: "flex items-baseline justify-between gap-3", children: [(0, jsx_runtime_1.jsx)(section_label_1.SectionLabel, { as: "span", children: rateLabel }), hasRate ? ((0, jsx_runtime_1.jsxs)("span", {
219
- // A distressed rate is a credit alarm: announced the moment it
220
- // crosses the band, so assistive tech does not lean on the tint.
221
- role: distressed ? 'alert' : undefined, className: (0, utils_1.cn)('inline-flex items-center gap-1.5', tint), children: [(0, jsx_runtime_1.jsx)(Icon, { "aria-hidden": true, className: "size-4 shrink-0" }), (0, jsx_runtime_1.jsxs)("span", { className: "sr-only", children: [bandWord, ": "] }), (0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: tint, children: (0, format_1.formatPercent)(rate, { unit: 'ratio', locale }) })] })) : ((0, jsx_runtime_1.jsxs)("span", { className: "text-muted-foreground inline-flex items-center gap-1.5", children: [(0, jsx_runtime_1.jsx)("span", { className: typography_1.LABEL_VOICE_CLASS, children: indeterminate ? indeterminateLabel : emptyLabel }), (0, jsx_runtime_1.jsx)(figure_1.Figure, { size: "row", className: "text-muted-foreground", children: format_1.NO_VALUE })] }))] }), (0, jsx_runtime_1.jsx)(aging_buckets_1.AgingBuckets, { buckets: buckets, currency: currency, locale: locale, showTotal: showTotal, labels: bucketLabels, healthyTone: healthyTone })] }));
222
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.delinquencyRate=delinquencyRate;exports.DelinquencyAging=DelinquencyAging;const jsx_runtime_1=require("react/jsx-runtime");const lucide_react_1=require("lucide-react");const typography_1=require("../../lib/typography");const utils_1=require("../../lib/utils");const figure_1=require("../figure");const format_1=require("../format");const money_math_1=require("../money-math");const section_label_1=require("../section-label");const aging_buckets_1=require("./aging-buckets");const RATE_PRECISION=1000000000000n;function delinquencyRate(r,i){const n=r.map(s=>(0,money_math_1.toMinor)(s.total,i));if(n.some(s=>s===null)){return{rate:null,overdueMinor:null,totalMinor:null,indeterminate:true}}let e=0n;let t=0n;let c=false;n.forEach((s,d)=>{const a=s;if(a<0n)c=true;e+=a;if(r[d].overdue)t+=a});if(c){return{rate:null,overdueMinor:t,totalMinor:e,indeterminate:true}}if(e===0n){return{rate:null,overdueMinor:t,totalMinor:e,indeterminate:false}}const u=t*RATE_PRECISION/e;const o=Number(u)/Number(RATE_PRECISION);if(!Number.isFinite(o)){return{rate:null,overdueMinor:t,totalMinor:e,indeterminate:false}}return{rate:o,overdueMinor:t,totalMinor:e,indeterminate:false}}const THRESHOLD_SCALE=10n**18n;function ratioExceeds(r,i,n){if(!Number.isFinite(n))return false;const e=Math.round(n*Number(THRESHOLD_SCALE));if(!Number.isFinite(e))return e<0;let t=BigInt(e);if(t===0n&&n!==0){t=n<0?-1n:1n}return r*THRESHOLD_SCALE>t*i}function exactBand(r,i,n,e){if(ratioExceeds(r,i,e))return"breach";if(ratioExceeds(r,i,n))return"warn";return"low"}const RATE_BAND={low:{Icon:lucide_react_1.ShieldCheck,tint:"text-system-success-h1a",word:"Saud\xE1vel"},warn:{Icon:lucide_react_1.TriangleAlert,tint:"text-system-alert-h1a",word:"Elevada"},breach:{Icon:lucide_react_1.AlertOctagon,tint:"text-credit",word:"Em estresse"}};function DelinquencyAging({buckets:r,currency:i,locale:n,rateLabel:e="Inadimpl\xEAncia",rateBandLabels:t,emptyLabel:c="sem carteira",indeterminateLabel:u="indeterminada",bucketLabels:o,warn:s=.05,breach:d=.1,showTotal:a=false,healthyTone:m="success",className:b}){const p=i?(0,money_math_1.minorDigitsOf)(i):2;const{rate:f,overdueMinor:x,totalMinor:g,indeterminate:N}=delinquencyRate(r,p);const h=f!==null;const l=h&&x!==null&&g!==null?exactBand(x,g,s,d):"low";const{Icon:j,word:w}=RATE_BAND[l];const _=m==="ink"&&l==="low"?"text-foreground":RATE_BAND[l].tint;const y=t?.[l]??w;const q=l==="breach";return(0,jsx_runtime_1.jsxs)("div",{className:(0,utils_1.cn)("flex flex-col gap-4",b),children:[(0,jsx_runtime_1.jsxs)("header",{className:"flex items-baseline justify-between gap-3",children:[(0,jsx_runtime_1.jsx)(section_label_1.SectionLabel,{as:"span",children:e}),h?(0,jsx_runtime_1.jsxs)("span",{role:q?"alert":void 0,className:(0,utils_1.cn)("inline-flex items-center gap-1.5",_),children:[(0,jsx_runtime_1.jsx)(j,{"aria-hidden":true,className:"size-4 shrink-0"}),(0,jsx_runtime_1.jsxs)("span",{className:"sr-only",children:[y,": "]}),(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:_,children:(0,format_1.formatPercent)(f,{unit:"ratio",locale:n})})]}):(0,jsx_runtime_1.jsxs)("span",{className:"text-muted-foreground inline-flex items-center gap-1.5",children:[(0,jsx_runtime_1.jsx)("span",{className:typography_1.LABEL_VOICE_CLASS,children:N?u:c}),(0,jsx_runtime_1.jsx)(figure_1.Figure,{size:"row",className:"text-muted-foreground",children:format_1.NO_VALUE})]})]}),(0,jsx_runtime_1.jsx)(aging_buckets_1.AgingBuckets,{buckets:r,currency:i,locale:n,showTotal:a,labels:o,healthyTone:m})]})}