@lerianstudio/sindarian-ui 1.4.0-beta.8 → 2.0.0-beta.10

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 (196) hide show
  1. package/dist/components/breadcrumb/index.d.ts.map +1 -1
  2. package/dist/components/breadcrumb/index.js +25 -1
  3. package/dist/components/card/account-card/index.d.ts.map +1 -1
  4. package/dist/components/card/account-card/index.js +5 -5
  5. package/dist/components/card/basic-card/index.d.ts.map +1 -1
  6. package/dist/components/card/basic-card/index.js +2 -2
  7. package/dist/components/card/entity-card/index.js +4 -4
  8. package/dist/components/dialog/confirmation-dialog/index.d.ts +36 -5
  9. package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  10. package/dist/components/dialog/confirmation-dialog/index.js +5 -2
  11. package/dist/components/entity-box/index.d.ts +18 -2
  12. package/dist/components/entity-box/index.d.ts.map +1 -1
  13. package/dist/components/entity-box/index.js +33 -5
  14. package/dist/components/entity-data-table/index.d.ts.map +1 -1
  15. package/dist/components/entity-data-table/index.js +1 -1
  16. package/dist/components/form/file-upload-field/index.d.ts +11 -2
  17. package/dist/components/form/file-upload-field/index.d.ts.map +1 -1
  18. package/dist/components/form/file-upload-field/index.js +8 -3
  19. package/dist/components/form/input-field/index.d.ts +41 -2
  20. package/dist/components/form/input-field/index.d.ts.map +1 -1
  21. package/dist/components/form/input-field/index.js +73 -15
  22. package/dist/components/form/password-field/index.d.ts +5 -1
  23. package/dist/components/form/password-field/index.d.ts.map +1 -1
  24. package/dist/components/form/password-field/index.js +2 -2
  25. package/dist/components/form/select-field/index.d.ts +9 -1
  26. package/dist/components/form/select-field/index.d.ts.map +1 -1
  27. package/dist/components/form/select-field/index.js +2 -2
  28. package/dist/components/page-header/index.d.ts.map +1 -1
  29. package/dist/components/page-header/index.js +2 -2
  30. package/dist/components/table/id-table-cell.d.ts +5 -1
  31. package/dist/components/table/id-table-cell.d.ts.map +1 -1
  32. package/dist/components/table/id-table-cell.js +48 -6
  33. package/dist/components/ui/autocomplete/index.d.ts +58 -6
  34. package/dist/components/ui/autocomplete/index.d.ts.map +1 -1
  35. package/dist/components/ui/autocomplete/index.js +96 -16
  36. package/dist/components/ui/badge/index.d.ts +11 -7
  37. package/dist/components/ui/badge/index.d.ts.map +1 -1
  38. package/dist/components/ui/badge/index.js +31 -9
  39. package/dist/components/ui/button/styles.css +31 -1
  40. package/dist/components/ui/calendar/index.d.ts.map +1 -1
  41. package/dist/components/ui/calendar/index.js +7 -1
  42. package/dist/components/ui/card/index.d.ts.map +1 -1
  43. package/dist/components/ui/card/index.js +1 -1
  44. package/dist/components/ui/copy-field/index.d.ts.map +1 -1
  45. package/dist/components/ui/copy-field/index.js +1 -1
  46. package/dist/components/ui/dropdown-menu/index.d.ts.map +1 -1
  47. package/dist/components/ui/dropdown-menu/index.js +4 -1
  48. package/dist/components/ui/field/index.d.ts.map +1 -1
  49. package/dist/components/ui/field/index.js +5 -2
  50. package/dist/components/ui/file-upload/index.d.ts +235 -9
  51. package/dist/components/ui/file-upload/index.d.ts.map +1 -1
  52. package/dist/components/ui/file-upload/index.js +354 -17
  53. package/dist/components/ui/form.d.ts +4 -0
  54. package/dist/components/ui/form.d.ts.map +1 -1
  55. package/dist/components/ui/form.js +53 -8
  56. package/dist/components/ui/input/styles.css +30 -2
  57. package/dist/components/ui/multiple-select/index.js +2 -2
  58. package/dist/components/ui/progress/index.d.ts +15 -1
  59. package/dist/components/ui/progress/index.d.ts.map +1 -1
  60. package/dist/components/ui/progress/index.js +25 -2
  61. package/dist/components/ui/sheet/index.d.ts.map +1 -1
  62. package/dist/components/ui/sheet/index.js +2 -2
  63. package/dist/components/ui/sidebar/index.d.ts +1 -0
  64. package/dist/components/ui/sidebar/index.d.ts.map +1 -1
  65. package/dist/components/ui/sidebar/index.js +1 -0
  66. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  67. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  68. package/dist/components/ui/sidebar/sidebar-expand-button.js +32 -2
  69. package/dist/components/ui/sidebar/sidebar-item.d.ts +1 -1
  70. package/dist/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  71. package/dist/components/ui/sidebar/sidebar-item.js +28 -4
  72. package/dist/components/ui/sidebar/sidebar-provider.d.ts +37 -0
  73. package/dist/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  74. package/dist/components/ui/sidebar/sidebar-provider.js +125 -4
  75. package/dist/components/ui/sidebar/sidebar-root.d.ts +38 -1
  76. package/dist/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  77. package/dist/components/ui/sidebar/sidebar-root.js +100 -5
  78. package/dist/components/ui/sidebar/sidebar-trigger.d.ts +18 -0
  79. package/dist/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  80. package/dist/components/ui/sidebar/sidebar-trigger.js +30 -0
  81. package/dist/components/ui/toggle-group/index.d.ts +1 -1
  82. package/dist/components/ui/toggle-group/index.d.ts.map +1 -1
  83. package/dist/components/ui/toggle-group/index.js +73 -4
  84. package/dist/components/ui/tooltip/index.d.ts +15 -0
  85. package/dist/components/ui/tooltip/index.d.ts.map +1 -1
  86. package/dist/components/ui/tooltip/index.js +16 -1
  87. package/dist/domain/blotter/index.d.ts +4 -2
  88. package/dist/domain/blotter/index.d.ts.map +1 -1
  89. package/dist/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
  90. package/dist/domain/delinquency-aging/aging-buckets.js +8 -3
  91. package/dist/domain/delinquency-aging/index.d.ts.map +1 -1
  92. package/dist/domain/delinquency-aging/index.js +8 -3
  93. package/dist/domain/key-id/index.js +1 -1
  94. package/dist/domain/status-rail/index.js +1 -1
  95. package/dist/domain/threshold-gauge/index.d.ts.map +1 -1
  96. package/dist/domain/threshold-gauge/index.js +9 -5
  97. package/dist/enterprise/stat-card/index.d.ts.map +1 -1
  98. package/dist/enterprise/stat-card/index.js +12 -4
  99. package/dist/esm/components/breadcrumb/index.d.ts.map +1 -1
  100. package/dist/esm/components/breadcrumb/index.js +25 -1
  101. package/dist/esm/components/card/account-card/index.d.ts.map +1 -1
  102. package/dist/esm/components/card/account-card/index.js +5 -5
  103. package/dist/esm/components/card/basic-card/index.d.ts.map +1 -1
  104. package/dist/esm/components/card/basic-card/index.js +2 -2
  105. package/dist/esm/components/card/entity-card/index.js +4 -4
  106. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts +36 -5
  107. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  108. package/dist/esm/components/dialog/confirmation-dialog/index.js +5 -2
  109. package/dist/esm/components/entity-box/index.d.ts +18 -2
  110. package/dist/esm/components/entity-box/index.d.ts.map +1 -1
  111. package/dist/esm/components/entity-box/index.js +30 -5
  112. package/dist/esm/components/entity-data-table/index.d.ts.map +1 -1
  113. package/dist/esm/components/entity-data-table/index.js +1 -1
  114. package/dist/esm/components/form/file-upload-field/index.d.ts +11 -2
  115. package/dist/esm/components/form/file-upload-field/index.d.ts.map +1 -1
  116. package/dist/esm/components/form/file-upload-field/index.js +8 -3
  117. package/dist/esm/components/form/input-field/index.d.ts +41 -2
  118. package/dist/esm/components/form/input-field/index.d.ts.map +1 -1
  119. package/dist/esm/components/form/input-field/index.js +73 -15
  120. package/dist/esm/components/form/password-field/index.d.ts +5 -1
  121. package/dist/esm/components/form/password-field/index.d.ts.map +1 -1
  122. package/dist/esm/components/form/password-field/index.js +2 -2
  123. package/dist/esm/components/form/select-field/index.d.ts +9 -1
  124. package/dist/esm/components/form/select-field/index.d.ts.map +1 -1
  125. package/dist/esm/components/form/select-field/index.js +2 -2
  126. package/dist/esm/components/page-header/index.d.ts.map +1 -1
  127. package/dist/esm/components/page-header/index.js +2 -2
  128. package/dist/esm/components/table/id-table-cell.d.ts +5 -1
  129. package/dist/esm/components/table/id-table-cell.d.ts.map +1 -1
  130. package/dist/esm/components/table/id-table-cell.js +48 -3
  131. package/dist/esm/components/ui/autocomplete/index.d.ts +58 -6
  132. package/dist/esm/components/ui/autocomplete/index.d.ts.map +1 -1
  133. package/dist/esm/components/ui/autocomplete/index.js +96 -16
  134. package/dist/esm/components/ui/badge/index.d.ts +11 -7
  135. package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
  136. package/dist/esm/components/ui/badge/index.js +31 -9
  137. package/dist/esm/components/ui/calendar/index.d.ts.map +1 -1
  138. package/dist/esm/components/ui/calendar/index.js +8 -2
  139. package/dist/esm/components/ui/card/index.d.ts.map +1 -1
  140. package/dist/esm/components/ui/card/index.js +1 -1
  141. package/dist/esm/components/ui/copy-field/index.d.ts.map +1 -1
  142. package/dist/esm/components/ui/copy-field/index.js +1 -1
  143. package/dist/esm/components/ui/dropdown-menu/index.d.ts.map +1 -1
  144. package/dist/esm/components/ui/dropdown-menu/index.js +4 -1
  145. package/dist/esm/components/ui/field/index.d.ts.map +1 -1
  146. package/dist/esm/components/ui/field/index.js +5 -2
  147. package/dist/esm/components/ui/file-upload/index.d.ts +235 -9
  148. package/dist/esm/components/ui/file-upload/index.d.ts.map +1 -1
  149. package/dist/esm/components/ui/file-upload/index.js +353 -17
  150. package/dist/esm/components/ui/form.d.ts +4 -0
  151. package/dist/esm/components/ui/form.d.ts.map +1 -1
  152. package/dist/esm/components/ui/form.js +53 -8
  153. package/dist/esm/components/ui/multiple-select/index.js +2 -2
  154. package/dist/esm/components/ui/progress/index.d.ts +15 -1
  155. package/dist/esm/components/ui/progress/index.d.ts.map +1 -1
  156. package/dist/esm/components/ui/progress/index.js +25 -2
  157. package/dist/esm/components/ui/sheet/index.d.ts.map +1 -1
  158. package/dist/esm/components/ui/sheet/index.js +2 -2
  159. package/dist/esm/components/ui/sidebar/index.d.ts +1 -0
  160. package/dist/esm/components/ui/sidebar/index.d.ts.map +1 -1
  161. package/dist/esm/components/ui/sidebar/index.js +1 -0
  162. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  163. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  164. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +32 -2
  165. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts +1 -1
  166. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  167. package/dist/esm/components/ui/sidebar/sidebar-item.js +28 -4
  168. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts +37 -0
  169. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  170. package/dist/esm/components/ui/sidebar/sidebar-provider.js +122 -1
  171. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts +38 -1
  172. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  173. package/dist/esm/components/ui/sidebar/sidebar-root.js +102 -7
  174. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts +18 -0
  175. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  176. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +26 -0
  177. package/dist/esm/components/ui/toggle-group/index.d.ts +1 -1
  178. package/dist/esm/components/ui/toggle-group/index.d.ts.map +1 -1
  179. package/dist/esm/components/ui/toggle-group/index.js +73 -4
  180. package/dist/esm/components/ui/tooltip/index.d.ts +15 -0
  181. package/dist/esm/components/ui/tooltip/index.d.ts.map +1 -1
  182. package/dist/esm/components/ui/tooltip/index.js +16 -1
  183. package/dist/esm/domain/blotter/index.d.ts +4 -2
  184. package/dist/esm/domain/blotter/index.d.ts.map +1 -1
  185. package/dist/esm/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
  186. package/dist/esm/domain/delinquency-aging/aging-buckets.js +8 -3
  187. package/dist/esm/domain/delinquency-aging/index.d.ts.map +1 -1
  188. package/dist/esm/domain/delinquency-aging/index.js +8 -3
  189. package/dist/esm/domain/key-id/index.js +1 -1
  190. package/dist/esm/domain/status-rail/index.js +1 -1
  191. package/dist/esm/domain/threshold-gauge/index.d.ts.map +1 -1
  192. package/dist/esm/domain/threshold-gauge/index.js +9 -5
  193. package/dist/esm/enterprise/stat-card/index.d.ts.map +1 -1
  194. package/dist/esm/enterprise/stat-card/index.js +12 -4
  195. package/dist/globals.css +101 -32
  196. package/package.json +5 -3
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Menu } from 'lucide-react';
4
+ import { cn } from '../../../lib/utils.js';
5
+ import { IconButton } from '../icon-button/index.js';
6
+ import { useSidebar } from './sidebar-provider.js';
7
+ /**
8
+ * The control that opens the mobile drawer.
9
+ *
10
+ * `md:hidden` by default because above 768px the rail is already on screen and
11
+ * a second way to reach it is a second thing to explain; a consumer that wants
12
+ * it everywhere passes its own display class.
13
+ *
14
+ * ⚠️ `aria-controls` IS SET ONLY WHILE THE DRAWER EXISTS. Radix unmounts the
15
+ * dialog content when closed, and a reference to an element that is not in the
16
+ * DOM is what axe-core reports as a CRITICAL `aria-valid-attr-value` — the same
17
+ * defect the Autocomplete panel was repaired for (console-sdk#150). A toggle
18
+ * with `aria-expanded="false"` and no `aria-controls` is complete on its own.
19
+ */
20
+ export const SidebarTrigger = ({ className, onClick, 'aria-label': ariaLabel = 'Open navigation', ...props }) => {
21
+ const { openMobile, setOpenMobile, sidebarId } = useSidebar();
22
+ return (_jsx(IconButton, { type: "button", variant: "outline", "data-slot": "sidebar-trigger", "aria-label": ariaLabel, "aria-expanded": openMobile, "aria-controls": openMobile ? sidebarId : undefined, className: cn('md:hidden', className), onClick: (event) => {
23
+ onClick?.(event);
24
+ setOpenMobile(!openMobile);
25
+ }, ...props, children: _jsx(Menu, { "aria-hidden": true }) }));
26
+ };
@@ -13,6 +13,6 @@ declare const toggleVariants: (props?: ({
13
13
  declare function ToggleGroup({ className, variant, size, spacing, children, style, ...props }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> & VariantProps<typeof toggleVariants> & {
14
14
  spacing?: number;
15
15
  }): React.JSX.Element;
16
- declare function ToggleGroupItem({ className, children, variant, size, ...props }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>): React.JSX.Element;
16
+ declare function ToggleGroupItem({ className, children, variant, size, onFocus, ...props }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>): React.JSX.Element;
17
17
  export { ToggleGroup, ToggleGroupItem };
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toggle-group/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,oBAAoB,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE;;;;GAIG;AACH,QAAA,MAAM,cAAc;;;8EAoBnB,CAAA;AAYD,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAW,EACX,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,GACvD,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,qBAwBF;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,GACvD,YAAY,CAAC,OAAO,cAAc,CAAC,qBAuBpC;AAED,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toggle-group/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,oBAAoB,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE;;;;GAIG;AACH,QAAA,MAAM,cAAc;;;8EAoBnB,CAAA;AA4DD,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAW,EACX,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,GACvD,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,qBA+BF;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,OAAO,EACP,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,GACvD,YAAY,CAAC,OAAO,cAAc,CAAC,qBAiDpC;AAED,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,CAAA"}
@@ -26,12 +26,58 @@ const toggleVariants = cva("hover:bg-muted hover:text-muted-foreground focus-vis
26
26
  size: 'default'
27
27
  }
28
28
  });
29
+ const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
30
+ /**
31
+ * Is an arrow key down right now?
32
+ *
33
+ * This is how an item tells keyboard navigation apart from a pointer press or a
34
+ * programmatic focus, and it is the seam Radix uses for the same job in its own
35
+ * `RadioGroup`. It works because `RovingFocusGroup` defers the focus move to a
36
+ * `setTimeout`: the keydown has already bubbled to `document` and set the flag
37
+ * by the time the item receives `focus`.
38
+ *
39
+ * The distinction is not cosmetic. A pointer press focuses BEFORE the click
40
+ * lands, so selecting on every focus would turn one click into
41
+ * select-then-deselect and break mouse selection outright.
42
+ *
43
+ * Returns null when disabled, so `type="multiple"` carries no flag to read.
44
+ */
45
+ function useArrowKeyPressed(enabled) {
46
+ const arrowKeyPressed = React.useRef(false);
47
+ React.useEffect(() => {
48
+ if (!enabled)
49
+ return;
50
+ const onKeyDown = (event) => {
51
+ if (ARROW_KEYS.includes(event.key))
52
+ arrowKeyPressed.current = true;
53
+ };
54
+ const onKeyUp = () => {
55
+ arrowKeyPressed.current = false;
56
+ };
57
+ document.addEventListener('keydown', onKeyDown);
58
+ document.addEventListener('keyup', onKeyUp);
59
+ window.addEventListener('blur', onKeyUp);
60
+ return () => {
61
+ document.removeEventListener('keydown', onKeyDown);
62
+ document.removeEventListener('keyup', onKeyUp);
63
+ window.removeEventListener('blur', onKeyUp);
64
+ // A group unmounted mid-keystroke never sees the keyup.
65
+ arrowKeyPressed.current = false;
66
+ };
67
+ }, [enabled]);
68
+ return enabled ? arrowKeyPressed : null;
69
+ }
29
70
  const ToggleGroupContext = React.createContext({
30
71
  size: 'default',
31
72
  variant: 'default',
32
- spacing: 0
73
+ spacing: 0,
74
+ arrowKeyPressed: null
33
75
  });
34
76
  function ToggleGroup({ className, variant, size, spacing = 0, children, style, ...props }) {
77
+ // Read, never destructured: `type` is the discriminant of the Radix props
78
+ // union, and pulling it out then spreading it back widens the union so the
79
+ // single/multiple props stop resolving.
80
+ const arrowKeyPressed = useArrowKeyPressed(props.type === 'single');
35
81
  return (_jsx(ToggleGroupPrimitive.Root, { "data-slot": "toggle-group", "data-variant": variant, "data-size": size, "data-spacing": spacing,
36
82
  // Caller style first: `--gap` is ours and must survive, but everything
37
83
  // else the caller passes has to reach the element.
@@ -39,13 +85,36 @@ function ToggleGroup({ className, variant, size, spacing = 0, children, style, .
39
85
  // Legacy carried a `data-[spacing=default]:...:shadow-xs` rule here that
40
86
  // never matched — `data-spacing` is always a number. Removed rather than
41
87
  // activated, so the rendered pixels stay identical to sindarian-x.
42
- 'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md', className), ...props, children: _jsx(ToggleGroupContext.Provider, { value: { variant, size, spacing }, children: children }) }));
88
+ 'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md', className), ...props, children: _jsx(ToggleGroupContext.Provider, { value: { variant, size, spacing, arrowKeyPressed }, children: children }) }));
43
89
  }
44
- function ToggleGroupItem({ className, children, variant, size, ...props }) {
90
+ function ToggleGroupItem({ className, children, variant, size, onFocus, ...props }) {
45
91
  const context = React.useContext(ToggleGroupContext);
92
+ /**
93
+ * Selection follows focus, which is what `role="radio"` promises.
94
+ *
95
+ * With `type="single"` Radix puts the group on the ARIA radio pattern: the
96
+ * root is a `radiogroup`, each item a `radio` with `aria-checked`. Under that
97
+ * pattern an arrow key both moves focus and checks the item it lands on.
98
+ * Radix only moves focus, so a screen-reader operator used to arrow across
99
+ * "radio, not checked, 2 of 3" with nothing ever selected.
100
+ *
101
+ * `type="multiple"` is a `toolbar` of `aria-pressed` buttons and keeps its
102
+ * current behavior, where moving focus without pressing is correct: the flag
103
+ * is null there.
104
+ *
105
+ * Clicking the element rather than writing the value keeps a single
106
+ * activation path, so Radix's own toggle and any caller `onClick` both fire
107
+ * exactly as they do for a real click.
108
+ */
109
+ const handleFocus = (event) => {
110
+ onFocus?.(event);
111
+ if (context.arrowKeyPressed?.current) {
112
+ event.currentTarget.click();
113
+ }
114
+ };
46
115
  return (_jsx(ToggleGroupPrimitive.Item, { "data-slot": "toggle-group-item", "data-variant": context.variant || variant, "data-size": context.size || size, "data-spacing": context.spacing, className: cn(toggleVariants({
47
116
  variant: context.variant || variant,
48
117
  size: context.size || size
49
- }), '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, children: children }));
118
+ }), '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 }));
50
119
  }
51
120
  export { ToggleGroup, ToggleGroupItem };
@@ -6,6 +6,21 @@ export type TooltipProps = React.ComponentProps<typeof TooltipPrimitive.Root> &
6
6
  };
7
7
  declare function Tooltip({ open: _open, onOpenChange, disabled, ...props }: TooltipProps): React.JSX.Element;
8
8
  declare function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>): React.JSX.Element;
9
+ /**
10
+ * The fill is a RAW palette step, not a theme token: `--color-shadcn-600` is a
11
+ * flat hex, so an inverted tooltip stays #27272A under both themes. The ink has
12
+ * to be theme-fixed too, which rules out `--primary-foreground` and
13
+ * `--background`: both invert, and both land on 1.00:1 against this fill in
14
+ * dark.
15
+ *
16
+ * base/400 was not unreadable here (5.81:1 on this fill; the 2.56:1 figure that
17
+ * class earns elsewhere is against a LIGHT ground, which this is not). It moved
18
+ * one step to base/300 because base/400 is banned kit-wide in
19
+ * `__tests__/ink-classes.test.ts`: its only safe ground is a fixed-dark fill,
20
+ * and that narrow exception had already leaked into eight slots that were not
21
+ * one. base/300 reads 10.08:1 here, and keeps this line quieter than the
22
+ * `text-white` a consumer puts beside it (`page-header/index.tsx:226`).
23
+ */
9
24
  declare function TooltipContent({ className, sideOffset, children, ...props }: React.ComponentProps<typeof TooltipPrimitive.Content>): React.JSX.Element;
10
25
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
11
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/tooltip/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAA;AAI3D,iBAAS,eAAe,CAAC,EACvB,aAAiB,EACjB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,qBAQxD;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,cAAc,CAC7C,OAAO,gBAAgB,CAAC,IAAI,CAC7B,GAAG;IACF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,OAAO,CAAC,EACf,IAAI,EAAE,KAAK,EACX,YAAY,EACZ,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,YAAY,qBAwBd;AAED,iBAAS,cAAc,CAAC,EACtB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAEvD;AAED,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,UAAc,EACd,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAiBvD;AAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/tooltip/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAA;AAI3D,iBAAS,eAAe,CAAC,EACvB,aAAiB,EACjB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,qBAQxD;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,cAAc,CAC7C,OAAO,gBAAgB,CAAC,IAAI,CAC7B,GAAG;IACF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,OAAO,CAAC,EACf,IAAI,EAAE,KAAK,EACX,YAAY,EACZ,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,YAAY,qBAwBd;AAED,iBAAS,cAAc,CAAC,EACtB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAEvD;AAED;;;;;;;;;;;;;;GAcG;AACH,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,UAAc,EACd,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAiBvD;AAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
@@ -22,7 +22,22 @@ function Tooltip({ open: _open, onOpenChange, disabled, ...props }) {
22
22
  function TooltipTrigger({ ...props }) {
23
23
  return _jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
24
24
  }
25
+ /**
26
+ * The fill is a RAW palette step, not a theme token: `--color-shadcn-600` is a
27
+ * flat hex, so an inverted tooltip stays #27272A under both themes. The ink has
28
+ * to be theme-fixed too, which rules out `--primary-foreground` and
29
+ * `--background`: both invert, and both land on 1.00:1 against this fill in
30
+ * dark.
31
+ *
32
+ * base/400 was not unreadable here (5.81:1 on this fill; the 2.56:1 figure that
33
+ * class earns elsewhere is against a LIGHT ground, which this is not). It moved
34
+ * one step to base/300 because base/400 is banned kit-wide in
35
+ * `__tests__/ink-classes.test.ts`: its only safe ground is a fixed-dark fill,
36
+ * and that narrow exception had already leaked into eight slots that were not
37
+ * one. base/300 reads 10.08:1 here, and keeps this line quieter than the
38
+ * `text-white` a consumer puts beside it (`page-header/index.tsx:226`).
39
+ */
25
40
  function TooltipContent({ className, sideOffset = 0, children, ...props }) {
26
- return (_jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: cn('bg-shadcn-600 text-shadcn-400 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, _jsx(TooltipPrimitive.Arrow, { className: "bg-shadcn-600 fill-shadcn-600 z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })] }) }));
41
+ return (_jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: 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, _jsx(TooltipPrimitive.Arrow, { className: "bg-shadcn-600 fill-shadcn-600 z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })] }) }));
27
42
  }
28
43
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -5,8 +5,10 @@
5
5
  * — no zebra fills. Each row: a quiet sentence-case sans label on the left, a mono
6
6
  * `tabular-nums` value on the right, `hover:bg-body-surface` as the quiet row
7
7
  * affordance (the recessed page surface, one step behind `bg-card`, in both
8
- * themes). Escalate the value color (`text-credit`, `text-system-alert`) only
9
- * when a metric crosses a threshold.
8
+ * themes). Escalate the value color (`text-credit`, `text-system-alert-h1a`)
9
+ * only when a metric crosses a threshold — the INK tokens, never the bare
10
+ * `text-system-*` fills, which are picked to carry white and read as low as
11
+ * 1.78:1 on this surface in light.
10
12
  *
11
13
  * <Blotter>
12
14
  * <BlotterRow label="Resolved on time" value="128" />
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/blotter/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,YAAY,+BAE5D;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;IAChB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,cAAc,EACd,SAAS,EACT,OAAe,EACf,OAAe,EAChB,EAAE,eAAe,+BAkDjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/blotter/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,YAAY,+BAE5D;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;IAChB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,cAAc,EACd,SAAS,EACT,OAAe,EACf,OAAe,EAChB,EAAE,eAAe,+BAkDjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"aging-buckets.d.ts","sourceRoot":"","sources":["../../../../src/domain/delinquency-aging/aging-buckets.tsx"],"names":[],"mappings":"AAyCA,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAA;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1C,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;oFACgF;IAChF,WAAW,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA2BD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAMlE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAMf;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAiB,EACjB,MAAM,EACN,WAAuB,EACvB,SAAS,EACV,EAAE,iBAAiB,+BAkHnB"}
1
+ {"version":3,"file":"aging-buckets.d.ts","sourceRoot":"","sources":["../../../../src/domain/delinquency-aging/aging-buckets.tsx"],"names":[],"mappings":"AAyCA,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAA;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1C,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;oFACgF;IAChF,WAAW,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgCD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAMlE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAMf;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAiB,EACjB,MAAM,EACN,WAAuB,EACvB,SAAS,EACV,EAAE,iBAAiB,+BAkHnB"}
@@ -38,11 +38,16 @@ import { minorDigitsOf, minorToDecimal, sumMinor } from '../money-math.js';
38
38
  import { MoneyText } from '../money-text/index.js';
39
39
  /** Band → glyph + tint + accessible word. The glyph (and the sr-only word) is
40
40
  * the load-bearing severity cue; the tint only reinforces it, so the
41
- * escalation survives grayscale and color-vision deficiency. */
41
+ * escalation survives grayscale and color-vision deficiency.
42
+ *
43
+ * The tint is an INK token (`-h1a`). A load-bearing glyph answers to the 3:1
44
+ * floor of SC 1.4.11, and the bare fill token `--system-alert` reads 1.78:1 on
45
+ * `--card` and 1.62:1 on `--body-surface` in light — the cue was invisible on
46
+ * the row it escalates. */
42
47
  const BAND = {
43
48
  current: {
44
49
  Icon: CircleDot,
45
- tint: 'text-system-success',
50
+ tint: 'text-system-success-h1a',
46
51
  word: 'Em dia'
47
52
  },
48
53
  recent: {
@@ -52,7 +57,7 @@ const BAND = {
52
57
  },
53
58
  aging: {
54
59
  Icon: AlertTriangle,
55
- tint: 'text-system-alert',
60
+ tint: 'text-system-alert-h1a',
56
61
  word: 'Em atraso'
57
62
  },
58
63
  overdue: { Icon: AlertOctagon, tint: 'text-credit', word: 'Vencido' }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/delinquency-aging/index.tsx"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAKtE,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAOpE;;wEAEwE;AACxE,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;oEACoE;AACpE,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,iFAAiF;IACjF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,6EAA6E;IAC7E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;0EAEsE;IACtE,aAAa,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,iBAAiB,EAAE,EAC5B,KAAK,EAAE,MAAM,GACZ,eAAe,CAuDjB;AAoFD,MAAM,WAAW,qBAAqB;IACpC;yEACqE;IACrE,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;sBAGkB;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;oBAEgB;IAChB,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC;;;mDAG+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;yEACqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAA2B,EAC3B,cAAc,EACd,UAA2B,EAC3B,kBAAoC,EACpC,YAAY,EACZ,IAAW,EACX,MAAY,EACZ,SAAiB,EACjB,WAAuB,EACvB,SAAS,EACV,EAAE,qBAAqB,+BA6EvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/delinquency-aging/index.tsx"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAKtE,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAOpE;;wEAEwE;AACxE,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;oEACoE;AACpE,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,iFAAiF;IACjF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,6EAA6E;IAC7E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;0EAEsE;IACtE,aAAa,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,iBAAiB,EAAE,EAC5B,KAAK,EAAE,MAAM,GACZ,eAAe,CAuDjB;AAyFD,MAAM,WAAW,qBAAqB;IACpC;yEACqE;IACrE,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;sBAGkB;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;oBAEgB;IAChB,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC;;;mDAG+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;yEACqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAA2B,EAC3B,cAAc,EACd,UAA2B,EAC3B,kBAAoC,EACpC,YAAY,EACZ,IAAW,EACX,MAAY,EACZ,SAAiB,EACjB,WAAuB,EACvB,SAAS,EACV,EAAE,qBAAqB,+BA6EvB"}
@@ -178,10 +178,15 @@ function exactBand(overdue, total, warn, breach) {
178
178
  /** Band → glyph + tint + accessible word. The glyph and sr-only word are the
179
179
  * load-bearing cue; the tint only reinforces, so the band survives grayscale
180
180
  * and color-vision deficiency. Mirrors the gauge's three-band canon, renamed
181
- * to the delinquency vocabulary. */
181
+ * to the delinquency vocabulary.
182
+ *
183
+ * The tint is an INK token (`-h1a`), because it is painted on the `Figure`
184
+ * below as well as on the glyph. The bare fill tokens read 1.78:1
185
+ * (`--system-alert`) and 3.35:1 (`--system-success`) on every light surface in
186
+ * the kit — the alert one under even the 3:1 floor a glyph answers to. */
182
187
  const RATE_BAND = {
183
- low: { Icon: ShieldCheck, tint: 'text-system-success', word: 'Saudável' },
184
- warn: { Icon: TriangleAlert, tint: 'text-system-alert', word: 'Elevada' },
188
+ low: { Icon: ShieldCheck, tint: 'text-system-success-h1a', word: 'Saudável' },
189
+ warn: { Icon: TriangleAlert, tint: 'text-system-alert-h1a', word: 'Elevada' },
185
190
  breach: { Icon: AlertOctagon, tint: 'text-credit', word: 'Em estresse' }
186
191
  };
187
192
  export 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 }) {
@@ -165,5 +165,5 @@ function CopyValue({ value }) {
165
165
  setCopied(false);
166
166
  });
167
167
  };
168
- return (_jsx("button", { type: "button", onClick: copy, "aria-label": copied ? 'Copiado para a área de transferência' : 'Copiar valor', className: "text-muted-foreground hover:text-foreground focus:ring-ring inline-flex size-5 shrink-0 items-center justify-center rounded-sm transition-colors duration-150 ease-out focus:ring-2 focus:outline-none", children: copied ? (_jsx(Check, { "aria-hidden": true, className: "text-system-success size-3" })) : (_jsx(Copy, { "aria-hidden": true, className: "size-3" })) }));
168
+ return (_jsx("button", { type: "button", onClick: copy, "aria-label": copied ? 'Copiado para a área de transferência' : 'Copiar valor', className: "text-muted-foreground hover:text-foreground focus:ring-ring inline-flex size-5 shrink-0 items-center justify-center rounded-sm transition-colors duration-150 ease-out focus:ring-2 focus:outline-none", children: copied ? (_jsx(Check, { "aria-hidden": true, className: "text-system-success-h1a size-3" })) : (_jsx(Copy, { "aria-hidden": true, className: "size-3" })) }));
169
169
  }
@@ -45,7 +45,7 @@ export function StatusRail({ lead, items = [], chips = [], className }) {
45
45
  // Tiny mono token: raised a hair off the sunken tape by the
46
46
  // card surface + whisper shadow.
47
47
  'inline-flex items-center gap-1 rounded-sm border px-1.5 py-0.5 shadow-sm', chip.alarm
48
- ? 'border-destructive/40 bg-destructive/10 text-destructive'
48
+ ? 'border-destructive/40 bg-destructive/10 text-system-error-h1a'
49
49
  : 'border-border bg-card text-foreground'), children: [chip.alarm ? (_jsxs(_Fragment, { children: [_jsx(TriangleAlert, { "aria-hidden": true, className: "size-3" }), _jsx("span", { className: "sr-only", children: "(alarme)" })] })) : null, chip.value] })] }, chip.id ?? i))) })) : null] }));
50
50
  }
51
51
  /** A tape item preceded by a separator dot when it is not the first token. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/threshold-gauge/index.tsx"],"names":[],"mappings":"AAiDA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEjD;gFACgF;AAChF,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,CAAA;AAEjE;;gDAEgD;AAChD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAA;AAEjE;;;;wEAIwE;AACxE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE/C,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC;oEACgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb;;;;iDAI6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,qEAAqE;IACrE,SAAS,EAAE,cAAc,CAAA;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;uCAImC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;0EAIsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,cAAc,GACxB,SAAS,CAUX;AA+CD,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,YAAY,EACZ,GAAO,EACP,GAAG,EACH,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,MAAkB,EAClB,QAAQ,EACR,MAAM,EACN,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACV,EAAE,mBAAmB,+BA8ErB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/domain/threshold-gauge/index.tsx"],"names":[],"mappings":"AAiDA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEjD;gFACgF;AAChF,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,CAAA;AAEjE;;gDAEgD;AAChD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAA;AAEjE;;;;wEAIwE;AACxE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE/C,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC;oEACgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb;;;;iDAI6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,qEAAqE;IACrE,SAAS,EAAE,cAAc,CAAA;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;uCAImC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;0EAIsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAuCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,cAAc,GACxB,SAAS,CAUX;AA+CD,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,YAAY,EACZ,GAAO,EACP,GAAG,EACH,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,MAAkB,EAClB,QAAQ,EACR,MAAM,EACN,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACV,EAAE,mBAAmB,+BA8ErB"}
@@ -51,22 +51,26 @@ import { MoneyText } from '../money-text/index.js';
51
51
  const BAND = {
52
52
  low: {
53
53
  Icon: ShieldCheck,
54
- tint: 'text-system-success',
54
+ tint: 'text-system-success-h1a',
55
55
  word: 'Dentro do limite'
56
56
  },
57
57
  warn: {
58
58
  Icon: TriangleAlert,
59
- tint: 'text-system-alert',
59
+ tint: 'text-system-alert-h1a',
60
60
  word: 'Próximo do limite'
61
61
  },
62
62
  breach: {
63
63
  Icon: OctagonX,
64
- tint: 'text-destructive',
64
+ tint: 'text-system-error-h1a',
65
65
  word: 'Limite ultrapassado'
66
66
  }
67
67
  };
68
- /** Track fill tint per band — kept distinct from the glyph tint so the bar can
69
- * use the softer wash while the glyph carries the full tint. */
68
+ /** Track fill tint per band, and the reason it is a SEPARATE map from the
69
+ * tint above: these are the fill tokens, and a fill answers to no text floor.
70
+ * The tint above is painted on the band glyph AND on the `Figure`, so it has
71
+ * to be the ink family. Light `--system-alert` is #EAB308, about 1.9:1 on
72
+ * white, and `--system-success` about 3.3:1 — both were readable only as a
73
+ * bar wash, never as the number the reader is here to read. */
70
74
  const BAND_FILL = {
71
75
  low: 'bg-system-success',
72
76
  warn: 'bg-system-alert',
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/stat-card/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAQtC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAoB5E,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,KAAK,EAAE,SAAS,CAAA;IAChB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,uDAAuD;IACvD,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,sDAAsD;IACtD,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;IAC7D,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yCAAyC;IACzC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAwED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,KAAK,EACL,IAAgB,EAChB,KAAK,EACL,QAAkB,EAClB,IAAI,EACJ,SAAS,EACV,EAAE,aAAa,+BAgCf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/stat-card/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAQtC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AA4B5E,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,KAAK,EAAE,SAAS,CAAA;IAChB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,uDAAuD;IACvD,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,sDAAsD;IACtD,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;IAC7D,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yCAAyC;IACzC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAwED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,KAAK,EACL,IAAgB,EAChB,KAAK,EACL,QAAkB,EAClB,IAAI,EACJ,SAAS,EACV,EAAE,aAAa,+BAgCf"}
@@ -5,12 +5,20 @@ import { LedgerPanel } from '../../domain/ledger-sheet/index.js';
5
5
  import { SectionLabel } from '../../domain/section-label/index.js';
6
6
  import { cn } from '../../lib/utils.js';
7
7
  /** Value/delta color per tone. `default` keeps the high-contrast foreground;
8
- * the rest escalate to a semantic theme token that tracks light/dark. */
8
+ * the rest escalate to a semantic theme token that tracks light/dark.
9
+ *
10
+ * All three escalations read the `-h1a` family, not a mix of `-h1a` and
11
+ * `-text`. `--system-*-text` is the ink of a tinted PILL, measured against its
12
+ * own surface; this card paints on the panel, and `-h1a` is the family gated
13
+ * against `--card` and `--background` in `__tests__/tokens-contract.test.ts`.
14
+ * The two differ by one palette step in dark, so a mixed table gave the three
15
+ * deltas three different weights on the same surface for no reason a reader
16
+ * could see. */
9
17
  const TONE_VALUE = {
10
18
  default: 'text-foreground',
11
- success: 'text-system-success-text',
12
- warning: 'text-system-alert-text',
13
- destructive: 'text-destructive'
19
+ success: 'text-system-success-h1a',
20
+ warning: 'text-system-alert-h1a',
21
+ destructive: 'text-system-error-h1a'
14
22
  };
15
23
  /** Trend stroke color per tone. Resolved through the `--color-*` wrappers (the
16
24
  * raw `--chart-N` tokens are bare HSL triples, not usable colors). */
package/dist/globals.css CHANGED
@@ -214,6 +214,28 @@
214
214
  :root {
215
215
  color-scheme: light; /* native widgets (form controls, scrollbars) follow the theme */
216
216
 
217
+ /*
218
+ Sidebar geometry. These were literals inside SidebarRoot's cva
219
+ (`w-[244px]` / `w-[72px]`), which a consumer could only override by
220
+ winning a specificity argument with `cn`. As custom properties the
221
+ default still ships with this sheet.
222
+
223
+ TWO places to re-point them, and only these two:
224
+ - on the rail, via `className="[--sidebar-width:280px]"`. SidebarRoot
225
+ copies exactly these two arbitrary-property classes onto the mobile
226
+ drawer's own element, so one class moves the rail AND the drawer.
227
+ - on `:root` or `html`, which every layout inherits from.
228
+
229
+ NOT on a React-tree wrapper above the rail: that reaches the rail, but
230
+ the mobile drawer is portalled into document.body, and custom properties
231
+ inherit down the DOM tree. A wrapper is not an ancestor of the portal;
232
+ `:root` is.
233
+
234
+ They are theme-independent on purpose: a rail is not wider in the dark.
235
+ */
236
+ --sidebar-width: 244px;
237
+ --sidebar-width-collapsed: 72px;
238
+
217
239
  /* Application tokens (from Figma ring-tokens) */
218
240
  --body-surface: 240 5% 96%; /* base/100 = #F4F4F5 */
219
241
  /*
@@ -294,7 +316,26 @@
294
316
  here claimed 4.4:1 was acceptable "on the shadcn-100 field", which named
295
317
  a fill the component never paints. */
296
318
  --input-placeholder: 240 4% 45%; /* one notch off base/500: #6E6E77, AA on body-surface */
297
- --ring: 240 5% 65%; /* focus ring */
319
+ /*
320
+ Focus ring. base/400 read 2.55:1 on white and 2.33:1 on --body-surface,
321
+ under the 3:1 floor a focus indicator answers to (SC 1.4.11), and this is
322
+ the ring every input, button and trigger in the kit paints: the wrapper
323
+ border on :focus-within, and the ring itself at ring-offset-0, both of
324
+ which touch the page ground directly. base/500 clears it on every light
325
+ ground: 4.84:1 on white (which is also --card and --popover here) and
326
+ 4.40:1 on --body-surface.
327
+
328
+ It does NOT serve both themes. On the dark container surface base/500
329
+ measures 2.16:1, so .dark keeps the old channel as its own declaration,
330
+ where it reads 5.81:1 on --background and 4.08:1 on --card.
331
+
332
+ No single value clears both themes with margin, and none is a palette
333
+ step: the best one channel does is an off-scale 240 5% 57%, which clears
334
+ 3:1 on all four grounds but by 0.04 on two of them. The per-theme pair
335
+ sits at 4.4+ light and 4.0+ dark, each half gated in
336
+ `__tests__/tokens-contract.test.ts`.
337
+ */
338
+ --ring: 240 4% 46%; /* base/500 = #71717A */
298
339
  --radius: 0.5rem;
299
340
 
300
341
  /* Accent variants */
@@ -425,6 +466,10 @@
425
466
  dark field that is already only 5.8:1, and going lighter here means
426
467
  darker, which would push the hint under the AA floor. */
427
468
  --input-placeholder: 240 5% 80%; /* between base/400 and base/300: #C9C9CF, AA on card (6.3:1); base/400 read 4.07:1 there */
469
+ /* Held at base/400, which light had to leave: on this ground the two
470
+ directions disagree. base/400 reads 5.81:1 on --background and 4.08:1 on
471
+ --card here, while light's base/500 would read 2.16:1 on --card. */
472
+ --ring: 240 5% 65%; /* base/400 = #A1A1AA */
428
473
  --primary: 240 5% 96%; /* base/100 = #F4F4F5 */
429
474
  --primary-foreground: 240 4% 16%; /* base/800 = #27272A */
430
475
  --secondary: 240 4% 16%; /* base/800 = #27272A */
@@ -518,7 +563,7 @@
518
563
  }
519
564
  }
520
565
 
521
- /* Sonner toast overrides — solid bold backgrounds (Radix parity) */
566
+ /* Sonner toast overrides — tinted surfaces from the system token families */
522
567
  [data-sonner-toaster] {
523
568
  --width: 420px;
524
569
  pointer-events: auto !important;
@@ -536,41 +581,41 @@
536
581
  }
537
582
 
538
583
  /*
539
- Type fills come from the system token families, so a toast themes with the
540
- rest of the app. All three coloured types take ONE ink, --accent-foreground:
541
- a solid system fill is bright enough to need near-black ink in BOTH themes,
542
- and that token is the only one in this sheet that is near-black in both.
543
-
544
- It replaced the per-family reasoning that stood here, which routed success
545
- and error through --primary-foreground because that token inverts (white in
546
- light, base/800 in dark). Inverting was the bug: white ink on the LIGHT
547
- fills measured 3.35:1 on --system-success and 3.78:1 on --system-error,
548
- both under AA, and no token value can fix that from the white side — the
549
- light green/600 and red/500 fills sit mid-luminance, so white caps at ~3.8
550
- while near-black reaches 5.9 and 5.3. Ratios now, ink over fill:
551
- light 5.93 / 5.25 / 11.17 and dark 11.39 / 7.23 / 13.00
552
- (success / error / warning). The dark pairs were already passing at
553
- 8.51 / 5.41 / 13.00 and only gained. `toast ink` in
554
- src/__tests__/tokens-contract.test.ts recomputes all six from these
555
- declarations, so the next token edit that drops a pair under 4.5 fails
556
- instead of shipping.
584
+ Each coloured type paints the `surface` + `text` + `border` trio of its own
585
+ family — the pairing every other tinted component in the kit already uses
586
+ (`components/ui/badge/index.tsx`, `enterprise/alert-banner/index.tsx`).
587
+ `surface` is the only slot in a system family built to sit BEHIND content: it
588
+ darkens on the dark canvas, while `base` and `h1a` are fill and ink slots
589
+ that INVERT between themes (`--system-success-h1a` is #166534 in light and
590
+ #BBF7D0 in dark). Grounding toast text on either of those forces a different
591
+ ink per theme, and the toast stops tracking the family it names.
592
+
593
+ Ink over ground, light / dark: success 6.81 / 10.62, error 7.60 / 8.51,
594
+ warning 6.62 / 11.70 — every half clear of the 4.5 floor by more than two
595
+ points. `system text tokens` in `src/__tests__/tokens-contract.test.ts`
596
+ already measures this pair for all five families, so the toast is covered by
597
+ the gate that guards the pills rather than by a rule written for it alone;
598
+ `sonner toast ink` there reads whichever pair these rules declare.
599
+
600
+ `info` stays neutral on `--card`: an informational toast is the unstyled
601
+ case, not a fourth colour.
557
602
  */
558
603
  [data-sonner-toast][data-type='success'] {
559
- --normal-bg: hsl(var(--system-success));
560
- --normal-text: hsl(var(--accent-foreground));
561
- --normal-border: transparent;
604
+ --normal-bg: hsl(var(--system-success-surface));
605
+ --normal-text: hsl(var(--system-success-text));
606
+ --normal-border: hsl(var(--system-success-border));
562
607
  }
563
608
 
564
609
  [data-sonner-toast][data-type='error'] {
565
- --normal-bg: hsl(var(--system-error));
566
- --normal-text: hsl(var(--accent-foreground));
567
- --normal-border: transparent;
610
+ --normal-bg: hsl(var(--system-error-surface));
611
+ --normal-text: hsl(var(--system-error-text));
612
+ --normal-border: hsl(var(--system-error-border));
568
613
  }
569
614
 
570
615
  [data-sonner-toast][data-type='warning'] {
571
- --normal-bg: hsl(var(--system-alert));
572
- --normal-text: hsl(var(--accent-foreground));
573
- --normal-border: transparent;
616
+ --normal-bg: hsl(var(--system-alert-surface));
617
+ --normal-text: hsl(var(--system-alert-text));
618
+ --normal-border: hsl(var(--system-alert-border));
574
619
  }
575
620
 
576
621
  [data-sonner-toast][data-type='info'] {
@@ -579,8 +624,32 @@
579
624
  --normal-border: hsl(var(--border));
580
625
  }
581
626
 
582
- [data-sonner-toast] [data-title] {
583
- font-weight: 600;
627
+ /*
628
+ The title outranks the description, and both rules have to WIN the cascade
629
+ for that to mean anything. Sonner ships
630
+ `[data-sonner-toast][data-styled='true'] [data-title]` at font-weight 500 and
631
+ its description twin at 400 — both (0,3,0), both injected at runtime.
632
+ The title rule here was a plain `[data-sonner-toast] [data-title]` (0,2,0):
633
+ it declared 600 and rendered at 500, losing outright, while the description
634
+ carried `!important` and rendered at 600. The hierarchy came out inverted on
635
+ every toast in the kit, the long line heavier than the label naming it.
636
+
637
+ Both now take the compound selector plus !important — the shape the
638
+ close-button rules below already use against this same stylesheet, and for
639
+ the same reason: source order cannot settle a tie with a sheet that is
640
+ injected at runtime.
641
+
642
+ The description returns to 400. It is the running text of a toast, and 14px
643
+ semibold across a full sentence reads as emphasis with nothing left to
644
+ emphasise; the family ink already carries the severity. Its `color` override
645
+ keeps !important on its own merits — sonner hardcodes #3f3f3f there, plus a
646
+ dark-theme rule of its own on top.
647
+
648
+ `toast text weights` in src/__tests__/tokens-contract.test.ts holds the order
649
+ and the two properties that let it apply.
650
+ */
651
+ [data-sonner-toast][data-styled='true'] [data-title] {
652
+ font-weight: 600 !important;
584
653
  font-size: 0.875rem;
585
654
  line-height: 1.25rem;
586
655
  }
@@ -588,7 +657,7 @@
588
657
  [data-sonner-toast] [data-description],
589
658
  [data-sonner-toast][data-styled='true'] [data-description] {
590
659
  font-size: 0.875rem;
591
- font-weight: 600 !important;
660
+ font-weight: 400 !important;
592
661
  line-height: 1.25rem;
593
662
  color: var(--normal-text) !important;
594
663
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerianstudio/sindarian-ui",
3
- "version": "1.4.0-beta.8",
3
+ "version": "2.0.0-beta.10",
4
4
  "description": "Sindarian UI - A UI library for Midaz Console",
5
5
  "license": "ISC",
6
6
  "author": {
@@ -43,12 +43,14 @@
43
43
  "build:esm": "tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json --resolve-full-paths && copyfiles -u 1 \"src/**/*.cjs\" \"src/**/*.d.cts\" \"src/**/*.json\" dist/esm && node -e \"require('fs').writeFileSync('dist/esm/package.json',JSON.stringify({type:'module'}))\" && node scripts/check-esm-output.mjs",
44
44
  "copy:assets": "copyfiles -f src/public/**/* dist/public",
45
45
  "copy:styles": "copyfiles -u 1 src/**/*.css dist",
46
- "lint": "eslint . --fix",
46
+ "lint": "eslint .",
47
+ "lint:fix": "eslint . --fix",
47
48
  "storybook": "storybook dev -p 6007",
48
49
  "build-storybook": "storybook build",
49
50
  "test": "jest",
50
51
  "test:e2e": "exit 0",
51
- "test:cov": "jest --coverage"
52
+ "test:cov": "jest --coverage",
53
+ "measure:input-shrink": "node scripts/measure-input-shrink.mjs"
52
54
  },
53
55
  "dependencies": {
54
56
  "@radix-ui/react-accordion": "^1.2.20",