@ng-solid/design-system 22.3.0 → 22.4.1

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.
@@ -122,13 +122,21 @@ declare class NsBreadcrumbsComponent {
122
122
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsBreadcrumbsComponent, "ns-breadcrumbs", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
123
123
  }
124
124
 
125
- type NsButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'success' | 'danger';
125
+ type NsButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'success' | 'danger' | 'dark';
126
+ type NsButtonSize = 'xs' | NsSize;
126
127
  declare class NsButtonComponent {
127
128
  readonly type: _angular_core.InputSignal<"button" | "submit" | "reset">;
128
129
  readonly variant: _angular_core.InputSignal<NsButtonVariant>;
129
- readonly size: _angular_core.InputSignal<NsSize>;
130
+ readonly size: _angular_core.InputSignal<NsButtonSize>;
130
131
  readonly icon: _angular_core.InputSignal<string>;
131
132
  readonly iconOnly: _angular_core.InputSignalWithTransform<boolean, unknown>;
133
+ /**
134
+ * Explicit `ns-icon` size override. Defaults to 14 for `size="xs"` and 16
135
+ * for every other size when left unset.
136
+ */
137
+ readonly iconSize: _angular_core.InputSignalWithTransform<number, unknown>;
138
+ /** Resolved `ns-icon` size: `iconSize()` when set, else a per-size default. */
139
+ readonly effectiveIconSize: _angular_core.Signal<number>;
132
140
  readonly ariaLabel: _angular_core.InputSignal<string>;
133
141
  readonly block: _angular_core.InputSignalWithTransform<boolean, unknown>;
134
142
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
@@ -150,7 +158,7 @@ declare class NsButtonComponent {
150
158
  private readonly control;
151
159
  focus(): void;
152
160
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsButtonComponent, never>;
153
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsButtonComponent, "ns-button", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
161
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsButtonComponent, "ns-button", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "iconSize": { "alias": "iconSize"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
154
162
  }
155
163
 
156
164
  type NsButtonGroupSelectionMode = 'single' | 'multiple';
@@ -199,7 +207,7 @@ type NsChipColor = NsColor | 'info' | 'selected';
199
207
  * `ns-chip` and intentionally not added to the shared `NsVariant` union.
200
208
  */
201
209
  type NsChipVariant = Exclude<NsVariant, 'ghost'> | 'tint';
202
- type NsChipSize = 'md' | 'pill';
210
+ type NsChipSize = 'md' | 'pill' | 'choice';
203
211
  declare class NsChipComponent {
204
212
  readonly color: _angular_core.InputSignal<NsChipColor>;
205
213
  readonly variant: _angular_core.InputSignal<NsChipVariant>;
@@ -505,6 +513,7 @@ declare class NsEditorColorPickerComponent implements OnInit {
505
513
  private editor;
506
514
  readonly presets: _angular_core.InputSignal<string[][]>;
507
515
  readonly type: _angular_core.InputSignal<"text_color" | "background_color">;
516
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
508
517
  showPopup: boolean;
509
518
  activeColor?: string;
510
519
  isActive: boolean;
@@ -516,10 +525,23 @@ declare class NsEditorColorPickerComponent implements OnInit {
516
525
  onColorSelect(color: string): void;
517
526
  remove(): void;
518
527
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorColorPickerComponent, never>;
519
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorColorPickerComponent, "ns-editor-color-picker", never, { "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
528
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorColorPickerComponent, "ns-editor-color-picker", never, { "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
529
+ }
530
+
531
+ declare class NsEditorImageComponent implements OnInit {
532
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
533
+ formImage: FormGroup;
534
+ show: boolean;
535
+ private fb;
536
+ private editor;
537
+ ngOnInit(): void;
538
+ insert(): void;
539
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorImageComponent, never>;
540
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorImageComponent, "ns-editor-image", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
520
541
  }
521
542
 
522
543
  declare class NsEditorLinkComponent implements OnInit {
544
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
523
545
  formLink: FormGroup;
524
546
  show: boolean;
525
547
  private fb;
@@ -527,7 +549,7 @@ declare class NsEditorLinkComponent implements OnInit {
527
549
  ngOnInit(): void;
528
550
  insert(): void;
529
551
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorLinkComponent, never>;
530
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorLinkComponent, "ns-editor-link", never, {}, {}, never, never, true, never>;
552
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorLinkComponent, "ns-editor-link", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
531
553
  }
532
554
 
533
555
  declare enum Commands {
@@ -554,29 +576,32 @@ declare enum Commands {
554
576
 
555
577
  declare class NsEditorListComponent implements OnInit {
556
578
  private editor;
579
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
557
580
  commands: typeof Commands;
558
581
  ngOnInit(): void;
559
582
  command(name: Commands): void;
560
583
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorListComponent, never>;
561
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorListComponent, "ns-editor-list", never, {}, {}, never, never, true, never>;
584
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorListComponent, "ns-editor-list", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
562
585
  }
563
586
 
564
587
  declare class NsEditorParagraphComponent {
565
588
  private editor;
589
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
566
590
  id: string;
567
591
  private _value;
568
592
  get value(): string;
569
593
  set value(heading: string);
570
594
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorParagraphComponent, never>;
571
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorParagraphComponent, "ns-editor-paragraph", never, {}, {}, never, never, true, never>;
595
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorParagraphComponent, "ns-editor-paragraph", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
572
596
  }
573
597
 
574
598
  declare class NsEditorToggleCommandComponent {
575
599
  private editor;
600
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
576
601
  commands: typeof Commands;
577
602
  command(name: Commands): void;
578
603
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorToggleCommandComponent, never>;
579
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorToggleCommandComponent, "ns-editor-toggle", never, {}, {}, never, never, true, never>;
604
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorToggleCommandComponent, "ns-editor-toggle", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
580
605
  }
581
606
 
582
607
  declare abstract class NsValueAccessor<T = string> implements ControlValueAccessor {
@@ -735,14 +760,17 @@ declare class NsDropdownItemDirective {
735
760
  readonly key: _angular_core.InputSignal<NsKey>;
736
761
  readonly label: _angular_core.InputSignal<string>;
737
762
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
763
+ readonly dot: _angular_core.InputSignal<NsColor>;
738
764
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsDropdownItemDirective, never>;
739
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NsDropdownItemDirective, "ns-dropdown-item", never, { "key": { "alias": "key"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
765
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NsDropdownItemDirective, "ns-dropdown-item", never, { "key": { "alias": "key"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
740
766
  }
741
767
 
742
768
  interface NsDropdownItem<T = unknown> {
743
769
  key: NsKey;
744
770
  label: string;
745
771
  disabled?: boolean;
772
+ /** Optional color dot rendered before the label (decorative, `aria-hidden`). */
773
+ dot?: NsColor;
746
774
  value?: T;
747
775
  }
748
776
  type NsDropdownValue = NsKey | readonly NsKey[] | null;
@@ -751,6 +779,7 @@ interface NsDropdownWorkingItem {
751
779
  readonly key: NsKey;
752
780
  readonly label: string;
753
781
  readonly disabled: boolean;
782
+ readonly dot?: NsColor;
754
783
  }
755
784
  declare class NsDropdownComponent extends NsValueAccessor<NsDropdownValue> {
756
785
  readonly collection: _angular_core.InputSignal<readonly NsDropdownItem<unknown>[]>;
@@ -782,6 +811,8 @@ declare class NsDropdownComponent extends NsValueAccessor<NsDropdownValue> {
782
811
  readonly visibleItems: _angular_core.Signal<NsDropdownWorkingItem[]>;
783
812
  readonly selectedKeys: _angular_core.Signal<ReadonlySet<NsKey>>;
784
813
  readonly selectedLabel: _angular_core.Signal<string>;
814
+ /** Dot of the selected item; the trigger shows it for single selection only. */
815
+ readonly selectedDot: _angular_core.Signal<NsColor>;
785
816
  readonly activeId: _angular_core.Signal<string>;
786
817
  constructor();
787
818
  toggle(): void;
@@ -829,6 +860,7 @@ declare class NsInputNumberComponent extends NsValueAccessor<number | null> {
829
860
  readonly currency: _angular_core.InputSignal<string>;
830
861
  readonly format: _angular_core.InputSignal<Intl.NumberFormatOptions>;
831
862
  readonly displayValue: _angular_core.WritableSignal<string>;
863
+ readonly currencyPrefix: _angular_core.Signal<string>;
832
864
  writeValue(value: number | null): void;
833
865
  onInput(text: string): void;
834
866
  onInputEvent(event: Event): void;
@@ -836,6 +868,29 @@ declare class NsInputNumberComponent extends NsValueAccessor<number | null> {
836
868
  onKeydown(event: KeyboardEvent): void;
837
869
  stepBy(direction: 1 | -1): void;
838
870
  private get formatter();
871
+ /**
872
+ * `format: { style: 'percent' }` deliberately breaks from `Intl.NumberFormat`'s
873
+ * own convention. `Intl` expects a *fraction* (`format(0.1)` → "10%"); this
874
+ * component's model is the 0-100 *magnitude* instead (`100` means 100%), so a
875
+ * model of `10` paints "10%".
876
+ *
877
+ * Why: almost every form in this codebase stores a percentage as an integer
878
+ * 0-100 (discounts, tax rates, commission splits, `min`/`max`/`step` all read
879
+ * naturally as "0 to 100"). Making the model a 0-1 fraction would just push
880
+ * the ×100/÷100 conversion onto every consumer instead of doing it once here.
881
+ *
882
+ * Do NOT "fix" this back to matching `Intl` — that silently multiplies every
883
+ * stored percentage by 100 the next time this input round-trips a value.
884
+ * The bug this comment guards against: `formatDisplayValue` used to hand the
885
+ * raw 0-100 model straight to `Intl` (which reads it as a fraction, so `0.1`
886
+ * printed as "10%"), while `parse` read "10%" back as the magnitude `10` — a
887
+ * value that then painted as "1,000%" on the next blur. `parse` already
888
+ * returns the 0-100 magnitude and is intentionally left untouched; only the
889
+ * percent *formatting* path divides by 100 before calling `Intl`.
890
+ */
891
+ private isPercentMode;
892
+ private formatDisplayValue;
893
+ /** Returns the 0-100 magnitude even in percent mode — see `isPercentMode`. */
839
894
  private parse;
840
895
  private constrain;
841
896
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsInputNumberComponent, never>;
@@ -954,9 +1009,16 @@ declare class NsContentEditableComponent extends NsValueAccessor<string> {
954
1009
  private elementRef;
955
1010
  private renderer;
956
1011
  readonly maxLength: _angular_core.InputSignal<number>;
1012
+ /**
1013
+ * Character count of the rendered content, measured the same way the
1014
+ * `maxlength` guard below measures it (`innerText.length`) so a consumer's
1015
+ * counter never drifts from what actually blocks typing.
1016
+ */
1017
+ readonly length: _angular_core.WritableSignal<number>;
957
1018
  enabled: boolean;
958
1019
  writeValue(value: string): void;
959
1020
  onInput(): void;
1021
+ private updateLength;
960
1022
  onBlur(): void;
961
1023
  onKeyUp(event: KeyboardEvent): void;
962
1024
  setDisabledState(isDisabled: boolean): void;
@@ -982,22 +1044,28 @@ declare class NsFieldDirective {
982
1044
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NsFieldDirective, "[nsField]", never, { "controlId": { "alias": "nsField"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
983
1045
  }
984
1046
 
1047
+ type NsEditorTool = 'paragraph' | 'format' | 'color' | 'list' | 'link' | 'image' | 'separator';
1048
+ declare const NS_EDITOR_TOOLS_DEFAULT: readonly NsEditorTool[];
985
1049
  declare class NsEditorComponent extends NsValueAccessor<string> implements OnInit, OnDestroy {
986
1050
  private editor;
987
- readonly rows: _angular_core.InputSignal<number>;
988
1051
  readonly maxLength: _angular_core.InputSignal<number>;
989
1052
  readonly colorPresets: _angular_core.InputSignal<string[]>;
1053
+ readonly tools: _angular_core.InputSignal<readonly NsEditorTool[]>;
990
1054
  textArea: ElementRef<HTMLElement>;
1055
+ private contentEditable;
1056
+ /** Mirrors the content-editable's own counter, measured off `innerText`. */
1057
+ readonly length: _angular_core.Signal<number>;
1058
+ readonly hasFooter: _angular_core.Signal<boolean>;
991
1059
  focused: () => void;
992
1060
  ngOnInit(): void;
993
1061
  get presets(): string[][];
994
1062
  blur(): void;
995
1063
  ngOnDestroy(): void;
996
1064
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsEditorComponent, never>;
997
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorComponent, "ns-editor", never, { "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "colorPresets": { "alias": "colorPresets"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1065
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEditorComponent, "ns-editor", never, { "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "colorPresets": { "alias": "colorPresets"; "required": false; "isSignal": true; }; "tools": { "alias": "tools"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
998
1066
  }
999
1067
 
1000
- type NsEmptyStateSize = 'sm' | 'md';
1068
+ type NsEmptyStateSize = 'sm' | 'md' | 'lg';
1001
1069
  declare class NsEmptyStateComponent {
1002
1070
  readonly title: _angular_core.InputSignal<string>;
1003
1071
  readonly description: _angular_core.InputSignal<string>;
@@ -1006,31 +1074,189 @@ declare class NsEmptyStateComponent {
1006
1074
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsEmptyStateComponent, "ns-empty-state", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, ["[empty-state-icon]", "[empty-state-actions]"], true, never>;
1007
1075
  }
1008
1076
 
1077
+ /**
1078
+ * No structural difference from `NsFile` — the guarantee this alias
1079
+ * documents ("already has an entry in `uidRegistry`") lives in the registry,
1080
+ * not on the object. Kept as a distinct name at call sites (`images()`,
1081
+ * `image()`, `retry()`, `remove()`) that specifically require an image which
1082
+ * has already been through `assignUid`.
1083
+ */
1084
+ type TrackedFile = NsFile;
1085
+ /**
1086
+ * Per-file upload status, keyed by `uid` (AVF-16). Replaces the old
1087
+ * `loading: Set<string>` — a boolean set can't distinguish "still
1088
+ * uploading" from "upload failed", which was the actual gap this HU closes.
1089
+ * `'ok'` is set (not deleted) on success so a file that went through this
1090
+ * component's own upload pipeline stays traceable; a file that arrived via
1091
+ * `writeValue`/`[value]` and never uploaded here simply has no entry, which
1092
+ * every template check (`=== 'subiendo'` / `=== 'fallido'`) already treats
1093
+ * as the normal/idle state.
1094
+ */
1095
+ type NsImageUploadFileStatus = 'subiendo' | 'ok' | 'fallido';
1009
1096
  declare class NsImageUploadComponent extends NsValueAccessor<NsFile | NsFile[] | null> {
1010
1097
  private client;
1011
1098
  private renderer;
1099
+ private readonly cdr;
1012
1100
  readonly accept: _angular_core.InputSignal<string>;
1013
1101
  readonly multi: _angular_core.InputSignalWithTransform<boolean, unknown>;
1014
1102
  readonly limit: _angular_core.InputSignalWithTransform<number, unknown>;
1103
+ readonly layout: _angular_core.InputSignal<"grid" | "cover">;
1104
+ /**
1105
+ * Rows the `__stack` column reserves before it starts scrolling
1106
+ * internally, in `layout="cover"`: at most 3, and never more than
1107
+ * `limit() - 1` (the cover itself takes one slot).
1108
+ */
1109
+ readonly reservedRows: _angular_core.Signal<number>;
1015
1110
  imgRef: ElementRef<HTMLInputElement>;
1016
- loading: Set<string>;
1111
+ status: Map<string, NsImageUploadFileStatus>;
1112
+ /**
1113
+ * Bumped by `setStatus`/`deleteStatus` on every `status` mutation.
1114
+ * `status` itself stays a plain, publicly-mutable `Map` — kept for the
1115
+ * existing per-file bookkeeping and for tests that poll it to synchronise
1116
+ * with an async upload — but a plain `Map.set()`/`.delete()` is invisible
1117
+ * to Angular's change detection: no signal write and no `markForCheck()`,
1118
+ * so nothing tells Angular this control needs checking again. Worse, an
1119
+ * `OnPush` ancestor that wasn't otherwise dirtied (e.g. the "Fotografías"
1120
+ * `<card>` wrapping this control in the product form) can skip this
1121
+ * subtree entirely on the next tick. That is exactly why a failed upload
1122
+ * used to get stuck showing the spinner forever, silently (AVF-18
1123
+ * corrección de rechazo #2): `status.set(uid, 'fallido')` ran, but nothing
1124
+ * ever told Angular to look again — unlike a successful upload, which
1125
+ * reaches the template through `value.set()` (a real signal write) via
1126
+ * `assignValue`/`onChange`. `statusOf()` reads this counter before reading
1127
+ * `status`, giving every render that goes through it a real signal
1128
+ * dependency, and `touchStatus()` also calls `markForCheck()` directly —
1129
+ * belt and braces: the explicit call is the same, long-proven mechanism
1130
+ * Angular has always used to announce a change made from outside its own
1131
+ * detection cycle (an RxJS subscription callback, here), and is what
1132
+ * reliably walks the ancestor chain and clears an `OnPush` skip, the way
1133
+ * a signal read alone was not enough to guarantee in practice.
1134
+ */
1135
+ private readonly statusVersion;
1136
+ private touchStatus;
1137
+ private setStatus;
1138
+ private deleteStatus;
1139
+ /**
1140
+ * The only path from `status` + `uid` to the template — and the one every
1141
+ * test should use too (AVF-18 corrección de rechazo #2): reading
1142
+ * `status.get(...)` directly, the way earlier tests did, cannot tell a
1143
+ * status change nobody announced to Angular from one that actually
1144
+ * rendered, which is exactly how the previous regression shipped green —
1145
+ * the map held `'fallido'`, the DOM still showed `'subiendo'`, and the
1146
+ * assertions that read the map straight agreed with the bug.
1147
+ */
1148
+ statusOf(image: NsFile): NsImageUploadFileStatus | undefined;
1149
+ /**
1150
+ * Active while a file dragged from outside the browser (desktop, another
1151
+ * app) hovers a drop zone — drives the highlight ring/border (AVF-9,
1152
+ * criteria 3-5). Never set for the internal thumbnail-reorder drag,
1153
+ * distinguished via `isFileDrag`.
1154
+ */
1155
+ readonly dragActive: _angular_core.WritableSignal<boolean>;
1156
+ /**
1157
+ * Inline, Spanish, component-owned notice for when a selection/drop
1158
+ * exceeds `limit()` (AVF-16). Deliberately not an `output()`: a consumer
1159
+ * that doesn't wire one up would silently drop files again, which is
1160
+ * exactly the defect this HU removes. Overwritten (never accumulated) on
1161
+ * every enqueue attempt, successful or not.
1162
+ */
1163
+ readonly limitWarning: _angular_core.WritableSignal<string>;
1017
1164
  private _fromIndex;
1018
1165
  private _toIndex;
1019
- get images(): NsFile[];
1020
- get image(): NsFile | null;
1166
+ /**
1167
+ * The only path from `value()` to the template, whatever fed it: a plain
1168
+ * `[value]="misImagenes"` binding — `value` is the public two-way `model()`
1169
+ * from `NsValueAccessor`, so nothing forces a consumer through
1170
+ * `writeValue`/`add` — lands here same as a file picked through the
1171
+ * control itself. `assignUid` is idempotent (never overwrites an existing
1172
+ * registry entry) and never mutates the `NsFile`, so re-running it every
1173
+ * getter call is safe: the `uid` a given instance gets on its first pass
1174
+ * through here is the one it keeps on every later change-detection cycle,
1175
+ * and no signal write happens as a side effect of reading the template
1176
+ * (AVF-15). Works the same whether the array/elements are frozen or not
1177
+ * (AVF-18 corrección de rechazo).
1178
+ */
1179
+ get images(): TrackedFile[];
1180
+ get image(): TrackedFile | null;
1181
+ /**
1182
+ * Reads the `uid` assigned to `image` — the accessor the `.ts` and the
1183
+ * template both use instead of a `.uid` property on the `NsFile` itself,
1184
+ * which no longer exists (AVF-18 corrección de rechazo: that property
1185
+ * write is exactly what threw on a frozen image). Public so the
1186
+ * template's `track` expressions can call it directly, and so `statusOf`
1187
+ * can resolve the key it looks up. Every `NsFile` reachable from
1188
+ * `images()`/`image()` has already been through `assignUid`, so this only
1189
+ * ever reads — the `assignUid` call here is a safety net for a caller that
1190
+ * hands in an image from outside that path.
1191
+ */
1192
+ uidOf(image: NsFile): string;
1193
+ /**
1194
+ * True while the single (`!multi()`) image's own upload attempt is
1195
+ * `'fallido'` — the one flag the drag-container button needs to swap
1196
+ * "open the file picker" for "retry this upload" (AVF-16, corrección de
1197
+ * rechazo: criterios 5-6 no estaban cubiertos en modo single, solo en
1198
+ * `multi`).
1199
+ */
1200
+ get singleFailed(): boolean;
1021
1201
  writeValue(value: NsFile | NsFile[] | null): void;
1022
1202
  onClick(): void;
1203
+ /**
1204
+ * Click handler for the single-mode (`!multi()`) drag-container: it is
1205
+ * both the file picker trigger and, once the image has failed, the
1206
+ * retry control — same dual role the `multi` grid button and the cover
1207
+ * chip already had (AVF-16 corrección de rechazo).
1208
+ */
1209
+ onDragContainerClick(): void;
1023
1210
  load(): void;
1024
1211
  add(image: NsFile): void;
1212
+ /**
1213
+ * Re-subscribes to the same upload the failed attempt used — no new
1214
+ * `NsUploadClient` contract needed (AVF-16 evidence: `upload(file):
1215
+ * Observable<file>` is already re-subscribable). Shared by the first
1216
+ * attempt (`add`) and every later retry. `uid` is passed in rather than
1217
+ * re-derived from `image`, since `retry()` needs the *original* uid even
1218
+ * though the `image` it holds may itself be a server response object by
1219
+ * then.
1220
+ */
1221
+ private upload;
1222
+ /**
1223
+ * Retries a failed upload in place: same `uid`, same position in the
1224
+ * gallery, no re-read from disk (the preview already holds the file's
1225
+ * data).
1226
+ */
1227
+ retry(image: TrackedFile): void;
1025
1228
  private assignValue;
1026
- private compareWith;
1027
- remove(image: NsFile): void;
1229
+ remove(image: TrackedFile): void;
1028
1230
  dragstart(event: DragEvent, index: number): void;
1231
+ /**
1232
+ * Shared by every drop target (thumbnails, the `cover` node — index 0 —
1233
+ * and the plain drop zones). `event.dataTransfer.types` never carries
1234
+ * `'Files'` for the internal reorder drag (it writes nothing to the
1235
+ * clipboard today), so that check alone tells the external-file drop and
1236
+ * the reorder drag apart without a separate state flag.
1237
+ */
1029
1238
  dragover(event: DragEvent, index: number): void;
1239
+ dragleave(event: DragEvent): void;
1030
1240
  dragend(event: DragEvent): void;
1031
1241
  drop(event: DragEvent): void;
1242
+ private isFileDrag;
1243
+ private isAcceptedFile;
1244
+ private addDroppedFile;
1245
+ /**
1246
+ * Accepts as many of `files` as fit under `limit()`, all at once, and
1247
+ * reports the rest inline. `limit()` is evaluated once here, against
1248
+ * `this.images.length` as it stands *before* any of this batch's
1249
+ * `add()` calls run — never inside a per-file callback, where it would
1250
+ * lag behind sibling files whose `FileReader`/upload hasn't resolved yet
1251
+ * and let more through than actually fit (AVF-16).
1252
+ *
1253
+ * Returns how many files were actually enqueued, so callers can decide
1254
+ * whether to mark the control touched.
1255
+ */
1256
+ private enqueueFiles;
1257
+ private buildLimitWarning;
1032
1258
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsImageUploadComponent, never>;
1033
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsImageUploadComponent, "ns-image-upload", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1259
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsImageUploadComponent, "ns-image-upload", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1034
1260
  }
1035
1261
 
1036
1262
  declare class NsLinkComponent {
@@ -1416,20 +1642,34 @@ declare class NsSkeletonComponent {
1416
1642
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsSkeletonComponent, "ns-skeleton", never, { "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "animated": { "alias": "animated"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1417
1643
  }
1418
1644
 
1419
- type NsStatCardVariant = 'default' | 'dark' | 'compact';
1645
+ type NsStatCardVariant = 'default' | 'dark' | 'compact' | 'tile';
1420
1646
  type NsStatCardDeltaTone = 'up' | 'down' | 'neutral';
1421
1647
  type NsStatCardValueTone = 'default' | 'success' | 'warning' | 'danger' | 'info';
1648
+ type NsStatCardHintTone = 'default' | 'success' | 'warning' | 'danger' | 'info';
1649
+ type NsStatCardIconTone = 'info' | 'success' | 'warning' | 'danger' | 'neutral';
1422
1650
  /**
1423
1651
  * Dashboard metric card: label, formatted value (with an optional muted
1424
1652
  * suffix), and an optional delta pill (`up` / `down` / `neutral`) with a
1425
1653
  * caption and a secondary hint. `variant="dark"` renders the emphasis
1426
1654
  * surface used for headline metrics; `variant="compact"` renders a smaller
1427
- * card with a smaller value size. Set `interactive` to render the card as a
1428
- * `<button>` and receive `(activated)` instead of a static `<div>`.
1655
+ * card with a smaller value size; `variant="tile"` renders a compact KPI
1656
+ * tile (icon circle beside a label/value/delta column, delta as plain
1657
+ * colored text instead of a pill). Set `interactive` to render the card as
1658
+ * a `<button>` and receive `(activated)` instead of a static `<div>`.
1429
1659
  *
1430
1660
  * `valueTone` colors only the headline value with the matching semantic
1431
1661
  * status color (`success`/`warning`/`danger`/`info`); it is ignored on
1432
- * `variant="dark"`, where the value stays white.
1662
+ * `variant="dark"`, where the value stays white. `hintTone` colors only the
1663
+ * hint with the same semantic scale, independently of `valueTone`; like
1664
+ * `valueTone`, it is ignored on `variant="dark"`, where the hint keeps the
1665
+ * emphasis-surface foreground color instead of a status color. `iconTone`
1666
+ * colors the icon wrapper background/foreground and applies to every
1667
+ * variant.
1668
+ *
1669
+ * The hint's own `margin-inline-start: auto` (pushing it to the opposite
1670
+ * edge from the value) only applies when it shares the meta row with a
1671
+ * `delta` and/or `deltaLabel` — something to separate from. A lone hint
1672
+ * (no delta, no deltaLabel) aligns to the start, under the value.
1433
1673
  */
1434
1674
  declare class NsStatCardComponent {
1435
1675
  readonly label: _angular_core.InputSignal<string>;
@@ -1440,13 +1680,15 @@ declare class NsStatCardComponent {
1440
1680
  readonly deltaLabel: _angular_core.InputSignal<string>;
1441
1681
  readonly hint: _angular_core.InputSignal<string>;
1442
1682
  readonly valueTone: _angular_core.InputSignal<NsStatCardValueTone>;
1683
+ readonly hintTone: _angular_core.InputSignal<NsStatCardHintTone>;
1684
+ readonly iconTone: _angular_core.InputSignal<NsStatCardIconTone>;
1443
1685
  readonly variant: _angular_core.InputSignal<NsStatCardVariant>;
1444
1686
  readonly interactive: _angular_core.InputSignalWithTransform<boolean, unknown>;
1445
1687
  readonly activated: _angular_core.OutputEmitterRef<void>;
1446
1688
  protected deltaGlyph(): string;
1447
1689
  protected onActivate(): void;
1448
1690
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NsStatCardComponent, never>;
1449
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsStatCardComponent, "ns-stat-card", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "delta": { "alias": "delta"; "required": false; "isSignal": true; }; "deltaTone": { "alias": "deltaTone"; "required": false; "isSignal": true; }; "deltaLabel": { "alias": "deltaLabel"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "valueTone": { "alias": "valueTone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; }, { "activated": "activated"; }, never, ["[stat-card-icon]", "[stat-card-footer]"], true, never>;
1691
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NsStatCardComponent, "ns-stat-card", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "delta": { "alias": "delta"; "required": false; "isSignal": true; }; "deltaTone": { "alias": "deltaTone"; "required": false; "isSignal": true; }; "deltaLabel": { "alias": "deltaLabel"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "valueTone": { "alias": "valueTone"; "required": false; "isSignal": true; }; "hintTone": { "alias": "hintTone"; "required": false; "isSignal": true; }; "iconTone": { "alias": "iconTone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; }, { "activated": "activated"; }, never, ["[stat-card-icon]", "[stat-card-footer]"], true, never>;
1450
1692
  }
1451
1693
 
1452
1694
  declare class TemplateDirective {
@@ -1549,6 +1791,34 @@ declare const NS_THEME_OPTIONS: InjectionToken<NsResolvedThemeOptions>;
1549
1791
  declare const NS_TOAST_OPTIONS: InjectionToken<NsResolvedToastThemeOptions>;
1550
1792
  declare function provideNsTheme(options?: NsThemeOptions): EnvironmentProviders;
1551
1793
 
1794
+ /**
1795
+ * Registry of theme tokens that used to be part of the Arvisfy preset and no
1796
+ * longer have any effect on rendering. `NsTokenTree` has an open index
1797
+ * signature and `mergeObjects` (below) merges unknown keys in without
1798
+ * complaint, so a consumer overriding a retired token gets no type error and
1799
+ * no `validateNsPreset` error -- the override is silently inert.
1800
+ * `validateNsPreset` walks this map against the resolved preset and emits a
1801
+ * `console.warn` for every retired path still present, so the override at
1802
+ * least surfaces instead of doing nothing invisibly.
1803
+ *
1804
+ * Keys are full token paths, one of:
1805
+ * - `primitive.<path>`
1806
+ * - `semantic.common.<path>`
1807
+ * - `semantic.colorScheme.<light|dark>.<path>`
1808
+ * - `components.<path>`
1809
+ *
1810
+ * Values are the exact message logged for that path. Do not include a
1811
+ * version number in a message: the published package version and this
1812
+ * source's `package.json` version can diverge, so a hardcoded version would
1813
+ * go stale.
1814
+ *
1815
+ * This lives here rather than in its own file: `packages/mcp` transpiles
1816
+ * this module in isolation (`extract-tokens.mjs`'s `assertNoValueImports`)
1817
+ * and cannot resolve a relative value import from a sibling module at that
1818
+ * point, so a second file imported here for its data would break
1819
+ * `nx run mcp:build-data`.
1820
+ */
1821
+ declare const NS_RETIRED_TOKENS: Readonly<Record<string, string>>;
1552
1822
  declare function defineNsPreset(base: NsThemePreset, overrides: NsThemePresetOverrides): NsThemePreset;
1553
1823
  declare function validateNsPreset(preset: NsThemePreset): void;
1554
1824
  declare function flattenTokens<T>(tree: NsTokenTree<T>): Map<string, T>;
@@ -1742,5 +2012,5 @@ declare class NsTooltipDirective implements OnDestroy {
1742
2012
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NsTooltipDirective, "[nsTooltip]", never, { "message": { "alias": "nsTooltip"; "required": true; "isSignal": true; }; "placement": { "alias": "nsTooltipPlacement"; "required": false; "isSignal": true; }; "delay": { "alias": "nsTooltipDelay"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1743
2013
  }
1744
2014
 
1745
- export { Arvisfy, NS_THEME_OPTIONS, NS_TOAST_OPTIONS, NsAccordionComponent, NsAccordionItemComponent, NsAlertComponent, NsAvatarComponent, NsAvatarGroupComponent, NsBadgeComponent, NsBreadcrumbItemComponent, NsBreadcrumbsComponent, NsButtonComponent, NsButtonGroupComponent, NsCardBodyComponent, NsCardComponent, NsCardFooterComponent, NsCardHeaderComponent, NsCheckboxComponent, NsChipComponent, NsCollectionController, NsCommandPaletteComponent, NsCommentComponent, NsContentEditableComponent, NsDatePickerComponent, NsDateRangePickerComponent, NsDescriptionComponent, NsDividerComponent, NsDrawerComponent, NsDrawerRef, NsDrawerService, NsDropdownComponent, NsDropdownItemDirective, NsEditorColorPickerComponent, NsEditorComponent, NsEditorLinkComponent, NsEditorListComponent, NsEditorParagraphComponent, NsEditorToggleCommandComponent, NsEmptyStateComponent, NsFieldContext, NsFieldDirective, NsImageUploadComponent, NsInputCodeComponent, NsInputComponent, NsInputGroupAddonComponent, NsInputGroupComponent, NsInputNumberComponent, NsInputSearchComponent, NsLinkComponent, NsLoadMoreComponent, NsMenuComponent, NsMenuDividerComponent, NsMenuItemComponent, NsMenuSectionComponent, NsMeterComponent, NsModalComponent, NsModalRef, NsModalService, NsOptionCardComponent, NsOverlayRef, NsOverlayService, NsPaginationComponent, NsPasswordComponent, NsPopoverComponent, NsProgressBarComponent, NsRadioComponent, NsRadioGroupComponent, NsSchedule, NsScheduleComponent, NsScheduleService, NsSchemaMarkupComponent, NsSideNavComponent, NsSideNavItemComponent, NsSideNavSectionComponent, NsSkeletonComponent, NsSliderComponent, NsStatCardComponent, NsSurfaceComponent, NsSwitchComponent, NsTabComponent, NsTabsComponent, NsTagComponent, NsTagGroupComponent, NsTextAreaComponent, NsThemeService, NsTimelineComponent, NsTimelineItemComponent, NsToastComponent, NsToastHandle, NsToastService, NsTooltipComponent, NsTooltipDirective, NsValueAccessor, TemplateDirective, defineNsPreset, flattenTokens, getNsOverlayPosition, provideNsTheme, referenceToCssVariable, tokenPathToCssVariable, validateNsPreset };
1746
- export type { NsAlertVariant, NsBadgeMode, NsButtonGroupSelectionMode, NsButtonVariant, NsChipColor, NsChipSize, NsChipVariant, NsCollectionItem, NsColor, NsColorScheme, NsCommandGroup, NsCommandItem, NsComment, NsComponentInputs, NsDateRangeValue, NsDateView, NsDeepPartial, NsDrawerComponentInputs, NsDrawerConfig, NsDrawerOptions, NsDrawerPosition, NsDropdownItem, NsDropdownValue, NsEmptyStateSize, NsFlattenedPrimitiveTokens, NsKey, NsModalConfig, NsModalOptions, NsModalSize, NsOrientation, NsOverlayCloseReason, NsOverlayConfig, NsOverlayPosition, NsPlacement, NsPrimitiveReference, NsPrimitiveTokenValue, NsResolvedColorScheme, NsResolvedThemeOptions, NsResolvedToastThemeOptions, NsSchemaMarkup, NsSchemaType, NsSelectionMode, NsSemanticReference, NsSemanticTokens, NsSideNavColor, NsSize, NsSliderValue, NsStatCardDeltaTone, NsStatCardValueTone, NsStatCardVariant, NsTabsVariant, NsThemeOptions, NsThemePreset, NsThemePresetOverrides, NsTimelineItemColor, NsTimelineSize, NsToastAction, NsToastCloseReason, NsToastOptions, NsToastPlacement, NsToastThemeOptions, NsToastVariant, NsTokenTree, NsVariant };
2015
+ export { Arvisfy, NS_EDITOR_TOOLS_DEFAULT, NS_RETIRED_TOKENS, NS_THEME_OPTIONS, NS_TOAST_OPTIONS, NsAccordionComponent, NsAccordionItemComponent, NsAlertComponent, NsAvatarComponent, NsAvatarGroupComponent, NsBadgeComponent, NsBreadcrumbItemComponent, NsBreadcrumbsComponent, NsButtonComponent, NsButtonGroupComponent, NsCardBodyComponent, NsCardComponent, NsCardFooterComponent, NsCardHeaderComponent, NsCheckboxComponent, NsChipComponent, NsCollectionController, NsCommandPaletteComponent, NsCommentComponent, NsContentEditableComponent, NsDatePickerComponent, NsDateRangePickerComponent, NsDescriptionComponent, NsDividerComponent, NsDrawerComponent, NsDrawerRef, NsDrawerService, NsDropdownComponent, NsDropdownItemDirective, NsEditorColorPickerComponent, NsEditorComponent, NsEditorImageComponent, NsEditorLinkComponent, NsEditorListComponent, NsEditorParagraphComponent, NsEditorToggleCommandComponent, NsEmptyStateComponent, NsFieldContext, NsFieldDirective, NsImageUploadComponent, NsInputCodeComponent, NsInputComponent, NsInputGroupAddonComponent, NsInputGroupComponent, NsInputNumberComponent, NsInputSearchComponent, NsLinkComponent, NsLoadMoreComponent, NsMenuComponent, NsMenuDividerComponent, NsMenuItemComponent, NsMenuSectionComponent, NsMeterComponent, NsModalComponent, NsModalRef, NsModalService, NsOptionCardComponent, NsOverlayRef, NsOverlayService, NsPaginationComponent, NsPasswordComponent, NsPopoverComponent, NsProgressBarComponent, NsRadioComponent, NsRadioGroupComponent, NsSchedule, NsScheduleComponent, NsScheduleService, NsSchemaMarkupComponent, NsSideNavComponent, NsSideNavItemComponent, NsSideNavSectionComponent, NsSkeletonComponent, NsSliderComponent, NsStatCardComponent, NsSurfaceComponent, NsSwitchComponent, NsTabComponent, NsTabsComponent, NsTagComponent, NsTagGroupComponent, NsTextAreaComponent, NsThemeService, NsTimelineComponent, NsTimelineItemComponent, NsToastComponent, NsToastHandle, NsToastService, NsTooltipComponent, NsTooltipDirective, NsValueAccessor, TemplateDirective, defineNsPreset, flattenTokens, getNsOverlayPosition, provideNsTheme, referenceToCssVariable, tokenPathToCssVariable, validateNsPreset };
2016
+ export type { NsAlertVariant, NsBadgeMode, NsButtonGroupSelectionMode, NsButtonSize, NsButtonVariant, NsChipColor, NsChipSize, NsChipVariant, NsCollectionItem, NsColor, NsColorScheme, NsCommandGroup, NsCommandItem, NsComment, NsComponentInputs, NsDateRangeValue, NsDateView, NsDeepPartial, NsDrawerComponentInputs, NsDrawerConfig, NsDrawerOptions, NsDrawerPosition, NsDropdownItem, NsDropdownValue, NsEditorTool, NsEmptyStateSize, NsFlattenedPrimitiveTokens, NsKey, NsModalConfig, NsModalOptions, NsModalSize, NsOrientation, NsOverlayCloseReason, NsOverlayConfig, NsOverlayPosition, NsPlacement, NsPrimitiveReference, NsPrimitiveTokenValue, NsResolvedColorScheme, NsResolvedThemeOptions, NsResolvedToastThemeOptions, NsSchemaMarkup, NsSchemaType, NsSelectionMode, NsSemanticReference, NsSemanticTokens, NsSideNavColor, NsSize, NsSliderValue, NsStatCardDeltaTone, NsStatCardHintTone, NsStatCardIconTone, NsStatCardValueTone, NsStatCardVariant, NsTabsVariant, NsThemeOptions, NsThemePreset, NsThemePresetOverrides, NsTimelineItemColor, NsTimelineSize, NsToastAction, NsToastCloseReason, NsToastOptions, NsToastPlacement, NsToastThemeOptions, NsToastVariant, NsTokenTree, NsVariant };