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

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 (129) hide show
  1. package/dist/components/card/account-card/index.d.ts.map +1 -1
  2. package/dist/components/card/account-card/index.js +1 -1
  3. package/dist/components/card/entity-card/index.js +3 -3
  4. package/dist/components/dialog/confirmation-dialog/index.d.ts +36 -5
  5. package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  6. package/dist/components/dialog/confirmation-dialog/index.js +2 -2
  7. package/dist/components/entity-box/index.js +1 -1
  8. package/dist/components/entity-data-table/index.d.ts.map +1 -1
  9. package/dist/components/entity-data-table/index.js +1 -1
  10. package/dist/components/form/file-upload-field/index.d.ts +11 -2
  11. package/dist/components/form/file-upload-field/index.d.ts.map +1 -1
  12. package/dist/components/form/file-upload-field/index.js +8 -3
  13. package/dist/components/form/input-field/index.d.ts +41 -2
  14. package/dist/components/form/input-field/index.d.ts.map +1 -1
  15. package/dist/components/form/input-field/index.js +73 -15
  16. package/dist/components/form/select-field/index.d.ts +9 -1
  17. package/dist/components/form/select-field/index.d.ts.map +1 -1
  18. package/dist/components/form/select-field/index.js +2 -2
  19. package/dist/components/page-header/index.d.ts.map +1 -1
  20. package/dist/components/page-header/index.js +2 -2
  21. package/dist/components/ui/autocomplete/index.d.ts +34 -6
  22. package/dist/components/ui/autocomplete/index.d.ts.map +1 -1
  23. package/dist/components/ui/autocomplete/index.js +72 -16
  24. package/dist/components/ui/badge/index.d.ts.map +1 -1
  25. package/dist/components/ui/badge/index.js +11 -1
  26. package/dist/components/ui/button/styles.css +31 -1
  27. package/dist/components/ui/calendar/index.d.ts.map +1 -1
  28. package/dist/components/ui/calendar/index.js +7 -1
  29. package/dist/components/ui/card/index.d.ts.map +1 -1
  30. package/dist/components/ui/card/index.js +1 -1
  31. package/dist/components/ui/dropdown-menu/index.d.ts.map +1 -1
  32. package/dist/components/ui/dropdown-menu/index.js +4 -1
  33. package/dist/components/ui/field/index.d.ts.map +1 -1
  34. package/dist/components/ui/field/index.js +5 -2
  35. package/dist/components/ui/file-upload/index.d.ts +76 -9
  36. package/dist/components/ui/file-upload/index.d.ts.map +1 -1
  37. package/dist/components/ui/file-upload/index.js +47 -12
  38. package/dist/components/ui/form.d.ts +4 -0
  39. package/dist/components/ui/form.d.ts.map +1 -1
  40. package/dist/components/ui/form.js +53 -8
  41. package/dist/components/ui/multiple-select/index.js +2 -2
  42. package/dist/components/ui/progress/index.d.ts +15 -1
  43. package/dist/components/ui/progress/index.d.ts.map +1 -1
  44. package/dist/components/ui/progress/index.js +25 -2
  45. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  46. package/dist/components/ui/sidebar/sidebar-expand-button.js +17 -1
  47. package/dist/components/ui/toggle-group/index.d.ts +1 -1
  48. package/dist/components/ui/toggle-group/index.d.ts.map +1 -1
  49. package/dist/components/ui/toggle-group/index.js +73 -4
  50. package/dist/components/ui/tooltip/index.d.ts +15 -0
  51. package/dist/components/ui/tooltip/index.d.ts.map +1 -1
  52. package/dist/components/ui/tooltip/index.js +16 -1
  53. package/dist/domain/blotter/index.d.ts +4 -2
  54. package/dist/domain/blotter/index.d.ts.map +1 -1
  55. package/dist/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
  56. package/dist/domain/delinquency-aging/aging-buckets.js +8 -3
  57. package/dist/domain/delinquency-aging/index.d.ts.map +1 -1
  58. package/dist/domain/delinquency-aging/index.js +8 -3
  59. package/dist/domain/key-id/index.js +1 -1
  60. package/dist/domain/status-rail/index.js +1 -1
  61. package/dist/domain/threshold-gauge/index.d.ts.map +1 -1
  62. package/dist/domain/threshold-gauge/index.js +9 -5
  63. package/dist/enterprise/stat-card/index.d.ts.map +1 -1
  64. package/dist/enterprise/stat-card/index.js +12 -4
  65. package/dist/esm/components/card/account-card/index.d.ts.map +1 -1
  66. package/dist/esm/components/card/account-card/index.js +1 -1
  67. package/dist/esm/components/card/entity-card/index.js +3 -3
  68. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts +36 -5
  69. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  70. package/dist/esm/components/dialog/confirmation-dialog/index.js +2 -2
  71. package/dist/esm/components/entity-box/index.js +1 -1
  72. package/dist/esm/components/entity-data-table/index.d.ts.map +1 -1
  73. package/dist/esm/components/entity-data-table/index.js +1 -1
  74. package/dist/esm/components/form/file-upload-field/index.d.ts +11 -2
  75. package/dist/esm/components/form/file-upload-field/index.d.ts.map +1 -1
  76. package/dist/esm/components/form/file-upload-field/index.js +8 -3
  77. package/dist/esm/components/form/input-field/index.d.ts +41 -2
  78. package/dist/esm/components/form/input-field/index.d.ts.map +1 -1
  79. package/dist/esm/components/form/input-field/index.js +73 -15
  80. package/dist/esm/components/form/select-field/index.d.ts +9 -1
  81. package/dist/esm/components/form/select-field/index.d.ts.map +1 -1
  82. package/dist/esm/components/form/select-field/index.js +2 -2
  83. package/dist/esm/components/page-header/index.d.ts.map +1 -1
  84. package/dist/esm/components/page-header/index.js +2 -2
  85. package/dist/esm/components/ui/autocomplete/index.d.ts +34 -6
  86. package/dist/esm/components/ui/autocomplete/index.d.ts.map +1 -1
  87. package/dist/esm/components/ui/autocomplete/index.js +72 -16
  88. package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
  89. package/dist/esm/components/ui/badge/index.js +11 -1
  90. package/dist/esm/components/ui/calendar/index.d.ts.map +1 -1
  91. package/dist/esm/components/ui/calendar/index.js +8 -2
  92. package/dist/esm/components/ui/card/index.d.ts.map +1 -1
  93. package/dist/esm/components/ui/card/index.js +1 -1
  94. package/dist/esm/components/ui/dropdown-menu/index.d.ts.map +1 -1
  95. package/dist/esm/components/ui/dropdown-menu/index.js +4 -1
  96. package/dist/esm/components/ui/field/index.d.ts.map +1 -1
  97. package/dist/esm/components/ui/field/index.js +5 -2
  98. package/dist/esm/components/ui/file-upload/index.d.ts +76 -9
  99. package/dist/esm/components/ui/file-upload/index.d.ts.map +1 -1
  100. package/dist/esm/components/ui/file-upload/index.js +47 -13
  101. package/dist/esm/components/ui/form.d.ts +4 -0
  102. package/dist/esm/components/ui/form.d.ts.map +1 -1
  103. package/dist/esm/components/ui/form.js +53 -8
  104. package/dist/esm/components/ui/multiple-select/index.js +2 -2
  105. package/dist/esm/components/ui/progress/index.d.ts +15 -1
  106. package/dist/esm/components/ui/progress/index.d.ts.map +1 -1
  107. package/dist/esm/components/ui/progress/index.js +25 -2
  108. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  109. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +17 -1
  110. package/dist/esm/components/ui/toggle-group/index.d.ts +1 -1
  111. package/dist/esm/components/ui/toggle-group/index.d.ts.map +1 -1
  112. package/dist/esm/components/ui/toggle-group/index.js +73 -4
  113. package/dist/esm/components/ui/tooltip/index.d.ts +15 -0
  114. package/dist/esm/components/ui/tooltip/index.d.ts.map +1 -1
  115. package/dist/esm/components/ui/tooltip/index.js +16 -1
  116. package/dist/esm/domain/blotter/index.d.ts +4 -2
  117. package/dist/esm/domain/blotter/index.d.ts.map +1 -1
  118. package/dist/esm/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
  119. package/dist/esm/domain/delinquency-aging/aging-buckets.js +8 -3
  120. package/dist/esm/domain/delinquency-aging/index.d.ts.map +1 -1
  121. package/dist/esm/domain/delinquency-aging/index.js +8 -3
  122. package/dist/esm/domain/key-id/index.js +1 -1
  123. package/dist/esm/domain/status-rail/index.js +1 -1
  124. package/dist/esm/domain/threshold-gauge/index.d.ts.map +1 -1
  125. package/dist/esm/domain/threshold-gauge/index.js +9 -5
  126. package/dist/esm/enterprise/stat-card/index.d.ts.map +1 -1
  127. package/dist/esm/enterprise/stat-card/index.js +12 -4
  128. package/dist/globals.css +24 -1
  129. package/package.json +1 -1
@@ -23,7 +23,7 @@ const useFormField = () => {
23
23
  const fieldState = form && fieldContext.name
24
24
  ? form.getFieldState(fieldContext.name, form.formState)
25
25
  : undefined;
26
- const { id, required } = itemContext;
26
+ const { id, required, described, onDescribedChange } = itemContext;
27
27
  return {
28
28
  id,
29
29
  name: fieldContext.name,
@@ -31,36 +31,81 @@ const useFormField = () => {
31
31
  formDescriptionId: `${id}-form-item-description`,
32
32
  formMessageId: `${id}-form-item-message`,
33
33
  required,
34
+ described,
35
+ onDescribedChange,
34
36
  ...fieldState
35
37
  };
36
38
  };
37
39
  const FormItemContext = React.createContext({});
40
+ /**
41
+ * Announce that this slot is on the page, for as long as it is.
42
+ *
43
+ * `rendered` is a parameter rather than a caller-side condition because
44
+ * `FormMessage` returns null when it has nothing to say, and a hook cannot sit
45
+ * behind that early return.
46
+ */
47
+ function useDescribingSlot(slot, rendered) {
48
+ const { onDescribedChange } = React.useContext(FormItemContext);
49
+ React.useEffect(() => {
50
+ if (!rendered)
51
+ return;
52
+ onDescribedChange?.(slot, true);
53
+ return () => onDescribedChange?.(slot, false);
54
+ }, [onDescribedChange, slot, rendered]);
55
+ }
38
56
  const FormItem = React.forwardRef(({ className, required, ...props }, ref) => {
39
57
  const id = React.useId();
40
- return (_jsx(FormItemContext.Provider, { value: { id, required }, children: _jsx("div", { ref: ref, className: cn('space-y-2', className), ...props }) }));
58
+ const [described, setDescribed] = React.useState({ message: false, description: false });
59
+ // Keeps the object identity when nothing moved, so a slot re-registering
60
+ // does not re-render the item for no reason.
61
+ const onDescribedChange = React.useCallback((slot, rendered) => setDescribed((current) => current[slot] === rendered
62
+ ? current
63
+ : { ...current, [slot]: rendered }), []);
64
+ return (_jsx(FormItemContext.Provider, { value: { id, required, described, onDescribedChange }, children: _jsx("div", { ref: ref, className: cn('space-y-2', className), ...props }) }));
41
65
  });
42
66
  FormItem.displayName = 'FormItem';
43
67
  const FormLabel = React.forwardRef(({ className, extra, children, ...props }, ref) => {
44
68
  const { required, error, formItemId } = useFormField();
45
- return (_jsxs(Label, { ref: ref, className: cn('text-muted-foreground flex justify-between text-sm font-semibold', error && 'text-destructive', className), htmlFor: formItemId, ...props, children: [_jsxs("span", { children: [children, required ? ' *' : ''] }), extra] }));
69
+ return (_jsxs(Label, { ref: ref, className: cn('text-muted-foreground flex justify-between text-sm font-semibold',
70
+ // The error TEXT token, matching FormMessage below: `--destructive`
71
+ // is the badge/fill family and reads 3.80:1 as ink on the dark card.
72
+ error && 'text-system-error-h1a', className), htmlFor: formItemId, ...props, children: [_jsxs("span", { children: [children, required ? ' *' : ''] }), extra] }));
46
73
  });
47
74
  FormLabel.displayName = 'FormLabel';
48
75
  export const FormTooltip = ({ children, ...others }) => (_jsx(TooltipProvider, { ...others, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(HelpCircle, { className: "text-container-text ml-2 h-4 w-4" }) }), _jsx(TooltipContent, { children: children })] }) }));
49
76
  const FormControl = React.forwardRef(({ ...props }, ref) => {
50
- const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
51
- return (_jsx(Slot, { ref: ref, id: formItemId, "aria-describedby": !error
52
- ? `${formDescriptionId}`
53
- : `${formDescriptionId} ${formMessageId}`, "aria-invalid": !!error, ...props }));
77
+ const { error, formItemId, formDescriptionId, formMessageId, described } = useFormField();
78
+ // Only ids that resolve. A screen reader drops a dangling IDREF silently, so
79
+ // the barrier this removes is diagnostic rather than operational: a form with
80
+ // thirteen broken associations is a form where a real one cannot be spotted.
81
+ //
82
+ // Message first: a reader hears the error before the hint. `undefined` when
83
+ // both slots are empty, which drops the attribute — and, because Radix Slot
84
+ // OVERWRITES rather than merges, still lets the wrapped element carry its own
85
+ // (`ui/file-upload` merges the injected id with its own error id that way).
86
+ const describedBy = [
87
+ described?.message ? formMessageId : undefined,
88
+ described?.description ? formDescriptionId : undefined
89
+ ]
90
+ .filter(Boolean)
91
+ .join(' ') || undefined;
92
+ return (_jsx(Slot, { ref: ref, id: formItemId, "aria-describedby": describedBy, "aria-invalid": !!error, ...props }));
54
93
  });
55
94
  FormControl.displayName = 'FormControl';
56
95
  const FormDescription = React.forwardRef(({ className, ...props }, ref) => {
57
96
  const { formDescriptionId } = useFormField();
58
- return (_jsx("p", { ref: ref, id: formDescriptionId, className: cn('text-shadcn-400 text-xs font-medium', className), ...props }));
97
+ useDescribingSlot('description', true);
98
+ return (_jsx("p", { ref: ref, id: formDescriptionId, className: cn('text-muted-foreground text-xs font-medium', className), ...props }));
59
99
  });
60
100
  FormDescription.displayName = 'FormDescription';
61
101
  const FormMessage = React.forwardRef(({ className, children, ...props }, ref) => {
62
102
  const { error, formMessageId } = useFormField();
63
103
  const body = error ? String(error?.message) : children;
104
+ // Registered on `body`, not on `error`: a message given plain children
105
+ // renders copy that the control has to point at too. The old expression only
106
+ // added the message id when react-hook-form reported an error, so a
107
+ // standalone message was rendered and never associated.
108
+ useDescribingSlot('message', Boolean(body));
64
109
  if (!body) {
65
110
  return null;
66
111
  }
@@ -38,7 +38,7 @@ export const MultipleSelectTrigger = React.forwardRef(({ className, children, re
38
38
  setOpen(false);
39
39
  inputRef.current?.blur();
40
40
  });
41
- return (_jsxs("div", { ref: _ref, className: cn('bg-background ring-offset-background placeholder:text-shadcn-400 focus:ring-ring border-shadcn-400 flex flex-row rounded-md border text-sm focus:ring-2 focus:ring-offset-0 focus:outline-hidden focus-visible:outline-hidden md:text-sm [&>span]:line-clamp-1', {
41
+ return (_jsxs("div", { ref: _ref, className: cn('bg-background ring-offset-background placeholder:text-input-placeholder focus:ring-ring border-input-border flex flex-row rounded-md border text-sm focus:ring-2 focus:ring-offset-0 focus:outline-hidden focus-visible:outline-hidden md:text-sm [&>span]:line-clamp-1', {
42
42
  'h-10': value.length === 0,
43
43
  'min-h-10': value.length > 0,
44
44
  'cursor-text': !disabled && !readOnly && value.length !== 0,
@@ -77,7 +77,7 @@ export const MultipleSelectValue = React.forwardRef(({ className, ...props }, re
77
77
  value?.map((value) => (_jsxs(Badge, { variant: "secondary", className: cn('data-disabled:bg-muted-foreground data-fixed:bg-muted-foreground data-disabled:text-muted data-fixed:text-muted data-disabled:hover:bg-muted-foreground data-fixed:hover:bg-muted-foreground'), children: [showValue ? value : options[value], _jsx("button", { type: "button", className: cn('ring-offset-background focus:ring-ring ml-1 rounded-full outline-hidden focus:ring-2 focus:ring-offset-2', disabled && 'hidden'), children: _jsx(X, { className: "text-muted-foreground hover:text-foreground h-3 w-3", onClick: (event) => {
78
78
  event.stopPropagation();
79
79
  handleChange(value);
80
- } }) })] }, value))), _jsx(CommandPrimitive.Input, { ...props, ref: inputRef, disabled: disabled, className: cn('placeholder:text-muted-foreground bg-transparent outline-hidden focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 disabled:placeholder:opacity-0', className) })] }));
80
+ } }) })] }, value))), _jsx(CommandPrimitive.Input, { ...props, ref: inputRef, disabled: disabled, className: cn('placeholder:text-input-placeholder bg-transparent outline-hidden focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 disabled:placeholder:opacity-0', className) })] }));
81
81
  });
82
82
  MultipleSelectValue.displayName = 'MultipleSelectValue';
83
83
  export const MultipleSelectEmpty = React.forwardRef(({ className, ...props }, forwardedRef) => {
@@ -3,6 +3,20 @@ import * as ProgressPrimitive from '@radix-ui/react-progress';
3
3
  type ProgressProps = React.ComponentProps<typeof ProgressPrimitive.Root> & {
4
4
  indicatorColor?: string;
5
5
  };
6
- declare function Progress({ className, value, indicatorColor, ...props }: ProgressProps): React.JSX.Element;
6
+ /**
7
+ * `value` and `max` are Radix's own props, so the bar reports `aria-valuenow` /
8
+ * `aria-valuemax` and flips `data-state` between `loading` and `complete`.
9
+ * Omitting `value`, or passing `null`, is Radix's indeterminate state and draws
10
+ * an empty track.
11
+ *
12
+ * Both numbers are BOUNDED BEFORE THE ROOT SEES THEM, so the drawn width and
13
+ * the announced value can never disagree. Radix accepts a value only inside
14
+ * `[0, max]`: hand it one outside and the root drops `aria-valuenow`, sticks
15
+ * `data-state` on `indeterminate` and logs an error, while the indicator here
16
+ * goes on drawing the clamped bar. Substituting 100 for a non-positive max is
17
+ * Radix's own fallback, and is also what keeps a `max` of 0 from dividing by
18
+ * zero.
19
+ */
20
+ declare function Progress({ className, value, max, indicatorColor, ...props }: ProgressProps): React.JSX.Element;
7
21
  export { Progress };
8
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/progress/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAA;AAI7D,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC,GAAG;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,KAAK,EACL,cAA6B,EAC7B,GAAG,KAAK,EACT,EAAE,aAAa,qBAiBf;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/progress/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAA;AAI7D,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC,GAAG;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,KAAK,EACL,GAAG,EACH,cAA6B,EAC7B,GAAG,KAAK,EACT,EAAE,aAAa,qBA6Bf;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -2,7 +2,30 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as ProgressPrimitive from '@radix-ui/react-progress';
4
4
  import { cn } from '../../../lib/utils.js';
5
- function Progress({ className, value, indicatorColor = 'bg-primary', ...props }) {
6
- return (_jsx(ProgressPrimitive.Root, { "data-slot": "progress", className: cn('bg-primary/20 relative h-4 w-full overflow-hidden rounded-full', className), ...props, children: _jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", className: cn('h-full w-full flex-1 transition-all', indicatorColor), style: { transform: `translateX(-${100 - (value || 0)}%)` } }) }));
5
+ /**
6
+ * `value` and `max` are Radix's own props, so the bar reports `aria-valuenow` /
7
+ * `aria-valuemax` and flips `data-state` between `loading` and `complete`.
8
+ * Omitting `value`, or passing `null`, is Radix's indeterminate state and draws
9
+ * an empty track.
10
+ *
11
+ * Both numbers are BOUNDED BEFORE THE ROOT SEES THEM, so the drawn width and
12
+ * the announced value can never disagree. Radix accepts a value only inside
13
+ * `[0, max]`: hand it one outside and the root drops `aria-valuenow`, sticks
14
+ * `data-state` on `indeterminate` and logs an error, while the indicator here
15
+ * goes on drawing the clamped bar. Substituting 100 for a non-positive max is
16
+ * Radix's own fallback, and is also what keeps a `max` of 0 from dividing by
17
+ * zero.
18
+ */
19
+ function Progress({ className, value, max, indicatorColor = 'bg-primary', ...props }) {
20
+ const scale = Number.isFinite(max) && max > 0 ? max : 100;
21
+ // Bound against `scale`, not against the rejected `max`: with `max={0}` the
22
+ // scale is already 100, and clamping to 0 would report a finished bar empty.
23
+ // Non-finite values are indeterminate, matching Radix without producing an
24
+ // invalid CSS transform.
25
+ const bounded = Number.isFinite(value)
26
+ ? Math.min(scale, Math.max(0, value))
27
+ : null;
28
+ const percent = ((bounded ?? 0) / scale) * 100;
29
+ return (_jsx(ProgressPrimitive.Root, { "data-slot": "progress", value: bounded, max: scale, className: cn('bg-primary/20 relative h-4 w-full overflow-hidden rounded-full', className), ...props, children: _jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", className: cn('h-full w-full flex-1 transition-all', indicatorColor), style: { transform: `translateX(-${100 - percent}%)` } }) }));
7
30
  }
8
31
  export { Progress };
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-expand-button.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-expand-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,KAAK,wBAAwB,GAAG;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,aAAa,wBAAwB,sBA6CxE,CAAA"}
1
+ {"version":3,"file":"sidebar-expand-button.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-expand-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,KAAK,wBAAwB,GAAG;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,aAAa,wBAAwB,sBAyDxE,CAAA"}
@@ -8,5 +8,21 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../
8
8
  import { IconButton } from '../icon-button/index.js';
9
9
  export const SidebarExpandButton = ({ tooltip }) => {
10
10
  const { isCollapsed, toggleSidebar } = useSidebar();
11
- return (_jsxs(React.Fragment, { children: [!isCollapsed && (_jsx("div", { "data-slot": "sidebar-expand-button", className: "border-border bg-card flex w-full", children: _jsx("div", { className: "absolute right-[-20px] bottom-4", children: _jsx(IconButton, { variant: "secondary", rounded: true, onClick: toggleSidebar, "aria-label": tooltip || 'Collapse sidebar', "aria-expanded": true, children: _jsx(PanelLeftClose, { className: "text-shadcn-400" }) }) }) })), isCollapsed && (_jsx(SidebarFooter, { children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { className: "group/expand-button text-shadcn-400 hover:bg-accent rounded-sm bg-transparent p-2", onClick: toggleSidebar, "aria-label": tooltip || 'Expand sidebar', "aria-expanded": false, children: _jsx(PanelRightClose, { className: "group-hover/expand-button:text-white dark:text-white" }) }), _jsx(TooltipContent, { side: "right", children: tooltip || 'Expand' })] }) }) }))] }));
11
+ return (_jsxs(React.Fragment, { children: [!isCollapsed && (_jsx("div", { "data-slot": "sidebar-expand-button", className: "border-border bg-card flex w-full", children: _jsx("div", { className: "absolute right-[-20px] bottom-4", children: _jsx(IconButton, { variant: "secondary", rounded: true, onClick: toggleSidebar, "aria-label": tooltip || 'Collapse sidebar', "aria-expanded": true, children: _jsx(PanelLeftClose, { className: "text-muted-foreground" }) }) }) })), isCollapsed && (_jsx(SidebarFooter, { children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger
12
+ // `hover:text-accent-foreground` on the TRIGGER, not only on
13
+ // the glyph below. The base ink here used to be base/400, which
14
+ // no rule paired with anything; now that it is the muted token,
15
+ // it is the ink anything inside this trigger inherits, and the
16
+ // muted token reads 1.07:1 on sunglow in dark. The glyph
17
+ // overrides it today, so this pairs the fill for whatever the
18
+ // trigger holds next.
19
+ , {
20
+ // `hover:text-accent-foreground` on the TRIGGER, not only on
21
+ // the glyph below. The base ink here used to be base/400, which
22
+ // no rule paired with anything; now that it is the muted token,
23
+ // it is the ink anything inside this trigger inherits, and the
24
+ // muted token reads 1.07:1 on sunglow in dark. The glyph
25
+ // overrides it today, so this pairs the fill for whatever the
26
+ // trigger holds next.
27
+ className: "group/expand-button text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-sm bg-transparent p-2", onClick: toggleSidebar, "aria-label": tooltip || 'Expand sidebar', "aria-expanded": false, children: _jsx(PanelRightClose, { className: "group-hover/expand-button:text-accent-foreground dark:text-white" }) }), _jsx(TooltipContent, { side: "right", children: tooltip || 'Expand' })] }) }) }))] }));
12
28
  };
@@ -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). */