@joanroucoux/cairn-ui 0.8.1 → 0.9.0

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 (125) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +2 -0
  3. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs +57 -53
  4. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs.map +1 -1
  5. package/fesm2022/joanroucoux-cairn-ui-alert.mjs +155 -47
  6. package/fesm2022/joanroucoux-cairn-ui-alert.mjs.map +1 -1
  7. package/fesm2022/joanroucoux-cairn-ui-amount.mjs +220 -110
  8. package/fesm2022/joanroucoux-cairn-ui-amount.mjs.map +1 -1
  9. package/fesm2022/joanroucoux-cairn-ui-async.mjs +392 -216
  10. package/fesm2022/joanroucoux-cairn-ui-async.mjs.map +1 -1
  11. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs +145 -68
  12. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs.map +1 -1
  13. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs +87 -47
  14. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs.map +1 -1
  15. package/fesm2022/joanroucoux-cairn-ui-badge.mjs +83 -43
  16. package/fesm2022/joanroucoux-cairn-ui-badge.mjs.map +1 -1
  17. package/fesm2022/joanroucoux-cairn-ui-button.mjs +184 -104
  18. package/fesm2022/joanroucoux-cairn-ui-button.mjs.map +1 -1
  19. package/fesm2022/joanroucoux-cairn-ui-card.mjs +232 -137
  20. package/fesm2022/joanroucoux-cairn-ui-card.mjs.map +1 -1
  21. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs +298 -102
  22. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs.map +1 -1
  23. package/fesm2022/joanroucoux-cairn-ui-control.mjs +4 -17
  24. package/fesm2022/joanroucoux-cairn-ui-control.mjs.map +1 -1
  25. package/fesm2022/joanroucoux-cairn-ui-delta.mjs +150 -83
  26. package/fesm2022/joanroucoux-cairn-ui-delta.mjs.map +1 -1
  27. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs +508 -471
  28. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs.map +1 -1
  29. package/fesm2022/joanroucoux-cairn-ui-donut.mjs +255 -157
  30. package/fesm2022/joanroucoux-cairn-ui-donut.mjs.map +1 -1
  31. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs +303 -0
  32. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs.map +1 -0
  33. package/fesm2022/joanroucoux-cairn-ui-empty.mjs +76 -35
  34. package/fesm2022/joanroucoux-cairn-ui-empty.mjs.map +1 -1
  35. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs +40 -31
  36. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs.map +1 -1
  37. package/fesm2022/joanroucoux-cairn-ui-fact.mjs +188 -79
  38. package/fesm2022/joanroucoux-cairn-ui-fact.mjs.map +1 -1
  39. package/fesm2022/joanroucoux-cairn-ui-field.mjs +309 -173
  40. package/fesm2022/joanroucoux-cairn-ui-field.mjs.map +1 -1
  41. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs +165 -87
  42. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs.map +1 -1
  43. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs +269 -0
  44. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs.map +1 -0
  45. package/fesm2022/joanroucoux-cairn-ui-input.mjs +205 -85
  46. package/fesm2022/joanroucoux-cairn-ui-input.mjs.map +1 -1
  47. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs +838 -512
  48. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs.map +1 -1
  49. package/fesm2022/joanroucoux-cairn-ui-menu.mjs +401 -225
  50. package/fesm2022/joanroucoux-cairn-ui-menu.mjs.map +1 -1
  51. package/fesm2022/joanroucoux-cairn-ui-meter.mjs +143 -57
  52. package/fesm2022/joanroucoux-cairn-ui-meter.mjs.map +1 -1
  53. package/fesm2022/joanroucoux-cairn-ui-motion.mjs +367 -399
  54. package/fesm2022/joanroucoux-cairn-ui-motion.mjs.map +1 -1
  55. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs +73 -44
  56. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs.map +1 -1
  57. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs +191 -0
  58. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs.map +1 -0
  59. package/fesm2022/joanroucoux-cairn-ui-row.mjs +376 -146
  60. package/fesm2022/joanroucoux-cairn-ui-row.mjs.map +1 -1
  61. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs +183 -81
  62. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs.map +1 -1
  63. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs +233 -0
  64. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs.map +1 -0
  65. package/fesm2022/joanroucoux-cairn-ui-select.mjs +121 -67
  66. package/fesm2022/joanroucoux-cairn-ui-select.mjs.map +1 -1
  67. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs +129 -51
  68. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs.map +1 -1
  69. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs +80 -39
  70. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs.map +1 -1
  71. package/fesm2022/joanroucoux-cairn-ui-stat.mjs +85 -55
  72. package/fesm2022/joanroucoux-cairn-ui-stat.mjs.map +1 -1
  73. package/fesm2022/joanroucoux-cairn-ui-switch.mjs +48 -35
  74. package/fesm2022/joanroucoux-cairn-ui-switch.mjs.map +1 -1
  75. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs +113 -69
  76. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs.map +1 -1
  77. package/fesm2022/joanroucoux-cairn-ui-table.mjs +1036 -310
  78. package/fesm2022/joanroucoux-cairn-ui-table.mjs.map +1 -1
  79. package/fesm2022/joanroucoux-cairn-ui-toast.mjs +240 -127
  80. package/fesm2022/joanroucoux-cairn-ui-toast.mjs.map +1 -1
  81. package/fesm2022/joanroucoux-cairn-ui.mjs +0 -4
  82. package/package.json +17 -1
  83. package/styles/motion.css +1 -13
  84. package/styles/tokens.css +35 -64
  85. package/types/joanroucoux-cairn-ui-action-bar.d.ts +9 -14
  86. package/types/joanroucoux-cairn-ui-alert.d.ts +29 -15
  87. package/types/joanroucoux-cairn-ui-amount.d.ts +64 -32
  88. package/types/joanroucoux-cairn-ui-async.d.ts +85 -38
  89. package/types/joanroucoux-cairn-ui-avatar.d.ts +34 -22
  90. package/types/joanroucoux-cairn-ui-back-link.d.ts +20 -15
  91. package/types/joanroucoux-cairn-ui-badge.d.ts +22 -14
  92. package/types/joanroucoux-cairn-ui-button.d.ts +36 -18
  93. package/types/joanroucoux-cairn-ui-card.d.ts +48 -23
  94. package/types/joanroucoux-cairn-ui-choice-chips.d.ts +91 -35
  95. package/types/joanroucoux-cairn-ui-control.d.ts +9 -18
  96. package/types/joanroucoux-cairn-ui-delta.d.ts +46 -24
  97. package/types/joanroucoux-cairn-ui-dialog.d.ts +124 -57
  98. package/types/joanroucoux-cairn-ui-donut.d.ts +83 -46
  99. package/types/joanroucoux-cairn-ui-drawer.d.ts +73 -0
  100. package/types/joanroucoux-cairn-ui-empty.d.ts +20 -13
  101. package/types/joanroucoux-cairn-ui-external-link.d.ts +6 -10
  102. package/types/joanroucoux-cairn-ui-fact.d.ts +49 -25
  103. package/types/joanroucoux-cairn-ui-field.d.ts +72 -49
  104. package/types/joanroucoux-cairn-ui-filter-chips.d.ts +35 -20
  105. package/types/joanroucoux-cairn-ui-group-header.d.ts +58 -0
  106. package/types/joanroucoux-cairn-ui-input.d.ts +59 -37
  107. package/types/joanroucoux-cairn-ui-line-chart.d.ts +199 -89
  108. package/types/joanroucoux-cairn-ui-menu.d.ts +81 -44
  109. package/types/joanroucoux-cairn-ui-meter.d.ts +44 -22
  110. package/types/joanroucoux-cairn-ui-motion.d.ts +61 -75
  111. package/types/joanroucoux-cairn-ui-nav-item.d.ts +15 -13
  112. package/types/joanroucoux-cairn-ui-result-group.d.ts +52 -0
  113. package/types/joanroucoux-cairn-ui-row.d.ts +79 -37
  114. package/types/joanroucoux-cairn-ui-segmented.d.ts +51 -27
  115. package/types/joanroucoux-cairn-ui-select-pill.d.ts +52 -0
  116. package/types/joanroucoux-cairn-ui-select.d.ts +28 -18
  117. package/types/joanroucoux-cairn-ui-skeleton.d.ts +35 -18
  118. package/types/joanroucoux-cairn-ui-stale-link.d.ts +23 -16
  119. package/types/joanroucoux-cairn-ui-stat.d.ts +26 -21
  120. package/types/joanroucoux-cairn-ui-switch.d.ts +7 -11
  121. package/types/joanroucoux-cairn-ui-tab-bar.d.ts +20 -17
  122. package/types/joanroucoux-cairn-ui-table.d.ts +251 -89
  123. package/types/joanroucoux-cairn-ui-toast.d.ts +46 -36
  124. package/types/joanroucoux-cairn-ui.d.ts +1 -2
  125. package/fesm2022/joanroucoux-cairn-ui.mjs.map +0 -1
@@ -1,114 +1,224 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, signal, input, inject, LOCALE_ID, booleanAttribute, computed, Component } from '@angular/core';
3
-
4
- const MINUS = '−';
5
- const EM_DASH = '—';
6
- const BULLETS = '••••';
7
- /** Formats a number or an amount for the locale, with a missing value as an em dash and masking behind four bullets. */
1
+ import * as i0 from "@angular/core";
2
+ import { Component, InjectionToken, LOCALE_ID, booleanAttribute, computed, inject, input, signal } from "@angular/core";
3
+ const MINUS = "−";
4
+ const EM_DASH = "—";
5
+ const BULLETS = "••••";
8
6
  function formatAmount(value, options, masked = false) {
9
- if (value === null || value === undefined || Number.isNaN(value)) {
10
- return EM_DASH;
11
- }
12
- const digits = options.fractionDigits ?? 2;
13
- const format = new Intl.NumberFormat(options.locale, {
14
- ...(options.currency ? { style: 'currency', currency: options.currency } : {}),
15
- minimumFractionDigits: digits,
16
- maximumFractionDigits: digits,
17
- });
18
- const magnitude = Math.abs(value);
19
- const parts = format.formatToParts(magnitude);
20
- if (masked) {
21
- let replaced = false;
22
- return parts
23
- .map((part) => {
24
- if (['integer', 'group', 'decimal', 'fraction'].includes(part.type)) {
25
- if (replaced) {
26
- return '';
27
- }
28
- replaced = true;
29
- return BULLETS;
30
- }
31
- return part.value;
32
- })
33
- .join('');
34
- }
35
- const text = parts.map((part) => part.value).join('');
36
- const isZero = Number(format.format(magnitude).replace(/[^\d]/g, '')) === 0;
37
- if (!options.signed || isZero) {
38
- return value < 0 && !isZero ? `${MINUS}${text}` : text;
39
- }
40
- return `${value > 0 ? '+' : MINUS}${text}`;
7
+ if (value === null || value === void 0 || Number.isNaN(value)) return EM_DASH;
8
+ const digits = options.fractionDigits ?? 2;
9
+ const format = new Intl.NumberFormat(options.locale, {
10
+ ...options.currency ? {
11
+ style: "currency",
12
+ currency: options.currency
13
+ } : {},
14
+ minimumFractionDigits: digits,
15
+ maximumFractionDigits: digits
16
+ });
17
+ const magnitude = Math.abs(value);
18
+ const parts = format.formatToParts(magnitude);
19
+ if (masked) {
20
+ let replaced = false;
21
+ return parts.map((part) => {
22
+ if ([
23
+ "integer",
24
+ "group",
25
+ "decimal",
26
+ "fraction"
27
+ ].includes(part.type)) {
28
+ if (replaced) return "";
29
+ replaced = true;
30
+ return BULLETS;
31
+ }
32
+ return part.value;
33
+ }).join("");
34
+ }
35
+ const text = parts.map((part) => part.value).join("");
36
+ const isZero = Number(format.format(magnitude).replace(/[^\d]/g, "")) === 0;
37
+ if (!options.signed || isZero) return value < 0 && !isZero ? `${MINUS}${text}` : text;
38
+ return `${value > 0 ? "+" : MINUS}${text}`;
41
39
  }
42
-
43
- /** App-wide "amounts are hidden" state. Defaults to never masked; the app overrides it. */
44
- const UI_AMOUNT_MASKED = new InjectionToken('UI_AMOUNT_MASKED', {
45
- providedIn: 'root',
46
- factory: () => signal(false),
40
+ const UI_AMOUNT_MASKED = new InjectionToken("UI_AMOUNT_MASKED", {
41
+ providedIn: "root",
42
+ factory: () => signal(false)
43
+ });
44
+ const AMOUNT_NUMERICS = ["tabular", "proportional"];
45
+ const AMOUNT_MASKINGS = ["dots", "hide"];
46
+ var UiAmount = class UiAmount {
47
+ value = input(...ngDevMode ? [void 0, { debugName: "value" }] : /* istanbul ignore next */ []);
48
+ currency = input(...ngDevMode ? [void 0, { debugName: "currency" }] : /* istanbul ignore next */ []);
49
+ locale = input(inject(LOCALE_ID), ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
50
+ signed = input(false, {
51
+ ...ngDevMode ? { debugName: "signed" } : /* istanbul ignore next */ {},
52
+ transform: booleanAttribute
53
+ });
54
+ fractionDigits = input(2, ...ngDevMode ? [{ debugName: "fractionDigits" }] : /* istanbul ignore next */ []);
55
+ numeric = input("tabular", ...ngDevMode ? [{ debugName: "numeric" }] : /* istanbul ignore next */ []);
56
+ whenMasked = input("dots", ...ngDevMode ? [{ debugName: "whenMasked" }] : /* istanbul ignore next */ []);
57
+ #masked = inject(UI_AMOUNT_MASKED);
58
+ hidden = computed(() => this.#masked() && this.whenMasked() === "hide", ...ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []);
59
+ text = computed(() => formatAmount(this.value(), {
60
+ locale: this.locale(),
61
+ currency: this.currency(),
62
+ signed: this.signed(),
63
+ fractionDigits: this.fractionDigits()
64
+ }, this.#masked()), ...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
65
+ classes = computed(() => {
66
+ const missing = this.value() === null || this.value() === void 0;
67
+ return [
68
+ "whitespace-nowrap",
69
+ this.numeric() === "tabular" ? "tabular-nums" : "",
70
+ missing ? "text-(--subtle-foreground)" : ""
71
+ ].filter(Boolean).join(" ");
72
+ }, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
73
+ static ɵfac = i0.ɵɵngDeclareFactory({
74
+ minVersion: "12.0.0",
75
+ version: "22.2.0",
76
+ ngImport: i0,
77
+ type: UiAmount,
78
+ deps: [],
79
+ target: i0.ɵɵFactoryTarget.Component
80
+ });
81
+ static ɵcmp = i0.ɵɵngDeclareComponent({
82
+ minVersion: "17.1.0",
83
+ version: "22.2.0",
84
+ type: UiAmount,
85
+ isStandalone: true,
86
+ selector: "ui-amount",
87
+ inputs: {
88
+ value: {
89
+ classPropertyName: "value",
90
+ publicName: "value",
91
+ isSignal: true,
92
+ isRequired: false,
93
+ transformFunction: null
94
+ },
95
+ currency: {
96
+ classPropertyName: "currency",
97
+ publicName: "currency",
98
+ isSignal: true,
99
+ isRequired: false,
100
+ transformFunction: null
101
+ },
102
+ locale: {
103
+ classPropertyName: "locale",
104
+ publicName: "locale",
105
+ isSignal: true,
106
+ isRequired: false,
107
+ transformFunction: null
108
+ },
109
+ signed: {
110
+ classPropertyName: "signed",
111
+ publicName: "signed",
112
+ isSignal: true,
113
+ isRequired: false,
114
+ transformFunction: null
115
+ },
116
+ fractionDigits: {
117
+ classPropertyName: "fractionDigits",
118
+ publicName: "fractionDigits",
119
+ isSignal: true,
120
+ isRequired: false,
121
+ transformFunction: null
122
+ },
123
+ numeric: {
124
+ classPropertyName: "numeric",
125
+ publicName: "numeric",
126
+ isSignal: true,
127
+ isRequired: false,
128
+ transformFunction: null
129
+ },
130
+ whenMasked: {
131
+ classPropertyName: "whenMasked",
132
+ publicName: "whenMasked",
133
+ isSignal: true,
134
+ isRequired: false,
135
+ transformFunction: null
136
+ }
137
+ },
138
+ host: { properties: {
139
+ "class": "classes()",
140
+ "attr.hidden": "hidden() || null"
141
+ } },
142
+ ngImport: i0,
143
+ template: "{{ text() }}",
144
+ isInline: true
145
+ });
146
+ };
147
+ i0.ɵɵngDeclareClassMetadata({
148
+ minVersion: "12.0.0",
149
+ version: "22.2.0",
150
+ ngImport: i0,
151
+ type: UiAmount,
152
+ decorators: [{
153
+ type: Component,
154
+ args: [{
155
+ selector: "ui-amount",
156
+ template: "{{ text() }}",
157
+ host: {
158
+ "[class]": "classes()",
159
+ "[attr.hidden]": "hidden() || null"
160
+ }
161
+ }]
162
+ }],
163
+ propDecorators: {
164
+ value: [{
165
+ type: i0.Input,
166
+ args: [{
167
+ isSignal: true,
168
+ alias: "value",
169
+ required: false
170
+ }]
171
+ }],
172
+ currency: [{
173
+ type: i0.Input,
174
+ args: [{
175
+ isSignal: true,
176
+ alias: "currency",
177
+ required: false
178
+ }]
179
+ }],
180
+ locale: [{
181
+ type: i0.Input,
182
+ args: [{
183
+ isSignal: true,
184
+ alias: "locale",
185
+ required: false
186
+ }]
187
+ }],
188
+ signed: [{
189
+ type: i0.Input,
190
+ args: [{
191
+ isSignal: true,
192
+ alias: "signed",
193
+ required: false
194
+ }]
195
+ }],
196
+ fractionDigits: [{
197
+ type: i0.Input,
198
+ args: [{
199
+ isSignal: true,
200
+ alias: "fractionDigits",
201
+ required: false
202
+ }]
203
+ }],
204
+ numeric: [{
205
+ type: i0.Input,
206
+ args: [{
207
+ isSignal: true,
208
+ alias: "numeric",
209
+ required: false
210
+ }]
211
+ }],
212
+ whenMasked: [{
213
+ type: i0.Input,
214
+ args: [{
215
+ isSignal: true,
216
+ alias: "whenMasked",
217
+ required: false
218
+ }]
219
+ }]
220
+ }
47
221
  });
48
- /** Available figure styles. `AmountNumeric` is derived from this tuple. */
49
- const AMOUNT_NUMERICS = ['tabular', 'proportional'];
50
- /** Available masking behaviors. `AmountMasking` is derived from this tuple. */
51
- const AMOUNT_MASKINGS = ['dots', 'hide'];
52
- /**
53
- * A number or an amount of money, formatted for the locale and masked when the app hides amounts.
54
- *
55
- * @example
56
- * <ui-amount [value]="total" currency="EUR" numeric="proportional" />
57
- * <ui-amount [value]="dayChange" currency="EUR" signed whenMasked="hide" />
58
- */
59
- class UiAmount {
60
- value = input(/* @ts-ignore */
61
- ...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
62
- currency = input(/* @ts-ignore */
63
- ...(ngDevMode ? [undefined, { debugName: "currency" }] : /* istanbul ignore next */ []));
64
- locale = input(inject(LOCALE_ID), /* @ts-ignore */
65
- ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
66
- signed = input(false, { ...(ngDevMode ? { debugName: "signed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
67
- fractionDigits = input(2, /* @ts-ignore */
68
- ...(ngDevMode ? [{ debugName: "fractionDigits" }] : /* istanbul ignore next */ []));
69
- numeric = input('tabular', /* @ts-ignore */
70
- ...(ngDevMode ? [{ debugName: "numeric" }] : /* istanbul ignore next */ []));
71
- whenMasked = input('dots', /* @ts-ignore */
72
- ...(ngDevMode ? [{ debugName: "whenMasked" }] : /* istanbul ignore next */ []));
73
- #masked = inject(UI_AMOUNT_MASKED);
74
- hidden = computed(() => this.#masked() && this.whenMasked() === 'hide', /* @ts-ignore */
75
- ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
76
- text = computed(() => formatAmount(this.value(), {
77
- locale: this.locale(),
78
- currency: this.currency(),
79
- signed: this.signed(),
80
- fractionDigits: this.fractionDigits(),
81
- }, this.#masked()), /* @ts-ignore */
82
- ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
83
- classes = computed(() => {
84
- const missing = this.value() === null || this.value() === undefined;
85
- return [
86
- 'whitespace-nowrap',
87
- this.numeric() === 'tabular' ? 'tabular-nums' : '',
88
- missing ? 'text-(--subtle-foreground)' : '',
89
- ]
90
- .filter(Boolean)
91
- .join(' ');
92
- }, /* @ts-ignore */
93
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
94
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAmount, deps: [], target: i0.ɵɵFactoryTarget.Component });
95
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiAmount, isStandalone: true, selector: "ui-amount", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, signed: { classPropertyName: "signed", publicName: "signed", isSignal: true, isRequired: false, transformFunction: null }, fractionDigits: { classPropertyName: "fractionDigits", publicName: "fractionDigits", isSignal: true, isRequired: false, transformFunction: null }, numeric: { classPropertyName: "numeric", publicName: "numeric", isSignal: true, isRequired: false, transformFunction: null }, whenMasked: { classPropertyName: "whenMasked", publicName: "whenMasked", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.hidden": "hidden() || null" } }, ngImport: i0, template: '{{ text() }}', isInline: true });
96
- }
97
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAmount, decorators: [{
98
- type: Component,
99
- args: [{
100
- selector: 'ui-amount',
101
- template: '{{ text() }}',
102
- host: {
103
- '[class]': 'classes()',
104
- '[attr.hidden]': 'hidden() || null',
105
- },
106
- }]
107
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], signed: [{ type: i0.Input, args: [{ isSignal: true, alias: "signed", required: false }] }], fractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "fractionDigits", required: false }] }], numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], whenMasked: [{ type: i0.Input, args: [{ isSignal: true, alias: "whenMasked", required: false }] }] } });
108
-
109
- /**
110
- * Generated bundle index. Do not edit.
111
- */
112
-
113
222
  export { AMOUNT_MASKINGS, AMOUNT_NUMERICS, UI_AMOUNT_MASKED, UiAmount, formatAmount };
114
- //# sourceMappingURL=joanroucoux-cairn-ui-amount.mjs.map
223
+
224
+ //# sourceMappingURL=joanroucoux-cairn-ui-amount.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"joanroucoux-cairn-ui-amount.mjs","sources":["../../../projects/ui/amount/format-amount.ts","../../../projects/ui/amount/amount.ts","../../../projects/ui/amount/joanroucoux-cairn-ui-amount.ts"],"sourcesContent":["const MINUS = '−';\nconst EM_DASH = '—';\nconst BULLETS = '••••';\n\nexport type AmountFormatOptions = {\n locale: string;\n currency?: string;\n signed?: boolean;\n fractionDigits?: number;\n};\n\n/** Formats a number or an amount for the locale, with a missing value as an em dash and masking behind four bullets. */\nexport function formatAmount(value: number | null | undefined, options: AmountFormatOptions, masked = false): string {\n if (value === null || value === undefined || Number.isNaN(value)) {\n return EM_DASH;\n }\n const digits = options.fractionDigits ?? 2;\n const format = new Intl.NumberFormat(options.locale, {\n ...(options.currency ? { style: 'currency', currency: options.currency } : {}),\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n const magnitude = Math.abs(value);\n const parts = format.formatToParts(magnitude);\n\n if (masked) {\n let replaced = false;\n return parts\n .map((part) => {\n if (['integer', 'group', 'decimal', 'fraction'].includes(part.type)) {\n if (replaced) {\n return '';\n }\n replaced = true;\n return BULLETS;\n }\n return part.value;\n })\n .join('');\n }\n\n const text = parts.map((part) => part.value).join('');\n const isZero = Number(format.format(magnitude).replace(/[^\\d]/g, '')) === 0;\n if (!options.signed || isZero) {\n return value < 0 && !isZero ? `${MINUS}${text}` : text;\n }\n return `${value > 0 ? '+' : MINUS}${text}`;\n}\n","import {\n Component,\n InjectionToken,\n LOCALE_ID,\n type Signal,\n booleanAttribute,\n computed,\n inject,\n input,\n signal,\n} from '@angular/core';\n\nimport { formatAmount } from './format-amount';\n\n/** App-wide \"amounts are hidden\" state. Defaults to never masked; the app overrides it. */\nexport const UI_AMOUNT_MASKED = new InjectionToken<Signal<boolean>>('UI_AMOUNT_MASKED', {\n providedIn: 'root',\n factory: () => signal(false),\n});\n\n/** Available figure styles. `AmountNumeric` is derived from this tuple. */\nexport const AMOUNT_NUMERICS = ['tabular', 'proportional'] as const;\nexport type AmountNumeric = (typeof AMOUNT_NUMERICS)[number];\n\n/** Available masking behaviors. `AmountMasking` is derived from this tuple. */\nexport const AMOUNT_MASKINGS = ['dots', 'hide'] as const;\nexport type AmountMasking = (typeof AMOUNT_MASKINGS)[number];\n\n/**\n * A number or an amount of money, formatted for the locale and masked when the app hides amounts.\n *\n * @example\n * <ui-amount [value]=\"total\" currency=\"EUR\" numeric=\"proportional\" />\n * <ui-amount [value]=\"dayChange\" currency=\"EUR\" signed whenMasked=\"hide\" />\n */\n@Component({\n selector: 'ui-amount',\n template: '{{ text() }}',\n host: {\n '[class]': 'classes()',\n '[attr.hidden]': 'hidden() || null',\n },\n})\nexport class UiAmount {\n readonly value = input<number | null | undefined>();\n readonly currency = input<string>();\n readonly locale = input<string>(inject(LOCALE_ID));\n readonly signed = input(false, { transform: booleanAttribute });\n readonly fractionDigits = input(2);\n readonly numeric = input<AmountNumeric>('tabular');\n readonly whenMasked = input<AmountMasking>('dots');\n\n readonly #masked = inject(UI_AMOUNT_MASKED);\n\n protected readonly hidden = computed(() => this.#masked() && this.whenMasked() === 'hide');\n\n protected readonly text = computed(() =>\n formatAmount(\n this.value(),\n {\n locale: this.locale(),\n currency: this.currency(),\n signed: this.signed(),\n fractionDigits: this.fractionDigits(),\n },\n this.#masked(),\n ),\n );\n\n protected readonly classes = computed(() => {\n const missing = this.value() === null || this.value() === undefined;\n\n return [\n 'whitespace-nowrap',\n this.numeric() === 'tabular' ? 'tabular-nums' : '',\n missing ? 'text-(--subtle-foreground)' : '',\n ]\n .filter(Boolean)\n .join(' ');\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"joanroucoux-cairn-ui-amount.mjs","names":[],"sources":["../../../projects/ui/amount/format-amount.ts","../../../projects/ui/amount/amount.ts"],"sourcesContent":["const MINUS = '−';\nconst EM_DASH = '—';\nconst BULLETS = '••••';\n\nexport type AmountFormatOptions = {\n locale: string;\n currency?: string;\n signed?: boolean;\n fractionDigits?: number;\n};\n\n/** Formats a number or an amount for the locale. A missing value is an em dash, a masked one four bullets. */\nexport function formatAmount(value: number | null | undefined, options: AmountFormatOptions, masked = false): string {\n if (value === null || value === undefined || Number.isNaN(value)) {\n return EM_DASH;\n }\n const digits = options.fractionDigits ?? 2;\n const format = new Intl.NumberFormat(options.locale, {\n ...(options.currency ? { style: 'currency', currency: options.currency } : {}),\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n const magnitude = Math.abs(value);\n const parts = format.formatToParts(magnitude);\n\n if (masked) {\n let replaced = false;\n return parts\n .map((part) => {\n if (['integer', 'group', 'decimal', 'fraction'].includes(part.type)) {\n if (replaced) {\n return '';\n }\n replaced = true;\n return BULLETS;\n }\n return part.value;\n })\n .join('');\n }\n\n const text = parts.map((part) => part.value).join('');\n const isZero = Number(format.format(magnitude).replace(/[^\\d]/g, '')) === 0;\n if (!options.signed || isZero) {\n return value < 0 && !isZero ? `${MINUS}${text}` : text;\n }\n return `${value > 0 ? '+' : MINUS}${text}`;\n}\n","import {\n Component,\n InjectionToken,\n LOCALE_ID,\n type Signal,\n booleanAttribute,\n computed,\n inject,\n input,\n signal,\n} from '@angular/core';\n\nimport { formatAmount } from './format-amount';\n\n/** App-wide \"amounts are hidden\" state. Defaults to never masked; the app overrides it. */\nexport const UI_AMOUNT_MASKED = new InjectionToken<Signal<boolean>>('UI_AMOUNT_MASKED', {\n providedIn: 'root',\n factory: () => signal(false),\n});\n\n/** Available figure styles. */\nexport const AMOUNT_NUMERICS = ['tabular', 'proportional'] as const;\nexport type AmountNumeric = (typeof AMOUNT_NUMERICS)[number];\n\n/** Available masking behaviors. */\nexport const AMOUNT_MASKINGS = ['dots', 'hide'] as const;\nexport type AmountMasking = (typeof AMOUNT_MASKINGS)[number];\n\n/**\n * A number or an amount of money, formatted for the locale and masked when the app hides amounts.\n *\n * @example\n * <ui-amount [value]=\"total\" currency=\"EUR\" numeric=\"proportional\" />\n * <ui-amount [value]=\"dayChange\" currency=\"EUR\" signed whenMasked=\"hide\" />\n */\n@Component({\n selector: 'ui-amount',\n template: '{{ text() }}',\n host: {\n '[class]': 'classes()',\n '[attr.hidden]': 'hidden() || null',\n },\n})\nexport class UiAmount {\n readonly value = input<number | null | undefined>();\n readonly currency = input<string>();\n readonly locale = input<string>(inject(LOCALE_ID));\n readonly signed = input(false, { transform: booleanAttribute });\n readonly fractionDigits = input(2);\n readonly numeric = input<AmountNumeric>('tabular');\n readonly whenMasked = input<AmountMasking>('dots');\n\n readonly #masked = inject(UI_AMOUNT_MASKED);\n\n protected readonly hidden = computed(() => this.#masked() && this.whenMasked() === 'hide');\n\n protected readonly text = computed(() =>\n formatAmount(\n this.value(),\n {\n locale: this.locale(),\n currency: this.currency(),\n signed: this.signed(),\n fractionDigits: this.fractionDigits(),\n },\n this.#masked(),\n ),\n );\n\n protected readonly classes = computed(() => {\n const missing = this.value() === null || this.value() === undefined;\n\n return [\n 'whitespace-nowrap',\n this.numeric() === 'tabular' ? 'tabular-nums' : '',\n missing ? 'text-(--subtle-foreground)' : '',\n ]\n .filter(Boolean)\n .join(' ');\n });\n}\n"],"mappings":"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"}