@joanroucoux/cairn-ui 0.2.0 → 0.4.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.
@@ -1,5 +1,69 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { Signal, ElementRef } from '@angular/core';
2
+ import { InjectionToken, Signal, ElementRef } from '@angular/core';
3
+
4
+ /** App-wide "amounts are hidden" state. Defaults to never masked; the app overrides it. */
5
+ declare const UI_AMOUNT_MASKED: InjectionToken<Signal<boolean>>;
6
+ /** Available figure styles. `AmountNumeric` is derived from this tuple. */
7
+ declare const AMOUNT_NUMERICS: readonly ["tabular", "proportional"];
8
+ type AmountNumeric = (typeof AMOUNT_NUMERICS)[number];
9
+ /** Available masking behaviors. `AmountMasking` is derived from this tuple. */
10
+ declare const AMOUNT_MASKINGS: readonly ["dots", "hide"];
11
+ type AmountMasking = (typeof AMOUNT_MASKINGS)[number];
12
+ /**
13
+ * A number or an amount of money, formatted for the locale and masked when the app hides amounts.
14
+ *
15
+ * @example
16
+ * <ui-amount [value]="total" currency="EUR" numeric="proportional" />
17
+ * <ui-amount [value]="dayChange" currency="EUR" signed whenMasked="hide" />
18
+ */
19
+ declare class UiAmount {
20
+ #private;
21
+ readonly value: _angular_core.InputSignal<number | null | undefined>;
22
+ readonly currency: _angular_core.InputSignal<string | undefined>;
23
+ readonly locale: _angular_core.InputSignal<string>;
24
+ readonly signed: _angular_core.InputSignalWithTransform<boolean, unknown>;
25
+ readonly fractionDigits: _angular_core.InputSignal<number>;
26
+ readonly numeric: _angular_core.InputSignal<"tabular" | "proportional">;
27
+ readonly whenMasked: _angular_core.InputSignal<"dots" | "hide">;
28
+ protected readonly hidden: Signal<boolean>;
29
+ protected readonly text: Signal<string>;
30
+ protected readonly classes: Signal<string>;
31
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiAmount, never>;
32
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiAmount, "ui-amount", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "currency": { "alias": "currency"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "signed": { "alias": "signed"; "required": false; "isSignal": true; }; "fractionDigits": { "alias": "fractionDigits"; "required": false; "isSignal": true; }; "numeric": { "alias": "numeric"; "required": false; "isSignal": true; }; "whenMasked": { "alias": "whenMasked"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
33
+ }
34
+
35
+ type AmountFormatOptions = {
36
+ locale: string;
37
+ currency?: string;
38
+ signed?: boolean;
39
+ fractionDigits?: number;
40
+ };
41
+ /** Formats a number or an amount for the locale, with a missing value as an em dash and masking behind four bullets. */
42
+ declare function formatAmount(value: number | null | undefined, options: AmountFormatOptions, masked?: boolean): string;
43
+
44
+ /** Available async block states. `AsyncState` is derived from this tuple. */
45
+ declare const ASYNC_STATES: readonly ["loading", "error", "empty", "ready"];
46
+ type AsyncState = (typeof ASYNC_STATES)[number];
47
+ /**
48
+ * The three states of a block that depends on a service call, next to the ready content.
49
+ *
50
+ * @example
51
+ * <ui-async [state]="totalState()" errorTitle="Total could not be loaded" errorMessage="The server did not answer." retryLabel="Retry" (retry)="reload()">
52
+ * <span asyncLoading><ui-skeleton shape="figure" /></span>
53
+ * <span asyncEmpty>Add a holding to see your total.</span>
54
+ * <span>{{ total() }}</span>
55
+ * </ui-async>
56
+ */
57
+ declare class UiAsync {
58
+ readonly state: _angular_core.InputSignal<"loading" | "error" | "empty" | "ready">;
59
+ readonly errorTitle: _angular_core.InputSignal<string | undefined>;
60
+ readonly errorMessage: _angular_core.InputSignal<string | undefined>;
61
+ readonly retryLabel: _angular_core.InputSignal<string | undefined>;
62
+ readonly retry: _angular_core.OutputEmitterRef<void>;
63
+ protected readonly retryButtonClasses = "mt-2 relative inline-flex items-center justify-center gap-2 rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[transform,background-color,opacity] duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) min-h-(--row-min) px-4 text-label bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow)";
64
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiAsync, never>;
65
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiAsync, "ui-async", never, { "state": { "alias": "state"; "required": true; "isSignal": true; }; "errorTitle": { "alias": "errorTitle"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "retryLabel": { "alias": "retryLabel"; "required": false; "isSignal": true; }; }, { "retry": "retry"; }, never, ["[asyncLoading]", "[asyncEmpty]", "*"], true, never>;
66
+ }
3
67
 
4
68
  /** Available avatar sizes. `AvatarSize` is derived from this tuple. */
5
69
  declare const AVATAR_SIZES: readonly ["sm", "md"];
@@ -13,7 +77,7 @@ type AvatarSize = (typeof AVATAR_SIZES)[number];
13
77
  declare class UiAvatar {
14
78
  readonly initials: _angular_core.InputSignal<string>;
15
79
  readonly label: _angular_core.InputSignal<string>;
16
- readonly size: _angular_core.InputSignal<"md" | "sm">;
80
+ readonly size: _angular_core.InputSignal<"sm" | "md">;
17
81
  protected readonly classes: _angular_core.Signal<string>;
18
82
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiAvatar, never>;
19
83
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiAvatar, "ui-avatar", never, { "initials": { "alias": "initials"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -29,7 +93,7 @@ type BadgeVariant = (typeof BADGE_VARIANTS)[number];
29
93
  * <ui-badge>ETF</ui-badge>
30
94
  */
31
95
  declare class UiBadge {
32
- readonly variant: _angular_core.InputSignal<"outline" | "neutral">;
96
+ readonly variant: _angular_core.InputSignal<"neutral" | "outline">;
33
97
  protected readonly classes: _angular_core.Signal<string>;
34
98
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiBadge, never>;
35
99
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiBadge, "ui-badge", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -42,23 +106,14 @@ type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
42
106
  declare const BUTTON_SIZES: readonly ["md", "lg", "xl", "icon"];
43
107
  type ButtonSize = (typeof BUTTON_SIZES)[number];
44
108
  /**
45
- * Styled native button. Applied as an attribute so the host keeps every native
46
- * button behavior (type, disabled, form submission, accessibility) for free.
47
- *
48
- * Also applies to an anchor, for the one case where the action really is a navigation:
49
- * a download the browser has to perform itself.
50
- *
51
- * `size="icon"` has no visible text: give it an `aria-label`.
52
- *
53
- * A `loading` button shows a spinner before its label and swallows clicks, so a slow first
54
- * response cannot turn into a double submission.
109
+ * Styled native button or anchor, applied as an attribute so the host keeps every native behavior.
55
110
  *
56
111
  * @example
57
112
  * <button ui-button variant="destructive">Delete</button>
58
113
  * <button ui-button size="icon" variant="ghost" aria-label="More actions">...</button>
59
114
  */
60
115
  declare class UiButton {
61
- readonly variant: _angular_core.InputSignal<"primary" | "outline" | "ghost" | "destructive">;
116
+ readonly variant: _angular_core.InputSignal<"outline" | "primary" | "ghost" | "destructive">;
62
117
  readonly size: _angular_core.InputSignal<"md" | "lg" | "xl" | "icon">;
63
118
  readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
64
119
  protected readonly classes: _angular_core.Signal<string>;
@@ -81,7 +136,7 @@ type CardPadding = (typeof CARD_PADDINGS)[number];
81
136
  */
82
137
  declare class UiCard {
83
138
  readonly variant: _angular_core.InputSignal<"default" | "elevated">;
84
- readonly padding: _angular_core.InputSignal<"md" | "sm" | "none">;
139
+ readonly padding: _angular_core.InputSignal<"sm" | "md" | "none">;
85
140
  protected readonly classes: _angular_core.Signal<string>;
86
141
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiCard, never>;
87
142
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiCard, "ui-card", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "padding": { "alias": "padding"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -131,8 +186,8 @@ declare class UiDelta {
131
186
  declare const DIALOG_WIDTHS: readonly ["md", "lg"];
132
187
  type DialogWidth = (typeof DIALOG_WIDTHS)[number];
133
188
  /**
134
- * Modal dialog on the native <dialog>: focus trap, focus return, Escape and the top layer
135
- * come from the platform. Two projection slots - the body, and [dialogActions] for the footer.
189
+ * Modal dialog on the native <dialog>: a sheet rising from the bottom under `64rem`, centered
190
+ * above it. Two projection slots - the body, and [dialogActions] for the footer.
136
191
  *
137
192
  * @example
138
193
  * <ui-dialog heading="Delete this holding?" [open]="confirming()" (dismissed)="confirming.set(false)">
@@ -145,7 +200,7 @@ declare class UiDialog {
145
200
  readonly heading: _angular_core.InputSignal<string>;
146
201
  readonly description: _angular_core.InputSignal<string | undefined>;
147
202
  readonly width: _angular_core.InputSignal<"md" | "lg">;
148
- readonly open: _angular_core.InputSignal<boolean>;
203
+ readonly open: _angular_core.InputSignalWithTransform<boolean, unknown>;
149
204
  readonly dismissed: _angular_core.OutputEmitterRef<void>;
150
205
  protected readonly headingId: string;
151
206
  protected readonly descriptionId: string;
@@ -184,7 +239,6 @@ declare class UiField {
184
239
  readonly labelHidden: _angular_core.InputSignalWithTransform<boolean, unknown>;
185
240
  readonly hint: _angular_core.InputSignal<string | undefined>;
186
241
  readonly error: _angular_core.InputSignal<string | undefined>;
187
- /** Unit shown inside the control's right edge, such as `EUR` or `parts`. Not part of the control's value. */
188
242
  readonly unit: _angular_core.InputSignal<string | undefined>;
189
243
  protected readonly hintId: string;
190
244
  protected readonly errorId: string;
@@ -215,7 +269,7 @@ type ControlSize = (typeof CONTROL_SIZES)[number];
215
269
  * <input uiInput type="email" placeholder="you@example.com" />
216
270
  */
217
271
  declare class UiInput implements UiControl {
218
- readonly size: _angular_core.InputSignal<"md" | "sm">;
272
+ readonly size: _angular_core.InputSignal<"sm" | "md">;
219
273
  readonly errors: _angular_core.InputSignal<readonly UiControlError[]>;
220
274
  readonly touched: _angular_core.InputSignal<boolean>;
221
275
  protected readonly classes: _angular_core.Signal<string>;
@@ -240,6 +294,136 @@ declare class UiTextarea implements UiControl {
240
294
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<UiTextarea, "textarea[uiTextarea]", never, { "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
241
295
  }
242
296
 
297
+ type ChartPoint = {
298
+ t: number;
299
+ v: number;
300
+ };
301
+ type PlottedPoint = ChartPoint & {
302
+ x: number;
303
+ y: number;
304
+ };
305
+ type ChartGeometry = {
306
+ line: string;
307
+ end: {
308
+ x: number;
309
+ y: number;
310
+ };
311
+ start: {
312
+ y: number;
313
+ };
314
+ points: PlottedPoint[];
315
+ plotBottom: number;
316
+ plotTop: number;
317
+ };
318
+
319
+ type StartLabelPlacement = {
320
+ x: number;
321
+ y: number;
322
+ anchor: 'start' | 'end';
323
+ };
324
+
325
+ type PlotRef = ElementRef<SVGSVGElement>;
326
+ /**
327
+ * Value over time: a monotone curve with a dashed line at the starting value and a tooltip.
328
+ *
329
+ * @example
330
+ * <ui-line-chart [points]="points" label="Net worth over one month" startLabel="Since" [valueFormat]="formatEur" />
331
+ */
332
+ declare class UiLineChart {
333
+ #private;
334
+ readonly points: _angular_core.InputSignal<ChartPoint[]>;
335
+ readonly label: _angular_core.InputSignal<string>;
336
+ readonly valueFormat: _angular_core.InputSignal<(value: number) => string>;
337
+ readonly deltaFormat: _angular_core.InputSignal<(delta: number) => string>;
338
+ readonly timeFormat: _angular_core.InputSignal<(time: number) => string>;
339
+ readonly axisFormat: _angular_core.InputSignal<(time: number) => string>;
340
+ readonly startLabel: _angular_core.InputSignal<string>;
341
+ readonly timeColumnLabel: _angular_core.InputSignal<string>;
342
+ readonly valueColumnLabel: _angular_core.InputSignal<string>;
343
+ protected readonly svgRef: _angular_core.Signal<PlotRef>;
344
+ protected readonly activeIndex: _angular_core.WritableSignal<number | null>;
345
+ protected readonly animatedLine: _angular_core.WritableSignal<string | null>;
346
+ protected readonly measuredSize: _angular_core.WritableSignal<{
347
+ width: number;
348
+ height: number;
349
+ } | null>;
350
+ protected readonly effectiveWidth: _angular_core.Signal<number>;
351
+ protected readonly effectiveHeight: _angular_core.Signal<number>;
352
+ protected readonly geometry: _angular_core.Signal<ChartGeometry | null>;
353
+ protected readonly displayLine: _angular_core.Signal<string>;
354
+ protected readonly ticks: _angular_core.Signal<PlottedPoint[]>;
355
+ protected readonly active: _angular_core.Signal<PlottedPoint | null>;
356
+ protected readonly startLabelInfo: _angular_core.Signal<{
357
+ label: string;
358
+ placement: StartLabelPlacement;
359
+ } | null>;
360
+ constructor();
361
+ protected coreTick(index: number, count: number): boolean;
362
+ protected deltaFor(point: PlottedPoint): number;
363
+ protected deltaClasses(point: PlottedPoint): string;
364
+ protected tooltipStyle(point: PlottedPoint): string;
365
+ protected onPointerMove(event: PointerEvent): void;
366
+ protected onPointerLeave(): void;
367
+ protected onKeydown(event: KeyboardEvent): void;
368
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiLineChart, never>;
369
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiLineChart, "ui-line-chart", never, { "points": { "alias": "points"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "valueFormat": { "alias": "valueFormat"; "required": false; "isSignal": true; }; "deltaFormat": { "alias": "deltaFormat"; "required": false; "isSignal": true; }; "timeFormat": { "alias": "timeFormat"; "required": false; "isSignal": true; }; "axisFormat": { "alias": "axisFormat"; "required": false; "isSignal": true; }; "startLabel": { "alias": "startLabel"; "required": false; "isSignal": true; }; "timeColumnLabel": { "alias": "timeColumnLabel"; "required": false; "isSignal": true; }; "valueColumnLabel": { "alias": "valueColumnLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
370
+ }
371
+
372
+ /**
373
+ * One action of a `ui-menu`; `destructive` paints it in `--negative`.
374
+ *
375
+ * @example
376
+ * <button uiMenuItem destructive (click)="remove()">Delete the line</button>
377
+ */
378
+ declare class UiMenuItem {
379
+ #private;
380
+ readonly destructive: _angular_core.InputSignalWithTransform<boolean, unknown>;
381
+ protected readonly classes: _angular_core.Signal<string>;
382
+ focus(): void;
383
+ hasFocus(): boolean;
384
+ protected onClick(): void;
385
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiMenuItem, never>;
386
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<UiMenuItem, "button[uiMenuItem]", never, { "destructive": { "alias": "destructive"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
387
+ }
388
+ /**
389
+ * Secondary actions menu, opened from its trigger through the native Popover API.
390
+ *
391
+ * @example
392
+ * <button ui-button size="icon" aria-label="More" [uiMenuTrigger]="menu">...</button>
393
+ * <ui-menu #menu label="Line actions">
394
+ * <button uiMenuItem (click)="edit()">Edit</button>
395
+ * <button uiMenuItem destructive (click)="remove()">Delete the line</button>
396
+ * </ui-menu>
397
+ */
398
+ declare class UiMenu {
399
+ #private;
400
+ readonly label: _angular_core.InputSignal<string>;
401
+ readonly menuId: string;
402
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
403
+ protected readonly classes = "m-0 min-w-44 p-1 rounded-container bg-(--elevated) shadow-[0_8px_24px_rgb(0_0_0/0.16)] text-(--foreground) transition-[opacity,transform,overlay,display] transition-discrete duration-(--duration-fast) ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100";
404
+ protected readonly items: _angular_core.Signal<readonly UiMenuItem[]>;
405
+ open(trigger: HTMLElement): void;
406
+ close(): void;
407
+ protected onToggle(event: Event): void;
408
+ protected onKeydown(event: KeyboardEvent): void;
409
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiMenu, never>;
410
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiMenu, "ui-menu", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; }, {}, ["items"], ["*"], true, never>;
411
+ }
412
+ /**
413
+ * Opens a `ui-menu` from a trigger element and wires `aria-haspopup`, `aria-expanded` and
414
+ * `aria-controls` on it.
415
+ *
416
+ * @example
417
+ * <button ui-button size="icon" aria-label="More" [uiMenuTrigger]="menu">...</button>
418
+ */
419
+ declare class UiMenuTrigger {
420
+ #private;
421
+ readonly uiMenuTrigger: _angular_core.InputSignal<UiMenu>;
422
+ protected toggle(): void;
423
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiMenuTrigger, never>;
424
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<UiMenuTrigger, "[uiMenuTrigger]", never, { "uiMenuTrigger": { "alias": "uiMenuTrigger"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
425
+ }
426
+
243
427
  /** Ramp step used to paint the fill. `MeterTone` is derived from this tuple. */
244
428
  declare const METER_TONES: readonly [1, 2, 3, 4, 5, 6];
245
429
  type MeterTone = (typeof METER_TONES)[number];
@@ -254,13 +438,44 @@ declare class UiMeter {
254
438
  readonly value: _angular_core.InputSignal<number>;
255
439
  readonly label: _angular_core.InputSignal<string>;
256
440
  readonly valueText: _angular_core.InputSignal<string>;
257
- readonly tone: _angular_core.InputSignal<4 | 1 | 2 | 3 | 5 | 6>;
441
+ readonly tone: _angular_core.InputSignal<2 | 4 | 1 | 3 | 5 | 6>;
258
442
  protected readonly percent: _angular_core.Signal<number>;
259
443
  protected readonly fillClasses: _angular_core.Signal<string>;
260
444
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiMeter, never>;
261
445
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiMeter, "ui-meter", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "valueText": { "alias": "valueText"; "required": true; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
262
446
  }
263
447
 
448
+ /**
449
+ * One destination of the sidebar navigation (Portfolio, Holdings, Allocation, Accounts).
450
+ *
451
+ * @example
452
+ * <a ui-nav-item [active]="url === '/'" routerLink="/">
453
+ * <lucide-icon navIcon name="house" />
454
+ * Portfolio
455
+ * </a>
456
+ */
457
+ declare class UiNavItem {
458
+ readonly active: _angular_core.InputSignalWithTransform<boolean, unknown>;
459
+ protected readonly classes: _angular_core.Signal<string>;
460
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiNavItem, never>;
461
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiNavItem, "a[ui-nav-item]", never, { "active": { "alias": "active"; "required": false; "isSignal": true; }; }, {}, never, ["[navIcon]", "*"], true, never>;
462
+ }
463
+
464
+ /**
465
+ * Clickable row of a list: a holding, an envelope, an account.
466
+ *
467
+ * @example
468
+ * <a ui-row [selected]="holding.id === openId()" [routerLink]="['/holdings', holding.id]">
469
+ * {{ holding.name }}
470
+ * </a>
471
+ */
472
+ declare class UiRow {
473
+ readonly selected: _angular_core.InputSignalWithTransform<boolean, unknown>;
474
+ protected readonly classes: _angular_core.Signal<string>;
475
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiRow, never>;
476
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiRow, "a[ui-row], button[ui-row]", never, { "selected": { "alias": "selected"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
477
+ }
478
+
264
479
  type SegmentedOption = {
265
480
  value: string;
266
481
  label: string;
@@ -297,7 +512,7 @@ declare class UiSegmented {
297
512
  * <select uiSelect><option value="pea">PEA</option></select>
298
513
  */
299
514
  declare class UiSelect implements UiControl {
300
- readonly size: _angular_core.InputSignal<"md" | "sm">;
515
+ readonly size: _angular_core.InputSignal<"sm" | "md">;
301
516
  readonly errors: _angular_core.InputSignal<readonly UiControlError[]>;
302
517
  readonly touched: _angular_core.InputSignal<boolean>;
303
518
  protected readonly classes: _angular_core.Signal<string>;
@@ -306,12 +521,8 @@ declare class UiSelect implements UiControl {
306
521
  }
307
522
 
308
523
  /**
309
- * Decorative placeholder for content that is still loading, at the shape of the content it stands
310
- * in for. Deliberately hidden from assistive technology: the calling screen keeps its own
311
- * `role="status"` sentence.
312
- *
313
- * Pulses opacity from 1 to 0.45 and back over `--pulse-duration`, which `tokens.css` sets to `0ms`
314
- * under `prefers-reduced-motion: reduce`: the pulse stops there with no branching in this component.
524
+ * Decorative, pulsing placeholder for content that is still loading, at the shape of the content
525
+ * it stands in for.
315
526
  *
316
527
  * @example
317
528
  * <ui-skeleton shape="figure" />
@@ -354,6 +565,18 @@ declare class UiStat {
354
565
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiStat, "ui-stat", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, ["[uiStatValue]", "[uiStatDelta]", "[uiStatCaption]", "[uiStatAside]"], true, never>;
355
566
  }
356
567
 
568
+ /**
569
+ * Native checkbox styled as an iOS-style switch, exposed to assistive technology as `role="switch"`.
570
+ *
571
+ * @example
572
+ * <input type="checkbox" uiSwitch [checked]="hidden()" (change)="toggle()" aria-label="Hide amounts" />
573
+ */
574
+ declare class UiSwitch {
575
+ protected readonly classes = "relative shrink-0 w-[51px] h-[31px] appearance-none cursor-pointer rounded-pill bg-(--muted) checked:bg-(--primary) transition-colors duration-(--duration-fast) ease-out disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) before:absolute before:inset-x-0 before:top-1/2 before:-translate-y-1/2 before:h-(--row-min) before:content-[''] after:absolute after:top-0.5 after:left-0.5 after:size-[27px] after:rounded-pill after:bg-(--card) after:shadow-[0_1px_3px_rgb(0_0_0/0.2)] after:transition-transform after:duration-(--duration-fast) after:ease-out after:content-[''] checked:after:translate-x-[20px]";
576
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiSwitch, never>;
577
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<UiSwitch, "input[type=checkbox][uiSwitch]", never, {}, {}, never, never, true, never>;
578
+ }
579
+
357
580
  /** Breakpoints a secondary column can be held back until. */
358
581
  declare const CELL_BREAKPOINTS: readonly ["md", "lg"];
359
582
  type CellBreakpoint = (typeof CELL_BREAKPOINTS)[number];
@@ -399,5 +622,30 @@ declare class UiTd {
399
622
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<UiTd, "td[uiTd]", never, { "numeric": { "alias": "numeric"; "required": false; "isSignal": true; }; "from": { "alias": "from"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
400
623
  }
401
624
 
402
- export { AVATAR_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, DELTA_EMPHASES, DIALOG_WIDTHS, METER_TONES, STAT_SIZES, UiAvatar, UiBadge, UiButton, UiCard, UiDelta, UiDialog, UiField, UiInput, UiMeter, UiSegmented, UiSelect, UiSkeleton, UiStat, UiTable, UiTd, UiTextarea, UiTh, UiTr };
403
- export type { AvatarSize, BadgeVariant, ButtonSize, ButtonVariant, CardPadding, CardVariant, CellBreakpoint, ControlSize, DeltaEmphasis, DialogWidth, MeterTone, SegmentedOption, StatSize, UiControlError };
625
+ /**
626
+ * Bottom navigation bar for iPhone: 52px of tabs plus the home indicator's safe area.
627
+ *
628
+ * @example
629
+ * <nav ui-tab-bar>
630
+ * <a ui-tab [active]="url === '/'" routerLink="/"><lucide-icon tabIcon name="house" />Portfolio</a>
631
+ * </nav>
632
+ */
633
+ declare class UiTabBar {
634
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiTabBar, never>;
635
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiTabBar, "nav[ui-tab-bar]", never, {}, {}, never, ["*"], true, never>;
636
+ }
637
+ /**
638
+ * One destination of `ui-tab-bar`.
639
+ *
640
+ * @example
641
+ * <a ui-tab active routerLink="/"><lucide-icon tabIcon name="house" />Portfolio</a>
642
+ */
643
+ declare class UiTab {
644
+ readonly active: _angular_core.InputSignalWithTransform<boolean, unknown>;
645
+ protected readonly classes: _angular_core.Signal<string>;
646
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiTab, never>;
647
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UiTab, "a[ui-tab]", never, { "active": { "alias": "active"; "required": false; "isSignal": true; }; }, {}, never, ["[tabIcon]", "*"], true, never>;
648
+ }
649
+
650
+ export { AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_STATES, AVATAR_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, DELTA_EMPHASES, DIALOG_WIDTHS, METER_TONES, STAT_SIZES, UI_AMOUNT_MASKED, UiAmount, UiAsync, UiAvatar, UiBadge, UiButton, UiCard, UiDelta, UiDialog, UiField, UiInput, UiLineChart, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiSegmented, UiSelect, UiSkeleton, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiTr, formatAmount };
651
+ export type { AmountFormatOptions, AmountMasking, AmountNumeric, AsyncState, AvatarSize, BadgeVariant, ButtonSize, ButtonVariant, CardPadding, CardVariant, CellBreakpoint, ChartPoint, ControlSize, DeltaEmphasis, DialogWidth, MeterTone, SegmentedOption, StatSize, UiControlError };