@lerianstudio/sindarian-ui 2.0.0-beta.25 → 2.0.0-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/charts/chart.js +4 -231
- package/dist/charts/index.js +1 -11
- package/dist/components/breadcrumb/get-breadcrumb-paths.js +1 -18
- package/dist/components/breadcrumb/index.js +1 -37
- package/dist/components/card/account-card/index.js +1 -69
- package/dist/components/card/basic-card/index.js +1 -20
- package/dist/components/card/dashboard-card/index.js +1 -20
- package/dist/components/card/entity-card/index.js +1 -68
- package/dist/components/card/index.js +1 -20
- package/dist/components/dialog/confirmation-dialog/index.js +1 -96
- package/dist/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -55
- package/dist/components/dialog/index.js +1 -19
- package/dist/components/dialog/large-dialog/index.js +1 -21
- package/dist/components/entity-box/index.js +1 -67
- package/dist/components/entity-data-table/index.js +1 -20
- package/dist/components/form/combo-box-field/index.js +1 -35
- package/dist/components/form/country-field/index.js +1 -11
- package/dist/components/form/date-picker-field/index.js +1 -83
- package/dist/components/form/date-range-field/index.js +1 -58
- package/dist/components/form/date-time-picker-field/index.js +1 -114
- package/dist/components/form/file-upload-field/index.js +1 -69
- package/dist/components/form/index.js +1 -31
- package/dist/components/form/input-field/index.js +1 -96
- package/dist/components/form/otp-field/index.js +1 -19
- package/dist/components/form/pagination-limit-field/index.js +1 -10
- package/dist/components/form/password-field/index.js +1 -16
- package/dist/components/form/radio-group-field/index.js +1 -36
- package/dist/components/form/renderable-label.js +1 -57
- package/dist/components/form/select-field/index.js +1 -68
- package/dist/components/form/state-field/index.js +1 -42
- package/dist/components/form/switch-field/index.js +1 -16
- package/dist/components/form/textarea-field/index.js +1 -23
- package/dist/components/page/index.js +1 -20
- package/dist/components/page-header/index.js +1 -80
- package/dist/components/pagination/index.js +1 -10
- package/dist/components/table/id-table-cell.js +1 -109
- package/dist/components/table/index.js +1 -19
- package/dist/components/table/locked-table-actions.js +1 -41
- package/dist/components/table/name-table-cell.js +1 -58
- package/dist/components/ui/accordion/index.js +1 -62
- package/dist/components/ui/alert/index.js +1 -45
- package/dist/components/ui/alert-dialog/index.js +1 -84
- package/dist/components/ui/autocomplete/index.js +1 -440
- package/dist/components/ui/autosize-textarea/index.js +1 -89
- package/dist/components/ui/avatar/index.js +1 -51
- package/dist/components/ui/badge/index.js +1 -83
- package/dist/components/ui/breadcrumb/index.js +1 -35
- package/dist/components/ui/button/index.js +1 -65
- package/dist/components/ui/calendar/index.js +1 -118
- package/dist/components/ui/card/index.js +1 -32
- package/dist/components/ui/checkbox/index.js +1 -44
- package/dist/components/ui/collapsible/index.js +1 -50
- package/dist/components/ui/command/index.js +1 -95
- package/dist/components/ui/copy-field/index.js +1 -163
- package/dist/components/ui/dialog/index.js +1 -80
- package/dist/components/ui/dropdown-menu/index.js +1 -110
- package/dist/components/ui/field/index.js +1 -82
- package/dist/components/ui/file-upload/index.js +1 -574
- package/dist/components/ui/form.js +1 -162
- package/dist/components/ui/hover-card/index.js +1 -51
- package/dist/components/ui/icon-button/index.js +1 -35
- package/dist/components/ui/input/adornment.js +1 -21
- package/dist/components/ui/input/index.js +1 -99
- package/dist/components/ui/label/index.js +1 -45
- package/dist/components/ui/lerian-wordmark/index.js +1 -7
- package/dist/components/ui/loading-button/index.js +1 -9
- package/dist/components/ui/multiple-select/index.js +1 -235
- package/dist/components/ui/otp-input/index.js +1 -62
- package/dist/components/ui/paper/index.js +1 -8
- package/dist/components/ui/paper-collapsible/index.js +1 -24
- package/dist/components/ui/popover/index.js +1 -55
- package/dist/components/ui/progress/index.js +1 -66
- package/dist/components/ui/qr-code/index.js +1 -27
- package/dist/components/ui/radio-group/index.js +1 -48
- package/dist/components/ui/scroll-area/index.js +1 -49
- package/dist/components/ui/select/index.js +1 -119
- package/dist/components/ui/separator/index.js +1 -43
- package/dist/components/ui/sheet/index.js +1 -136
- package/dist/components/ui/sidebar/index.js +1 -27
- package/dist/components/ui/sidebar/next-router.cjs +1 -119
- package/dist/components/ui/sidebar/sidebar-back-button.js +1 -8
- package/dist/components/ui/sidebar/sidebar-components.js +1 -23
- package/dist/components/ui/sidebar/sidebar-expand-button.js +1 -49
- package/dist/components/ui/sidebar/sidebar-item-button.js +1 -21
- package/dist/components/ui/sidebar/sidebar-item-collapsible.js +1 -52
- package/dist/components/ui/sidebar/sidebar-item-icon-button.js +1 -18
- package/dist/components/ui/sidebar/sidebar-item.js +1 -44
- package/dist/components/ui/sidebar/sidebar-provider.js +1 -201
- package/dist/components/ui/sidebar/sidebar-root.js +1 -130
- package/dist/components/ui/sidebar/sidebar-router.js +1 -126
- package/dist/components/ui/sidebar/sidebar-trigger.js +1 -57
- package/dist/components/ui/skeleton/index.js +1 -8
- package/dist/components/ui/stepper/index.js +1 -29
- package/dist/components/ui/switch/index.js +1 -43
- package/dist/components/ui/table/index.js +1 -56
- package/dist/components/ui/tabs/index.js +1 -55
- package/dist/components/ui/textarea/index.js +1 -8
- package/dist/components/ui/time-picker/index.js +1 -85
- package/dist/components/ui/toast/index.js +1 -3
- package/dist/components/ui/toast/toaster.js +1 -16
- package/dist/components/ui/toggle-group/index.js +1 -156
- package/dist/components/ui/tooltip/index.js +1 -81
- package/dist/domain/blotter/index.js +1 -20
- package/dist/domain/delinquency-aging/aging-buckets.js +1 -120
- package/dist/domain/delinquency-aging/index.js +1 -222
- package/dist/domain/figure/index.js +1 -19
- package/dist/domain/format.js +1 -137
- package/dist/domain/index.js +1 -43
- package/dist/domain/key-id/index.js +1 -174
- package/dist/domain/ledger-sheet/index.js +1 -28
- package/dist/domain/money-diff.js +1 -48
- package/dist/domain/money-math.js +1 -104
- package/dist/domain/money-text/index.js +1 -123
- package/dist/domain/section-label/index.js +1 -17
- package/dist/domain/status-rail/index.js +1 -76
- package/dist/domain/threshold-gauge/index.js +1 -161
- package/dist/enterprise/alert-banner/index.js +1 -24
- package/dist/enterprise/app-shell/index.js +1 -87
- package/dist/enterprise/cursor-pager/index.js +1 -26
- package/dist/enterprise/data-table/column-size.js +1 -103
- package/dist/enterprise/data-table/index.js +1 -345
- package/dist/enterprise/date-range-picker/index.js +1 -115
- package/dist/enterprise/detail-panel/index.js +1 -20
- package/dist/enterprise/empty-state/index.js +1 -14
- package/dist/enterprise/index.js +1 -39
- package/dist/enterprise/number-input/index.js +1 -252
- package/dist/enterprise/search-input/index.js +1 -121
- package/dist/enterprise/stat-card/index.js +1 -75
- package/dist/enterprise/status-badge/index.js +1 -120
- package/dist/enterprise/use-is-mobile.js +1 -68
- package/dist/enterprise/virtualized-table/index.js +1 -141
- package/dist/esm/charts/chart.js +4 -190
- package/dist/esm/charts/index.js +1 -3
- package/dist/esm/components/breadcrumb/get-breadcrumb-paths.js +1 -12
- package/dist/esm/components/breadcrumb/index.js +1 -30
- package/dist/esm/components/card/account-card/index.js +1 -53
- package/dist/esm/components/card/basic-card/index.js +1 -14
- package/dist/esm/components/card/dashboard-card/index.js +1 -14
- package/dist/esm/components/card/entity-card/index.js +1 -52
- package/dist/esm/components/card/index.js +1 -4
- package/dist/esm/components/dialog/confirmation-dialog/index.js +1 -60
- package/dist/esm/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -49
- package/dist/esm/components/dialog/index.js +1 -3
- package/dist/esm/components/dialog/large-dialog/index.js +1 -16
- package/dist/esm/components/entity-box/index.js +1 -56
- package/dist/esm/components/entity-data-table/index.js +1 -17
- package/dist/esm/components/form/combo-box-field/index.js +1 -28
- package/dist/esm/components/form/country-field/index.js +1 -7
- package/dist/esm/components/form/date-picker-field/index.js +1 -43
- package/dist/esm/components/form/date-range-field/index.js +1 -18
- package/dist/esm/components/form/date-time-picker-field/index.js +1 -74
- package/dist/esm/components/form/file-upload-field/index.js +1 -65
- package/dist/esm/components/form/index.js +1 -15
- package/dist/esm/components/form/input-field/index.js +1 -92
- package/dist/esm/components/form/otp-field/index.js +1 -15
- package/dist/esm/components/form/pagination-limit-field/index.js +1 -6
- package/dist/esm/components/form/password-field/index.js +1 -10
- package/dist/esm/components/form/radio-group-field/index.js +1 -32
- package/dist/esm/components/form/renderable-label.js +1 -54
- package/dist/esm/components/form/select-field/index.js +1 -64
- package/dist/esm/components/form/state-field/index.js +1 -35
- package/dist/esm/components/form/switch-field/index.js +1 -12
- package/dist/esm/components/form/textarea-field/index.js +1 -19
- package/dist/esm/components/page/index.js +1 -15
- package/dist/esm/components/page-header/index.js +1 -71
- package/dist/esm/components/pagination/index.js +1 -6
- package/dist/esm/components/table/id-table-cell.js +1 -105
- package/dist/esm/components/table/index.js +1 -3
- package/dist/esm/components/table/locked-table-actions.js +1 -37
- package/dist/esm/components/table/name-table-cell.js +1 -54
- package/dist/esm/components/ui/accordion/index.js +1 -24
- package/dist/esm/components/ui/alert/index.js +1 -38
- package/dist/esm/components/ui/alert-dialog/index.js +1 -39
- package/dist/esm/components/ui/autocomplete/index.js +1 -392
- package/dist/esm/components/ui/autosize-textarea/index.js +1 -51
- package/dist/esm/components/ui/avatar/index.js +1 -14
- package/dist/esm/components/ui/badge/index.js +1 -79
- package/dist/esm/components/ui/breadcrumb/index.js +1 -27
- package/dist/esm/components/ui/button/index.js +1 -60
- package/dist/esm/components/ui/calendar/index.js +1 -82
- package/dist/esm/components/ui/card/index.js +1 -24
- package/dist/esm/components/ui/checkbox/index.js +1 -9
- package/dist/esm/components/ui/collapsible/index.js +1 -13
- package/dist/esm/components/ui/command/index.js +1 -51
- package/dist/esm/components/ui/copy-field/index.js +1 -127
- package/dist/esm/components/ui/dialog/index.js +1 -36
- package/dist/esm/components/ui/dropdown-menu/index.js +1 -60
- package/dist/esm/components/ui/field/index.js +1 -71
- package/dist/esm/components/ui/file-upload/index.js +1 -536
- package/dist/esm/components/ui/form.js +1 -118
- package/dist/esm/components/ui/hover-card/index.js +1 -14
- package/dist/esm/components/ui/icon-button/index.js +1 -31
- package/dist/esm/components/ui/input/adornment.js +1 -17
- package/dist/esm/components/ui/input/index.js +1 -60
- package/dist/esm/components/ui/label/index.js +1 -10
- package/dist/esm/components/ui/lerian-wordmark/index.js +1 -4
- package/dist/esm/components/ui/loading-button/index.js +1 -7
- package/dist/esm/components/ui/multiple-select/index.js +1 -196
- package/dist/esm/components/ui/otp-input/index.js +1 -21
- package/dist/esm/components/ui/paper/index.js +1 -5
- package/dist/esm/components/ui/paper-collapsible/index.js +1 -19
- package/dist/esm/components/ui/popover/index.js +1 -17
- package/dist/esm/components/ui/progress/index.js +1 -31
- package/dist/esm/components/ui/qr-code/index.js +1 -24
- package/dist/esm/components/ui/radio-group/index.js +1 -12
- package/dist/esm/components/ui/scroll-area/index.js +1 -13
- package/dist/esm/components/ui/select/index.js +1 -74
- package/dist/esm/components/ui/separator/index.js +1 -8
- package/dist/esm/components/ui/sheet/index.js +1 -92
- package/dist/esm/components/ui/sidebar/index.js +1 -11
- package/dist/esm/components/ui/sidebar/next-router.cjs +1 -119
- package/dist/esm/components/ui/sidebar/sidebar-back-button.js +1 -5
- package/dist/esm/components/ui/sidebar/sidebar-components.js +1 -15
- package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +1 -42
- package/dist/esm/components/ui/sidebar/sidebar-item-button.js +1 -18
- package/dist/esm/components/ui/sidebar/sidebar-item-collapsible.js +1 -44
- package/dist/esm/components/ui/sidebar/sidebar-item-icon-button.js +1 -14
- package/dist/esm/components/ui/sidebar/sidebar-item.js +1 -40
- package/dist/esm/components/ui/sidebar/sidebar-provider.js +1 -193
- package/dist/esm/components/ui/sidebar/sidebar-root.js +1 -126
- package/dist/esm/components/ui/sidebar/sidebar-router.js +1 -89
- package/dist/esm/components/ui/sidebar/sidebar-trigger.js +1 -53
- package/dist/esm/components/ui/skeleton/index.js +1 -6
- package/dist/esm/components/ui/stepper/index.js +1 -20
- package/dist/esm/components/ui/switch/index.js +1 -8
- package/dist/esm/components/ui/table/index.js +1 -44
- package/dist/esm/components/ui/tabs/index.js +1 -17
- package/dist/esm/components/ui/textarea/index.js +1 -6
- package/dist/esm/components/ui/time-picker/index.js +1 -49
- package/dist/esm/components/ui/toast/index.js +1 -2
- package/dist/esm/components/ui/toast/toaster.js +1 -13
- package/dist/esm/components/ui/toggle-group/index.js +1 -120
- package/dist/esm/components/ui/tooltip/index.js +1 -43
- package/dist/esm/domain/blotter/index.js +1 -16
- package/dist/esm/domain/delinquency-aging/aging-buckets.js +1 -115
- package/dist/esm/domain/delinquency-aging/index.js +1 -218
- package/dist/esm/domain/figure/index.js +1 -15
- package/dist/esm/domain/format.js +1 -128
- package/dist/esm/domain/index.js +1 -19
- package/dist/esm/domain/key-id/index.js +1 -169
- package/dist/esm/domain/ledger-sheet/index.js +1 -24
- package/dist/esm/domain/money-diff.js +1 -45
- package/dist/esm/domain/money-math.js +1 -98
- package/dist/esm/domain/money-text/index.js +1 -118
- package/dist/esm/domain/section-label/index.js +1 -14
- package/dist/esm/domain/status-rail/index.js +1 -71
- package/dist/esm/domain/threshold-gauge/index.js +1 -157
- package/dist/esm/enterprise/alert-banner/index.js +1 -21
- package/dist/esm/enterprise/app-shell/index.js +1 -51
- package/dist/esm/enterprise/cursor-pager/index.js +1 -23
- package/dist/esm/enterprise/data-table/column-size.js +1 -97
- package/dist/esm/enterprise/data-table/index.js +1 -342
- package/dist/esm/enterprise/date-range-picker/index.js +1 -112
- package/dist/esm/enterprise/detail-panel/index.js +1 -17
- package/dist/esm/enterprise/empty-state/index.js +1 -11
- package/dist/esm/enterprise/index.js +1 -22
- package/dist/esm/enterprise/number-input/index.js +1 -214
- package/dist/esm/enterprise/search-input/index.js +1 -85
- package/dist/esm/enterprise/stat-card/index.js +1 -72
- package/dist/esm/enterprise/status-badge/index.js +1 -116
- package/dist/esm/enterprise/use-is-mobile.js +1 -31
- package/dist/esm/enterprise/virtualized-table/index.js +1 -138
- package/dist/esm/hooks/use-click-away.js +1 -22
- package/dist/esm/hooks/use-pagination.js +1 -38
- package/dist/esm/hooks/use-stepper.js +1 -22
- package/dist/esm/hooks/use-time.js +1 -13
- package/dist/esm/hooks/use-toast.js +1 -107
- package/dist/esm/index.js +1 -77
- package/dist/esm/lib/storage/get-storage-object.js +1 -17
- package/dist/esm/lib/storage/get-storage.js +1 -14
- package/dist/esm/lib/storage/index.js +1 -2
- package/dist/esm/lib/typography.js +1 -31
- package/dist/esm/lib/utils.js +1 -41
- package/dist/esm/theme/get-theme-script.js +1 -41
- package/dist/esm/theme/index.js +1 -4
- package/dist/esm/theme/mode-toggle.js +1 -45
- package/dist/esm/theme/theme-provider.js +1 -122
- package/dist/esm/toast/helpers.js +1 -36
- package/dist/esm/toast/index.js +1 -4
- package/dist/esm/types/metadata-type.js +1 -1
- package/dist/esm/utils/countries.cjs +1 -17
- package/dist/esm/utils/country-utils.js +1 -18
- package/dist/esm/utils/currency-codes.js +1 -181
- package/dist/hooks/use-click-away.js +1 -29
- package/dist/hooks/use-pagination.js +1 -41
- package/dist/hooks/use-stepper.js +1 -26
- package/dist/hooks/use-time.js +1 -20
- package/dist/hooks/use-toast.js +1 -111
- package/dist/index.js +1 -96
- package/dist/lib/storage/get-storage-object.js +1 -23
- package/dist/lib/storage/get-storage.js +1 -17
- package/dist/lib/storage/index.js +1 -18
- package/dist/lib/typography.js +1 -34
- package/dist/lib/utils.js +1 -45
- package/dist/theme/get-theme-script.js +1 -44
- package/dist/theme/index.js +1 -11
- package/dist/theme/mode-toggle.js +1 -48
- package/dist/theme/theme-provider.js +1 -160
- package/dist/toast/helpers.js +1 -41
- package/dist/toast/index.js +1 -10
- package/dist/types/metadata-type.js +1 -2
- package/dist/utils/countries.cjs +1 -17
- package/dist/utils/country-utils.js +1 -25
- package/dist/utils/currency-codes.js +1 -184
- package/package.json +4 -3
|
@@ -1,19 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FIGURE_CLASS = void 0;
|
|
4
|
-
exports.Figure = Figure;
|
|
5
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
-
const utils_1 = require("../../lib/utils");
|
|
7
|
-
/** Canonical class strings per figure size. The `tabular-nums` invariant lives
|
|
8
|
-
* here so it can never be forgotten at a call site. */
|
|
9
|
-
exports.FIGURE_CLASS = {
|
|
10
|
-
hero: 'text-4xl font-semibold tracking-tight tabular-nums lg:text-5xl',
|
|
11
|
-
'money-hero': 'text-2xl font-semibold tracking-tight tabular-nums lg:text-3xl',
|
|
12
|
-
panel: 'text-3xl font-semibold tracking-tight tabular-nums',
|
|
13
|
-
count: 'text-2xl font-semibold tracking-tight tabular-nums',
|
|
14
|
-
row: 'text-sm tabular-nums',
|
|
15
|
-
tick: 'text-xs leading-none tabular-nums'
|
|
16
|
-
};
|
|
17
|
-
function Figure({ size, children, className, as: Tag = 'span' }) {
|
|
18
|
-
return (0, jsx_runtime_1.jsx)(Tag, { className: (0, utils_1.cn)(exports.FIGURE_CLASS[size], className), children: children });
|
|
19
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FIGURE_CLASS=void 0;exports.Figure=Figure;const jsx_runtime_1=require("react/jsx-runtime");const utils_1=require("../../lib/utils");exports.FIGURE_CLASS={hero:"text-4xl font-semibold tracking-tight tabular-nums lg:text-5xl","money-hero":"text-2xl font-semibold tracking-tight tabular-nums lg:text-3xl",panel:"text-3xl font-semibold tracking-tight tabular-nums",count:"text-2xl font-semibold tracking-tight tabular-nums",row:"text-sm tabular-nums",tick:"text-xs leading-none tabular-nums"};function Figure({size:t,children:e,className:r,as:n="span"}){return(0,jsx_runtime_1.jsx)(n,{className:(0,utils_1.cn)(exports.FIGURE_CLASS[t],r),children:e})}
|
package/dist/domain/format.js
CHANGED
|
@@ -1,137 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Ledger-kit formatting helpers. Pure functions, no React. `MoneyText` owns
|
|
4
|
-
* monetary formatting; these cover percent, integer counts, and humanized
|
|
5
|
-
* durations (e.g. an average resolution time arriving as milliseconds).
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.NO_VALUE = void 0;
|
|
9
|
-
exports.isValidDigitCount = isValidDigitCount;
|
|
10
|
-
exports.safeLocale = safeLocale;
|
|
11
|
-
exports.formatPercent = formatPercent;
|
|
12
|
-
exports.toPercentValue = toPercentValue;
|
|
13
|
-
exports.formatCount = formatCount;
|
|
14
|
-
exports.humanizeDurationMs = humanizeDurationMs;
|
|
15
|
-
/** No-value placeholder. A middle dot reads as "empty" without an em dash, and
|
|
16
|
-
* stays narrow enough not to disturb tabular alignment. */
|
|
17
|
-
exports.NO_VALUE = '·';
|
|
18
|
-
/**
|
|
19
|
-
* Whether a digit count is one `Intl.NumberFormat` (and `Number#toFixed`, and
|
|
20
|
-
* `String#repeat`) will actually accept: a finite integer in 0..100. Anything
|
|
21
|
-
* else — a negative, a fraction, NaN, Infinity — makes those constructors throw
|
|
22
|
-
* a RangeError, which on a money surface means a blank screen instead of a
|
|
23
|
-
* number. Every caller turns an invalid count into the no-value path instead.
|
|
24
|
-
*
|
|
25
|
-
* Internal: shared by `format`, `money-text` and `money-math` so the three
|
|
26
|
-
* cannot drift on what "valid" means. Never exported from `src/domain/index.ts`.
|
|
27
|
-
*/
|
|
28
|
-
function isValidDigitCount(digits) {
|
|
29
|
-
return Number.isInteger(digits) && digits >= 0 && digits <= 100;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* A locale tag `Intl` will accept, or `undefined` — which every `Intl`
|
|
33
|
-
* constructor reads as "the runtime locale", the documented default for every
|
|
34
|
-
* `locale` prop in this layer.
|
|
35
|
-
*
|
|
36
|
-
* A structurally invalid tag makes EVERY `Intl` constructor throw a RangeError:
|
|
37
|
-
* `''`, `'en_US'` (underscore for hyphen — the commonest mistake, and what a
|
|
38
|
-
* POSIX `LANG` value looks like), a truncated tag out of a stored user
|
|
39
|
-
* preference. Unguarded, that RangeError escapes during render, so one bad
|
|
40
|
-
* preference string takes down the whole money surface instead of printing a
|
|
41
|
-
* number with the wrong decimal mark. `Intl.getCanonicalLocales` rejects exactly
|
|
42
|
-
* the tags the formatters reject, so it is the predicate rather than a
|
|
43
|
-
* hand-rolled BCP 47 regex.
|
|
44
|
-
*
|
|
45
|
-
* The locale is the least important input to a figure — the DIGITS are the
|
|
46
|
-
* point — so an unusable tag degrades to the runtime locale and the number still
|
|
47
|
-
* renders.
|
|
48
|
-
*
|
|
49
|
-
* Internal: shared by `format`, `money-text` and `number-input` so they cannot
|
|
50
|
-
* drift. Never exported from `src/domain/index.ts`.
|
|
51
|
-
*/
|
|
52
|
-
function safeLocale(locale) {
|
|
53
|
-
if (locale === undefined)
|
|
54
|
-
return undefined;
|
|
55
|
-
try {
|
|
56
|
-
Intl.getCanonicalLocales(locale);
|
|
57
|
-
return locale;
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
return undefined;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Format a rate as a percent string. `unit` is explicit, never inferred from
|
|
65
|
-
* magnitude: 'ratio' (default) treats `value` as 0..1 and scales ×100;
|
|
66
|
-
* 'percent' treats `value` as already 0..100.
|
|
67
|
-
*
|
|
68
|
-
* Uses Intl style:'percent' for correct rounding and a locale-aware decimal
|
|
69
|
-
* mark. Intl multiplies its input by 100, so we always feed it the RATIO —
|
|
70
|
-
* a 'percent' input is divided by 100 first.
|
|
71
|
-
*/
|
|
72
|
-
function formatPercent(value, options = {}) {
|
|
73
|
-
if (value === null || value === undefined || !Number.isFinite(value))
|
|
74
|
-
return exports.NO_VALUE;
|
|
75
|
-
const { digits = 1, unit = 'ratio', locale } = options;
|
|
76
|
-
// A caller-supplied digit count reaches Intl directly; an out-of-range one
|
|
77
|
-
// would throw a RangeError and take the whole surface down with it.
|
|
78
|
-
if (!isValidDigitCount(digits))
|
|
79
|
-
return exports.NO_VALUE;
|
|
80
|
-
const ratio = unit === 'percent' ? value / 100 : value;
|
|
81
|
-
return new Intl.NumberFormat(safeLocale(locale), {
|
|
82
|
-
style: 'percent',
|
|
83
|
-
minimumFractionDigits: digits,
|
|
84
|
-
maximumFractionDigits: digits
|
|
85
|
-
}).format(ratio);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Normalize a rate to the 0..100 range for chart geometry. `unit` is explicit:
|
|
89
|
-
* 'ratio' (default) scales a 0..1 input ×100; 'percent' is already 0..100.
|
|
90
|
-
*/
|
|
91
|
-
function toPercentValue(value, unit = 'ratio') {
|
|
92
|
-
if (value === null || value === undefined || !Number.isFinite(value))
|
|
93
|
-
return 0;
|
|
94
|
-
const pct = unit === 'percent' ? value : value * 100;
|
|
95
|
-
return Math.max(0, Math.min(100, pct));
|
|
96
|
-
}
|
|
97
|
-
/** Thousands-grouped integer count. `locale` defaults to the runtime locale. */
|
|
98
|
-
function formatCount(value, locale) {
|
|
99
|
-
if (value === null || value === undefined || !Number.isFinite(value))
|
|
100
|
-
return exports.NO_VALUE;
|
|
101
|
-
return new Intl.NumberFormat(safeLocale(locale), {
|
|
102
|
-
maximumFractionDigits: 0
|
|
103
|
-
}).format(value);
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Humanize a millisecond duration into the largest two sensible units.
|
|
107
|
-
* 0ms → "0s". Sub-minute → seconds. Otherwise the two most-significant
|
|
108
|
-
* CONTIGUOUS d/h/m units from the largest non-zero unit down — so "2d 0h 5m"
|
|
109
|
-
* renders as "2d 0h", not the misleading "2d 5m".
|
|
110
|
-
*
|
|
111
|
-
* Note: the d/h/m/s suffixes are English; localizing them is deferred.
|
|
112
|
-
*/
|
|
113
|
-
function humanizeDurationMs(ms) {
|
|
114
|
-
if (ms == null || !Number.isFinite(ms) || ms < 0)
|
|
115
|
-
return exports.NO_VALUE;
|
|
116
|
-
if (ms === 0)
|
|
117
|
-
return '0s';
|
|
118
|
-
const totalSeconds = Math.round(ms / 1000);
|
|
119
|
-
if (totalSeconds < 60)
|
|
120
|
-
return `${totalSeconds}s`;
|
|
121
|
-
const days = Math.floor(totalSeconds / 86400);
|
|
122
|
-
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
123
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
124
|
-
// Two contiguous units starting at the largest non-zero unit, in order.
|
|
125
|
-
const units = [
|
|
126
|
-
[days, 'd'],
|
|
127
|
-
[hours, 'h'],
|
|
128
|
-
[minutes, 'm']
|
|
129
|
-
];
|
|
130
|
-
const start = units.findIndex(([n]) => n > 0);
|
|
131
|
-
if (start === -1)
|
|
132
|
-
return `${minutes}m`;
|
|
133
|
-
return units
|
|
134
|
-
.slice(start, start + 2)
|
|
135
|
-
.map(([n, suffix]) => `${n}${suffix}`)
|
|
136
|
-
.join(' ');
|
|
137
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NO_VALUE=void 0;exports.isValidDigitCount=isValidDigitCount;exports.safeLocale=safeLocale;exports.formatPercent=formatPercent;exports.toPercentValue=toPercentValue;exports.formatCount=formatCount;exports.humanizeDurationMs=humanizeDurationMs;exports.NO_VALUE="\xB7";function isValidDigitCount(t){return Number.isInteger(t)&&t>=0&&t<=100}function safeLocale(t){if(t===void 0)return void 0;try{Intl.getCanonicalLocales(t);return t}catch{return void 0}}function formatPercent(t,n={}){if(t===null||t===void 0||!Number.isFinite(t))return exports.NO_VALUE;const{digits:r=1,unit:o="ratio",locale:e}=n;if(!isValidDigitCount(r))return exports.NO_VALUE;const i=o==="percent"?t/100:t;return new Intl.NumberFormat(safeLocale(e),{style:"percent",minimumFractionDigits:r,maximumFractionDigits:r}).format(i)}function toPercentValue(t,n="ratio"){if(t===null||t===void 0||!Number.isFinite(t))return 0;const r=n==="percent"?t:t*100;return Math.max(0,Math.min(100,r))}function formatCount(t,n){if(t===null||t===void 0||!Number.isFinite(t))return exports.NO_VALUE;return new Intl.NumberFormat(safeLocale(n),{maximumFractionDigits:0}).format(t)}function humanizeDurationMs(t){if(t==null||!Number.isFinite(t)||t<0)return exports.NO_VALUE;if(t===0)return"0s";const n=Math.round(t/1e3);if(n<60)return`${n}s`;const r=Math.floor(n/86400);const o=Math.floor(n%86400/3600);const e=Math.floor(n%3600/60);const i=[[r,"d"],[o,"h"],[e,"m"]];const u=i.findIndex(([s])=>s>0);if(u===-1)return`${e}m`;return i.slice(u,u+2).map(([s,c])=>`${s}${c}`).join(" ")}
|
package/dist/domain/index.js
CHANGED
|
@@ -1,43 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Owned by lane domain — see docs/plans/2026-08-26-sindarian-x-retirement/
|
|
3
|
-
//
|
|
4
|
-
// The finance domain grammar absorbed from @lerianstudio/sindarian-x@0.15.0.
|
|
5
|
-
// Exports are NAMED (never `export *`) on purpose: the port census freezes the
|
|
6
|
-
// public surface to exactly the symbols the four migrating apps import, and the
|
|
7
|
-
// money-math internals (`toMinor`, `Amount`, `sumMinor`, `formatMoneyParts`,
|
|
8
|
-
// `maskKeyId`, `AgingBuckets`, …) stay module-private so they never become an
|
|
9
|
-
// API this package has to keep.
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.DelinquencyAging = exports.gaugeBand = exports.ThresholdGauge = exports.StatusRail = exports.LivePulse = exports.Dot = exports.KeyId = exports.LedgerSheet = exports.LedgerPanel = exports.BlotterRow = exports.Blotter = exports.SectionLabel = exports.Figure = exports.FIGURE_CLASS = exports.MoneyText = exports.moneyDiff = exports.toPercentValue = exports.humanizeDurationMs = exports.formatPercent = exports.formatCount = exports.NO_VALUE = void 0;
|
|
12
|
-
var format_1 = require("./format");
|
|
13
|
-
Object.defineProperty(exports, "NO_VALUE", { enumerable: true, get: function () { return format_1.NO_VALUE; } });
|
|
14
|
-
Object.defineProperty(exports, "formatCount", { enumerable: true, get: function () { return format_1.formatCount; } });
|
|
15
|
-
Object.defineProperty(exports, "formatPercent", { enumerable: true, get: function () { return format_1.formatPercent; } });
|
|
16
|
-
Object.defineProperty(exports, "humanizeDurationMs", { enumerable: true, get: function () { return format_1.humanizeDurationMs; } });
|
|
17
|
-
Object.defineProperty(exports, "toPercentValue", { enumerable: true, get: function () { return format_1.toPercentValue; } });
|
|
18
|
-
var money_diff_1 = require("./money-diff");
|
|
19
|
-
Object.defineProperty(exports, "moneyDiff", { enumerable: true, get: function () { return money_diff_1.moneyDiff; } });
|
|
20
|
-
var money_text_1 = require("./money-text");
|
|
21
|
-
Object.defineProperty(exports, "MoneyText", { enumerable: true, get: function () { return money_text_1.MoneyText; } });
|
|
22
|
-
var figure_1 = require("./figure");
|
|
23
|
-
Object.defineProperty(exports, "FIGURE_CLASS", { enumerable: true, get: function () { return figure_1.FIGURE_CLASS; } });
|
|
24
|
-
Object.defineProperty(exports, "Figure", { enumerable: true, get: function () { return figure_1.Figure; } });
|
|
25
|
-
var section_label_1 = require("./section-label");
|
|
26
|
-
Object.defineProperty(exports, "SectionLabel", { enumerable: true, get: function () { return section_label_1.SectionLabel; } });
|
|
27
|
-
var blotter_1 = require("./blotter");
|
|
28
|
-
Object.defineProperty(exports, "Blotter", { enumerable: true, get: function () { return blotter_1.Blotter; } });
|
|
29
|
-
Object.defineProperty(exports, "BlotterRow", { enumerable: true, get: function () { return blotter_1.BlotterRow; } });
|
|
30
|
-
var ledger_sheet_1 = require("./ledger-sheet");
|
|
31
|
-
Object.defineProperty(exports, "LedgerPanel", { enumerable: true, get: function () { return ledger_sheet_1.LedgerPanel; } });
|
|
32
|
-
Object.defineProperty(exports, "LedgerSheet", { enumerable: true, get: function () { return ledger_sheet_1.LedgerSheet; } });
|
|
33
|
-
var key_id_1 = require("./key-id");
|
|
34
|
-
Object.defineProperty(exports, "KeyId", { enumerable: true, get: function () { return key_id_1.KeyId; } });
|
|
35
|
-
var status_rail_1 = require("./status-rail");
|
|
36
|
-
Object.defineProperty(exports, "Dot", { enumerable: true, get: function () { return status_rail_1.Dot; } });
|
|
37
|
-
Object.defineProperty(exports, "LivePulse", { enumerable: true, get: function () { return status_rail_1.LivePulse; } });
|
|
38
|
-
Object.defineProperty(exports, "StatusRail", { enumerable: true, get: function () { return status_rail_1.StatusRail; } });
|
|
39
|
-
var threshold_gauge_1 = require("./threshold-gauge");
|
|
40
|
-
Object.defineProperty(exports, "ThresholdGauge", { enumerable: true, get: function () { return threshold_gauge_1.ThresholdGauge; } });
|
|
41
|
-
Object.defineProperty(exports, "gaugeBand", { enumerable: true, get: function () { return threshold_gauge_1.gaugeBand; } });
|
|
42
|
-
var delinquency_aging_1 = require("./delinquency-aging");
|
|
43
|
-
Object.defineProperty(exports, "DelinquencyAging", { enumerable: true, get: function () { return delinquency_aging_1.DelinquencyAging; } });
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DelinquencyAging=exports.gaugeBand=exports.ThresholdGauge=exports.StatusRail=exports.LivePulse=exports.Dot=exports.KeyId=exports.LedgerSheet=exports.LedgerPanel=exports.BlotterRow=exports.Blotter=exports.SectionLabel=exports.Figure=exports.FIGURE_CLASS=exports.MoneyText=exports.moneyDiff=exports.toPercentValue=exports.humanizeDurationMs=exports.formatPercent=exports.formatCount=exports.NO_VALUE=void 0;var format_1=require("./format");Object.defineProperty(exports,"NO_VALUE",{enumerable:true,get:function(){return format_1.NO_VALUE}});Object.defineProperty(exports,"formatCount",{enumerable:true,get:function(){return format_1.formatCount}});Object.defineProperty(exports,"formatPercent",{enumerable:true,get:function(){return format_1.formatPercent}});Object.defineProperty(exports,"humanizeDurationMs",{enumerable:true,get:function(){return format_1.humanizeDurationMs}});Object.defineProperty(exports,"toPercentValue",{enumerable:true,get:function(){return format_1.toPercentValue}});var money_diff_1=require("./money-diff");Object.defineProperty(exports,"moneyDiff",{enumerable:true,get:function(){return money_diff_1.moneyDiff}});var money_text_1=require("./money-text");Object.defineProperty(exports,"MoneyText",{enumerable:true,get:function(){return money_text_1.MoneyText}});var figure_1=require("./figure");Object.defineProperty(exports,"FIGURE_CLASS",{enumerable:true,get:function(){return figure_1.FIGURE_CLASS}});Object.defineProperty(exports,"Figure",{enumerable:true,get:function(){return figure_1.Figure}});var section_label_1=require("./section-label");Object.defineProperty(exports,"SectionLabel",{enumerable:true,get:function(){return section_label_1.SectionLabel}});var blotter_1=require("./blotter");Object.defineProperty(exports,"Blotter",{enumerable:true,get:function(){return blotter_1.Blotter}});Object.defineProperty(exports,"BlotterRow",{enumerable:true,get:function(){return blotter_1.BlotterRow}});var ledger_sheet_1=require("./ledger-sheet");Object.defineProperty(exports,"LedgerPanel",{enumerable:true,get:function(){return ledger_sheet_1.LedgerPanel}});Object.defineProperty(exports,"LedgerSheet",{enumerable:true,get:function(){return ledger_sheet_1.LedgerSheet}});var key_id_1=require("./key-id");Object.defineProperty(exports,"KeyId",{enumerable:true,get:function(){return key_id_1.KeyId}});var status_rail_1=require("./status-rail");Object.defineProperty(exports,"Dot",{enumerable:true,get:function(){return status_rail_1.Dot}});Object.defineProperty(exports,"LivePulse",{enumerable:true,get:function(){return status_rail_1.LivePulse}});Object.defineProperty(exports,"StatusRail",{enumerable:true,get:function(){return status_rail_1.StatusRail}});var threshold_gauge_1=require("./threshold-gauge");Object.defineProperty(exports,"ThresholdGauge",{enumerable:true,get:function(){return threshold_gauge_1.ThresholdGauge}});Object.defineProperty(exports,"gaugeBand",{enumerable:true,get:function(){return threshold_gauge_1.gaugeBand}});var delinquency_aging_1=require("./delinquency-aging");Object.defineProperty(exports,"DelinquencyAging",{enumerable:true,get:function(){return delinquency_aging_1.DelinquencyAging}});
|
|
@@ -1,174 +1 @@
|
|
|
1
|
-
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.masksByDefault = masksByDefault;
|
|
5
|
-
exports.maskKeyId = maskKeyId;
|
|
6
|
-
exports.KeyId = KeyId;
|
|
7
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
-
/**
|
|
9
|
-
* KeyId — a masked, copyable, traceable identifier for Brazilian rails: a Pix
|
|
10
|
-
* key (CPF / CNPJ / email / phone / EVP-random), an End-to-End id (E2E), an
|
|
11
|
-
* idempotency key, or a generic id.
|
|
12
|
-
*
|
|
13
|
-
* Two jobs at once. PII keys (CPF/CNPJ/email/phone) are masked by default so a
|
|
14
|
-
* shared screen or a screenshot doesn't leak a person's document or contact —
|
|
15
|
-
* the middle of a document is revealed, the identifying head/tail is dotted.
|
|
16
|
-
* Long-but-not-secret ids (EVP/E2E/idempotency/generic) are merely truncated in
|
|
17
|
-
* the MIDDLE so the head and tail — the parts an operator eyeballs against a
|
|
18
|
-
* log — stay legible.
|
|
19
|
-
*
|
|
20
|
-
* <KeyId value="529.982.247-25" kind="pix-cpf" label="Payer" copyable />
|
|
21
|
-
* <KeyId value="E32074158202406211200abc123def456" kind="e2e" copyable />
|
|
22
|
-
*
|
|
23
|
-
* The copy button always lifts the RAW, unmasked value to the clipboard — the
|
|
24
|
-
* mask is a display concern, never a data one. The masked render and the copy
|
|
25
|
-
* affordance are what make this a client component.
|
|
26
|
-
*/
|
|
27
|
-
const lucide_react_1 = require("lucide-react");
|
|
28
|
-
const react_1 = require("react");
|
|
29
|
-
const typography_1 = require("../../lib/typography");
|
|
30
|
-
const utils_1 = require("../../lib/utils");
|
|
31
|
-
/** The dot used to redact a character. A bullet, not an asterisk: it reads as
|
|
32
|
-
* "hidden" without looking like a password field's shouting. */
|
|
33
|
-
const DOT = '•';
|
|
34
|
-
/** Kinds that carry PII and are masked by default. The id-shaped kinds are long
|
|
35
|
-
* but not secret, so they default to revealed (just truncated). */
|
|
36
|
-
const PII_KINDS = new Set([
|
|
37
|
-
'pix-cpf',
|
|
38
|
-
'pix-cnpj',
|
|
39
|
-
'pix-email',
|
|
40
|
-
'pix-phone'
|
|
41
|
-
]);
|
|
42
|
-
/** Whether a kind masks by default (PII) — used when `mask` is not supplied.
|
|
43
|
-
* Internal: exported for its unit tests, never from `src/domain/index.ts`. */
|
|
44
|
-
function masksByDefault(kind) {
|
|
45
|
-
return PII_KINDS.has(kind);
|
|
46
|
-
}
|
|
47
|
-
/** Keep only the digits — Brazilian documents arrive punctuated or bare. */
|
|
48
|
-
function digitsOf(value) {
|
|
49
|
-
return value.replace(/\D/g, '');
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Truncate the MIDDLE of a long value, keeping a head and tail so an operator
|
|
53
|
-
* can eyeball it against a log. Short values are returned whole.
|
|
54
|
-
*/
|
|
55
|
-
function truncateMiddle(value, head = 6, tail = 4) {
|
|
56
|
-
if (value.length <= head + tail + 1)
|
|
57
|
-
return value;
|
|
58
|
-
return `${value.slice(0, head)}…${value.slice(-tail)}`;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* The fallback for a PII value that is MALFORMED for its kind. It must not be
|
|
62
|
-
* `truncateMiddle`: a short malformed value (a CPF missing a digit, a hand-typed
|
|
63
|
-
* document, a name-shaped email that failed the `@` check) is returned WHOLE by
|
|
64
|
-
* truncation, so the "masked" render leaks the very PII the mask exists to hide.
|
|
65
|
-
* A fixed-width dot run reveals nothing — not the content, not even the length.
|
|
66
|
-
*
|
|
67
|
-
* DELIBERATE DIVERGENCE from sindarian-x@0.15.0, which truncated instead. It
|
|
68
|
-
* costs the operator the ability to eyeball a malformed document against a log;
|
|
69
|
-
* that is the correct trade, because the alternative is a screenshot with a real
|
|
70
|
-
* CPF in it. An operator who needs the value passes `mask={false}` explicitly.
|
|
71
|
-
*/
|
|
72
|
-
function redactPii() {
|
|
73
|
-
return DOT.repeat(6);
|
|
74
|
-
}
|
|
75
|
-
/** Mask all but the central block of a digit string, then re-punctuate it. */
|
|
76
|
-
function maskCpf(value) {
|
|
77
|
-
const d = digitsOf(value);
|
|
78
|
-
if (d.length !== 11)
|
|
79
|
-
return redactPii();
|
|
80
|
-
// Reveal the middle two blocks (456.789), dot the leading block and check digits.
|
|
81
|
-
return `${DOT.repeat(3)}.${d.slice(3, 6)}.${d.slice(6, 9)}-${DOT.repeat(2)}`;
|
|
82
|
-
}
|
|
83
|
-
function maskCnpj(value) {
|
|
84
|
-
const d = digitsOf(value);
|
|
85
|
-
if (d.length !== 14)
|
|
86
|
-
return redactPii();
|
|
87
|
-
// Reveal the central registration blocks, dot the head and the check digits.
|
|
88
|
-
return `${DOT.repeat(2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${DOT.repeat(2)}`;
|
|
89
|
-
}
|
|
90
|
-
function maskEmail(value) {
|
|
91
|
-
const at = value.indexOf('@');
|
|
92
|
-
if (at <= 0 || at === value.length - 1)
|
|
93
|
-
return redactPii();
|
|
94
|
-
// EXACTLY one '@', or it is not an address and the domain half cannot be
|
|
95
|
-
// trusted to be a domain. `a@private@domain.test` split on the FIRST '@' and
|
|
96
|
-
// published `private@domain.test` verbatim as the "domain" — the local part of
|
|
97
|
-
// a second address, revealed in a view whose whole purpose is to hide it.
|
|
98
|
-
// Malformed PII redacts, exactly like a wrong-length CPF.
|
|
99
|
-
if (value.indexOf('@', at + 1) !== -1)
|
|
100
|
-
return redactPii();
|
|
101
|
-
const first = value.slice(0, 1);
|
|
102
|
-
const domain = value.slice(at + 1);
|
|
103
|
-
return `${first}${DOT.repeat(3)}@${domain}`;
|
|
104
|
-
}
|
|
105
|
-
function maskPhone(value) {
|
|
106
|
-
const d = digitsOf(value);
|
|
107
|
-
// Expect a BR mobile in E.164-ish form: 55 + 2-digit area + 9 subscriber digits.
|
|
108
|
-
if (d.length !== 13 || !d.startsWith('55'))
|
|
109
|
-
return redactPii();
|
|
110
|
-
const area = d.slice(2, 4);
|
|
111
|
-
const last2 = d.slice(-2);
|
|
112
|
-
// Keep country + area, reveal the last two, dot the rest of the subscriber run.
|
|
113
|
-
return `+55 (${area}) ${DOT.repeat(5)}-${DOT.repeat(2)}${last2}`;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Mask a key for display. PII kinds get a structured mask that reveals a
|
|
117
|
-
* non-identifying middle and dots the rest; a value MALFORMED for its kind is
|
|
118
|
-
* redacted outright (see `redactPii`) rather than truncated, so a mask can never
|
|
119
|
-
* fall through to the raw secret. Id-shaped kinds are always middle-truncated
|
|
120
|
-
* (long, not secret). The copy path never uses this — it always sends the raw
|
|
121
|
-
* value.
|
|
122
|
-
*
|
|
123
|
-
* Internal: exported for its unit tests, never from `src/domain/index.ts`.
|
|
124
|
-
*/
|
|
125
|
-
function maskKeyId(value, kind) {
|
|
126
|
-
switch (kind) {
|
|
127
|
-
case 'pix-cpf':
|
|
128
|
-
return maskCpf(value);
|
|
129
|
-
case 'pix-cnpj':
|
|
130
|
-
return maskCnpj(value);
|
|
131
|
-
case 'pix-email':
|
|
132
|
-
return maskEmail(value);
|
|
133
|
-
case 'pix-phone':
|
|
134
|
-
return maskPhone(value);
|
|
135
|
-
default:
|
|
136
|
-
return truncateMiddle(value);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function KeyId({ value, kind = 'generic', label, mask, copyable = false, className }) {
|
|
140
|
-
const masked = mask ?? masksByDefault(kind);
|
|
141
|
-
const display = masked ? maskKeyId(value, kind) : truncateMiddle(value);
|
|
142
|
-
return ((0, jsx_runtime_1.jsxs)("span", { className: (0, utils_1.cn)('inline-flex min-w-0 items-center gap-2', className), children: [label ? ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(typography_1.LABEL_VOICE_CLASS, 'shrink-0 text-xs'), children: label })) : null, (0, jsx_runtime_1.jsx)("span", { className: "text-foreground truncate font-mono text-xs tabular-nums",
|
|
143
|
-
// The raw value as a tooltip only when nothing is hidden — never leak a
|
|
144
|
-
// masked PII value through the title attribute.
|
|
145
|
-
title: masked ? undefined : value, children: display }), copyable ? (0, jsx_runtime_1.jsx)(CopyValue, { value: value }) : null] }));
|
|
146
|
-
}
|
|
147
|
-
/** The copy affordance: lifts the RAW value to the clipboard and flips to a
|
|
148
|
-
* check for a beat. The transient confirmation is announced for assistive tech;
|
|
149
|
-
* the icon is paired with a text aria-label so the state isn't color-only. */
|
|
150
|
-
function CopyValue({ value }) {
|
|
151
|
-
const [copied, setCopied] = (0, react_1.useState)(false);
|
|
152
|
-
const copy = () => {
|
|
153
|
-
// ponytail: best-effort clipboard write — no toast, no error surface. The
|
|
154
|
-
// ceiling is silent failure in an insecure context (clipboard unavailable);
|
|
155
|
-
// upgrade path is to lift a result up via an onCopy callback when a caller
|
|
156
|
-
// needs to react.
|
|
157
|
-
//
|
|
158
|
-
// The rejection handler is NOT optional: `writeText` rejects on a denied
|
|
159
|
-
// permission or a non-secure context, and an unhandled rejection in a render
|
|
160
|
-
// tree is a console error at best and a crashed handler at worst. On failure
|
|
161
|
-
// the button simply does not flip to the copied state, so the operator sees
|
|
162
|
-
// that nothing was copied rather than a false confirmation.
|
|
163
|
-
void navigator.clipboard
|
|
164
|
-
?.writeText(value)
|
|
165
|
-
.then(() => {
|
|
166
|
-
setCopied(true);
|
|
167
|
-
setTimeout(() => setCopied(false), 1500);
|
|
168
|
-
})
|
|
169
|
-
.catch(() => {
|
|
170
|
-
setCopied(false);
|
|
171
|
-
});
|
|
172
|
-
};
|
|
173
|
-
return ((0, jsx_runtime_1.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 ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { "aria-hidden": true, className: "text-system-success-h1a size-3" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { "aria-hidden": true, className: "size-3" })) }));
|
|
174
|
-
}
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.masksByDefault=masksByDefault;exports.maskKeyId=maskKeyId;exports.KeyId=KeyId;const jsx_runtime_1=require("react/jsx-runtime");const lucide_react_1=require("lucide-react");const react_1=require("react");const typography_1=require("../../lib/typography");const utils_1=require("../../lib/utils");const DOT="\u2022";const PII_KINDS=new Set(["pix-cpf","pix-cnpj","pix-email","pix-phone"]);function masksByDefault(e){return PII_KINDS.has(e)}function digitsOf(e){return e.replace(/\D/g,"")}function truncateMiddle(e,t=6,n=4){if(e.length<=t+n+1)return e;return`${e.slice(0,t)}\u2026${e.slice(-n)}`}function redactPii(){return DOT.repeat(6)}function maskCpf(e){const t=digitsOf(e);if(t.length!==11)return redactPii();return`${DOT.repeat(3)}.${t.slice(3,6)}.${t.slice(6,9)}-${DOT.repeat(2)}`}function maskCnpj(e){const t=digitsOf(e);if(t.length!==14)return redactPii();return`${DOT.repeat(2)}.${t.slice(2,5)}.${t.slice(5,8)}/${t.slice(8,12)}-${DOT.repeat(2)}`}function maskEmail(e){const t=e.indexOf("@");if(t<=0||t===e.length-1)return redactPii();if(e.indexOf("@",t+1)!==-1)return redactPii();const n=e.slice(0,1);const r=e.slice(t+1);return`${n}${DOT.repeat(3)}@${r}`}function maskPhone(e){const t=digitsOf(e);if(t.length!==13||!t.startsWith("55"))return redactPii();const n=t.slice(2,4);const r=t.slice(-2);return`+55 (${n}) ${DOT.repeat(5)}-${DOT.repeat(2)}${r}`}function maskKeyId(e,t){switch(t){case"pix-cpf":return maskCpf(e);case"pix-cnpj":return maskCnpj(e);case"pix-email":return maskEmail(e);case"pix-phone":return maskPhone(e);default:return truncateMiddle(e)}}function KeyId({value:e,kind:t="generic",label:n,mask:r,copyable:i=false,className:c}){const s=r??masksByDefault(t);const a=s?maskKeyId(e,t):truncateMiddle(e);return(0,jsx_runtime_1.jsxs)("span",{className:(0,utils_1.cn)("inline-flex min-w-0 items-center gap-2",c),children:[n?(0,jsx_runtime_1.jsx)("span",{className:(0,utils_1.cn)(typography_1.LABEL_VOICE_CLASS,"shrink-0 text-xs"),children:n}):null,(0,jsx_runtime_1.jsx)("span",{className:"text-foreground truncate font-mono text-xs tabular-nums",title:s?void 0:e,children:a}),i?(0,jsx_runtime_1.jsx)(CopyValue,{value:e}):null]})}function CopyValue({value:e}){const[t,n]=(0,react_1.useState)(false);const r=()=>{void navigator.clipboard?.writeText(e).then(()=>{n(true);setTimeout(()=>n(false),1500)}).catch(()=>{n(false)})};return(0,jsx_runtime_1.jsx)("button",{type:"button",onClick:r,"aria-label":t?"Copiado para a \xE1rea de transfer\xEAncia":"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:t?(0,jsx_runtime_1.jsx)(lucide_react_1.Check,{"aria-hidden":true,className:"text-system-success-h1a size-3"}):(0,jsx_runtime_1.jsx)(lucide_react_1.Copy,{"aria-hidden":true,className:"size-3"})})}
|
|
@@ -1,28 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LedgerSheet = LedgerSheet;
|
|
4
|
-
exports.LedgerPanel = LedgerPanel;
|
|
5
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
-
const utils_1 = require("../../lib/utils");
|
|
7
|
-
/** Tailwind needs literal class names to survive purge; map cols → class. */
|
|
8
|
-
const COLS_CLASS = {
|
|
9
|
-
1: 'lg:grid-cols-1',
|
|
10
|
-
2: 'lg:grid-cols-2',
|
|
11
|
-
3: 'lg:grid-cols-3',
|
|
12
|
-
4: 'lg:grid-cols-4'
|
|
13
|
-
};
|
|
14
|
-
function LedgerSheet({ children, cols = 1, className }) {
|
|
15
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('border-border bg-border grid grid-cols-1 gap-px overflow-hidden rounded-lg border', COLS_CLASS[cols] ?? COLS_CLASS[1], className), children: children }));
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* One cell of a ledger sheet. Flush — no own border or shadow — with `bg-card`,
|
|
19
|
-
* internal `p-5` padding and `flex h-full flex-col gap-4` so panels stretch to
|
|
20
|
-
* equal height. Start each panel with a `<SectionLabel>` as its heading.
|
|
21
|
-
*
|
|
22
|
-
* Remaining props land on the rendered element, so a composed panel can carry
|
|
23
|
-
* its own `data-*` hooks (StatCard's `data-tone`, for one) without wrapping the
|
|
24
|
-
* cell in an extra div that would break the hairline seams.
|
|
25
|
-
*/
|
|
26
|
-
function LedgerPanel({ children, className, as: Tag = 'section', ...rest }) {
|
|
27
|
-
return ((0, jsx_runtime_1.jsx)(Tag, { className: (0, utils_1.cn)('bg-card flex h-full flex-col gap-4 p-5', className), ...rest, children: children }));
|
|
28
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.LedgerSheet=LedgerSheet;exports.LedgerPanel=LedgerPanel;const jsx_runtime_1=require("react/jsx-runtime");const utils_1=require("../../lib/utils");const COLS_CLASS={1:"lg:grid-cols-1",2:"lg:grid-cols-2",3:"lg:grid-cols-3",4:"lg:grid-cols-4"};function LedgerSheet({children:e,cols:r=1,className:l}){return(0,jsx_runtime_1.jsx)("div",{className:(0,utils_1.cn)("border-border bg-border grid grid-cols-1 gap-px overflow-hidden rounded-lg border",COLS_CLASS[r]??COLS_CLASS[1],l),children:e})}function LedgerPanel({children:e,className:r,as:l="section",...s}){return(0,jsx_runtime_1.jsx)(l,{className:(0,utils_1.cn)("bg-card flex h-full flex-col gap-4 p-5",r),...s,children:e})}
|
|
@@ -1,48 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.moneyDiff = moneyDiff;
|
|
4
|
-
/**
|
|
5
|
-
* moneyDiff — the signed difference between two reconciliation sides, computed
|
|
6
|
-
* on integer minor units and never on floats.
|
|
7
|
-
*
|
|
8
|
-
* THIRD RAIL (money): `left − right` runs through `toMinor` on both operands →
|
|
9
|
-
* BigInt subtraction → `minorToDecimal`, and the tolerance breach test compares
|
|
10
|
-
* MAGNITUDES in minor units. A float subtraction of two decimals would drift by
|
|
11
|
-
* a cent at reconciliation scale, which is the difference between a matched and
|
|
12
|
-
* an unmatched pair.
|
|
13
|
-
*
|
|
14
|
-
* A null `decimal` means an unparseable operand — surfaced, never coerced to
|
|
15
|
-
* zero, so a caller renders the no-value placeholder rather than a fabricated
|
|
16
|
-
* tie.
|
|
17
|
-
*/
|
|
18
|
-
const money_math_1 = require("./money-math");
|
|
19
|
-
function moneyDiff(money) {
|
|
20
|
-
const scale = money.minorDigits ?? (0, money_math_1.minorDigitsOf)(money.currency);
|
|
21
|
-
const l = (0, money_math_1.toMinor)(money.left, scale);
|
|
22
|
-
const r = (0, money_math_1.toMinor)(money.right, scale);
|
|
23
|
-
if (l === null || r === null)
|
|
24
|
-
return { decimal: null, breach: false };
|
|
25
|
-
const diff = l - r;
|
|
26
|
-
// A tolerance that was SUPPLIED but does not parse ('', 'oops', '-.') is not
|
|
27
|
-
// the same thing as no tolerance at all. Degrading to the no-tolerance rule
|
|
28
|
-
// made every nonzero difference a breach, so one typo in a tolerance field
|
|
29
|
-
// turned a reconciled book into a screen of false breaches — the loudest
|
|
30
|
-
// possible wrong answer. A supplied-invalid tolerance is INDETERMINATE,
|
|
31
|
-
// exactly like an unparseable operand: no number, no verdict.
|
|
32
|
-
const supplied = money.tolerance != null;
|
|
33
|
-
const rawTol = supplied ? (0, money_math_1.toMinor)(money.tolerance, scale) : null;
|
|
34
|
-
if (supplied && rawTol === null)
|
|
35
|
-
return { decimal: null, breach: false };
|
|
36
|
-
// A tolerance is a BAND WIDTH, so only its magnitude is meaningful. Taken
|
|
37
|
-
// signed, a negative tolerance made `|diff| > tol` true for every value
|
|
38
|
-
// including an exact tie (0n > -5n), flagging perfectly reconciled pairs as
|
|
39
|
-
// breaches. Normalizing to the magnitude means `-0.05` and `0.05` describe the
|
|
40
|
-
// same band, which is the only reading of a negative tolerance that is not a
|
|
41
|
-
// silent false alarm.
|
|
42
|
-
const tol = rawTol === null ? null : rawTol < 0n ? -rawTol : rawTol;
|
|
43
|
-
const abs = diff < 0n ? -diff : diff;
|
|
44
|
-
// A breach is a magnitude STRICTLY beyond the band; no tolerance → no band, so
|
|
45
|
-
// any nonzero difference is itself the breach.
|
|
46
|
-
const breach = tol === null ? diff !== 0n : abs > tol;
|
|
47
|
-
return { decimal: (0, money_math_1.minorToDecimal)(diff, scale), breach };
|
|
48
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.moneyDiff=moneyDiff;const money_math_1=require("./money-math");function moneyDiff(n){const e=n.minorDigits??(0,money_math_1.minorDigitsOf)(n.currency);const r=(0,money_math_1.toMinor)(n.left,e);const o=(0,money_math_1.toMinor)(n.right,e);if(r===null||o===null)return{decimal:null,breach:false};const l=r-o;const c=n.tolerance!=null;const t=c?(0,money_math_1.toMinor)(n.tolerance,e):null;if(c&&t===null)return{decimal:null,breach:false};const i=t===null?null:t<0n?-t:t;const s=l<0n?-l:l;const u=i===null?l!==0n:s>i;return{decimal:(0,money_math_1.minorToDecimal)(l,e),breach:u}}
|
|
@@ -1,104 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* money-math — exact integer-minor-unit arithmetic for the double-entry third rail.
|
|
4
|
-
*
|
|
5
|
-
* INTERNAL to the domain layer: nothing here is re-exported from
|
|
6
|
-
* `src/domain/index.ts`, so `toMinor`/`Amount`/`sumMinor` are NOT part of
|
|
7
|
-
* `@lerianstudio/sindarian-ui`'s public API. The consumers that need exact money
|
|
8
|
-
* arithmetic reach it through the components that own it (`moneyDiff`,
|
|
9
|
-
* `MoneyText`, `DelinquencyAging`).
|
|
10
|
-
*
|
|
11
|
-
* Amounts parse to integer minor units (BigInt) at a fixed scale; sums never
|
|
12
|
-
* round-trip through IEEE-754. Pass amounts as canonical decimal STRINGS for
|
|
13
|
-
* lossless math — numbers are converted via toFixed, which is float-bounded
|
|
14
|
-
* (fine for display-scale magnitudes, exact for strings).
|
|
15
|
-
*/
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.toMinor = toMinor;
|
|
18
|
-
exports.sumMinor = sumMinor;
|
|
19
|
-
exports.minorDigitsOf = minorDigitsOf;
|
|
20
|
-
exports.minorToDecimal = minorToDecimal;
|
|
21
|
-
const format_1 = require("./format");
|
|
22
|
-
// Round half-away-from-zero on the first dropped fraction digit.
|
|
23
|
-
function roundsUp(fraction, scale) {
|
|
24
|
-
return fraction.length > scale && fraction.charCodeAt(scale) - 48 >= 5;
|
|
25
|
-
}
|
|
26
|
-
/** Normalize to a canonical signed decimal: trim, unicode-minus, accounting parens. */
|
|
27
|
-
function canonical(raw) {
|
|
28
|
-
let s = raw.trim().replace(/−/g, '-');
|
|
29
|
-
if (/^\(.*\)$/.test(s))
|
|
30
|
-
s = '-' + s.slice(1, -1).trim(); // (1.23) -> -1.23
|
|
31
|
-
return s;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Amount -> integer minor units at `scale`, or null if unparseable.
|
|
35
|
-
*
|
|
36
|
-
* `scale` is validated before it reaches `toFixed`/`repeat`: an out-of-range
|
|
37
|
-
* scale (a caller passing `minorDigits: -1`) would throw a RangeError mid-render
|
|
38
|
-
* rather than degrade. It is the single choke point every money path in this
|
|
39
|
-
* layer routes through (`sumMinor`, `moneyDiff`, `delinquencyRate`,
|
|
40
|
-
* `sumBucketTotals`), so guarding it here guards all of them.
|
|
41
|
-
*/
|
|
42
|
-
function toMinor(value, scale) {
|
|
43
|
-
if (!(0, format_1.isValidDigitCount)(scale))
|
|
44
|
-
return null;
|
|
45
|
-
if (value === null || value === undefined || value === '')
|
|
46
|
-
return null;
|
|
47
|
-
let s = typeof value === 'number'
|
|
48
|
-
? Number.isFinite(value)
|
|
49
|
-
? value.toFixed(scale)
|
|
50
|
-
: ''
|
|
51
|
-
: canonical(value);
|
|
52
|
-
if (s === '' || s === '-' || s === '.' || !/^-?\d*(\.\d*)?$/.test(s))
|
|
53
|
-
return null;
|
|
54
|
-
const neg = s.startsWith('-');
|
|
55
|
-
if (neg)
|
|
56
|
-
s = s.slice(1);
|
|
57
|
-
const [intPart = '', fracPart = ''] = s.split('.');
|
|
58
|
-
// DELIBERATE DIVERGENCE from sindarian-x@0.15.0: the legacy regex admits a
|
|
59
|
-
// digitless token ('-.', and '.' once the sign is stripped) and coerced it to
|
|
60
|
-
// an exact 0n. A fabricated exact zero is the worst possible answer in
|
|
61
|
-
// reconciliation — it reads as a perfect tie and hides the bad input — so a
|
|
62
|
-
// digitless amount is now indeterminate (null), like every other garbage
|
|
63
|
-
// token. This mirrors the guard the legacy `rateFraction` already had.
|
|
64
|
-
if (intPart === '' && fracPart === '')
|
|
65
|
-
return null;
|
|
66
|
-
const frac = (fracPart + '0'.repeat(scale)).slice(0, scale);
|
|
67
|
-
let minor = BigInt((intPart || '0') + frac);
|
|
68
|
-
if (roundsUp(fracPart, scale))
|
|
69
|
-
minor += 1n;
|
|
70
|
-
return neg ? -minor : minor;
|
|
71
|
-
}
|
|
72
|
-
/** Sum amounts to minor units; null if ANY operand is unparseable (indeterminate). */
|
|
73
|
-
function sumMinor(values, scale) {
|
|
74
|
-
let total = 0n;
|
|
75
|
-
for (const v of values) {
|
|
76
|
-
const m = toMinor(v, scale);
|
|
77
|
-
if (m === null)
|
|
78
|
-
return null;
|
|
79
|
-
total += m;
|
|
80
|
-
}
|
|
81
|
-
return total;
|
|
82
|
-
}
|
|
83
|
-
/** Currency's minor-unit digit count via CLDR (BRL/USD->2, JPY->0, BHD->3), or fallback. */
|
|
84
|
-
function minorDigitsOf(currency, fallback = 2) {
|
|
85
|
-
try {
|
|
86
|
-
const opts = new Intl.NumberFormat('en', {
|
|
87
|
-
style: 'currency',
|
|
88
|
-
currency,
|
|
89
|
-
currencyDisplay: 'code'
|
|
90
|
-
}).resolvedOptions();
|
|
91
|
-
return opts.maximumFractionDigits ?? fallback;
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return fallback;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/** Minor units -> canonical decimal string (lossless), for handing to MoneyText. */
|
|
98
|
-
function minorToDecimal(minor, scale) {
|
|
99
|
-
const neg = minor < 0n;
|
|
100
|
-
const abs = (neg ? -minor : minor).toString().padStart(scale + 1, '0');
|
|
101
|
-
const intPart = abs.slice(0, abs.length - scale) || '0';
|
|
102
|
-
const fracPart = scale > 0 ? '.' + abs.slice(abs.length - scale) : '';
|
|
103
|
-
return (neg ? '-' : '') + intPart + fracPart;
|
|
104
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.toMinor=toMinor;exports.sumMinor=sumMinor;exports.minorDigitsOf=minorDigitsOf;exports.minorToDecimal=minorToDecimal;const format_1=require("./format");function roundsUp(n,t){return n.length>t&&n.charCodeAt(t)-48>=5}function canonical(n){let t=n.trim().replace(/−/g,"-");if(/^\(.*\)$/.test(t))t="-"+t.slice(1,-1).trim();return t}function toMinor(n,t){if(!(0,format_1.isValidDigitCount)(t))return null;if(n===null||n===void 0||n==="")return null;let r=typeof n==="number"?Number.isFinite(n)?n.toFixed(t):"":canonical(n);if(r===""||r==="-"||r==="."||!/^-?\d*(\.\d*)?$/.test(r))return null;const i=r.startsWith("-");if(i)r=r.slice(1);const[e="",o=""]=r.split(".");if(e===""&&o==="")return null;const u=(o+"0".repeat(t)).slice(0,t);let s=BigInt((e||"0")+u);if(roundsUp(o,t))s+=1n;return i?-s:s}function sumMinor(n,t){let r=0n;for(const i of n){const e=toMinor(i,t);if(e===null)return null;r+=e}return r}function minorDigitsOf(n,t=2){try{const r=new Intl.NumberFormat("en",{style:"currency",currency:n,currencyDisplay:"code"}).resolvedOptions();return r.maximumFractionDigits??t}catch{return t}}function minorToDecimal(n,t){const r=n<0n;const i=(r?-n:n).toString().padStart(t+1,"0");const e=i.slice(0,i.length-t)||"0";const o=t>0?"."+i.slice(i.length-t):"";return(r?"-":"")+e+o}
|