@underlayerdev/ui 0.9.5 → 0.10.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.
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@underlayerdev/ui",
3
- "version": "0.9.5",
3
+ "version": "0.10.0",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^22.0.0",
6
6
  "@angular/common": "^22.0.0",
7
7
  "@angular/core": "^22.0.0",
8
- "@splidejs/splide": "^4.1.4"
8
+ "@splidejs/splide": "^4.1.4",
9
+ "ngx-image-cropper": "^9.1.7"
9
10
  },
10
11
  "dependencies": {
11
12
  "tslib": "^2.3.0"
@@ -81,7 +81,14 @@ type UiSize = 'sm' | 'md' | 'lg' | 'xl';
81
81
  type UiCheckboxSize = 'default' | 'sm' | 'lg';
82
82
  type UiTheme = 'fill-purple' | 'fill-white' | 'fill-yellow' | 'fill-red' | 'transparent-purple' | 'transparent-white' | 'transparent-red' | 'transparent-black' | 'ghost-purple' | 'ghost-white' | 'ghost-red' | 'ghost-green' | 'outline-white' | 'outline-purple' | 'outline-red' | 'outline-green';
83
83
 
84
- type IconSize$1 = '5' | '6' | '7' | '8';
84
+ type IconSize$1 = '5' | '6' | '7' | '8' | '16';
85
+ /**
86
+ * Avatar-only size scale: the shared UiSize sizes, plus a larger '2xl' for
87
+ * contexts where the avatar itself is the focal point (e.g. an onboarding
88
+ * photo step) rather than one control among many. Deliberately not folded
89
+ * into UiSize — a giant size doesn't make sense on a button or input.
90
+ */
91
+ type AvatarSize = UiSize | '2xl';
85
92
  /**
86
93
  * A reusable avatar component that displays user images, initials, or icons.
87
94
  * Supports multiple sizes and fallback options when an image is not available.
@@ -90,7 +97,7 @@ type IconSize$1 = '5' | '6' | '7' | '8';
90
97
  */
91
98
  declare class AvatarComponent {
92
99
  /** The size of the avatar */
93
- size: _angular_core.InputSignal<UiSize>;
100
+ size: _angular_core.InputSignal<AvatarSize>;
94
101
  /** The image source URL */
95
102
  src: _angular_core.InputSignal<string | undefined>;
96
103
  /** Fallback initials to display when image is not available */
@@ -871,6 +878,98 @@ declare class ImageNotFoundDirective {
871
878
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ImageNotFoundDirective, "[peCatchImageNotFound]", never, { "showPlaceholder": { "alias": "showPlaceholder"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
872
879
  }
873
880
 
881
+ /** Visual shape of the crop mask/frame — purely cosmetic, doesn't affect the exported file. */
882
+ type ImageCropperShape = 'rectangle' | 'round';
883
+ /**
884
+ * Modal flow for cropping/resizing a photo. Wraps ngx-image-cropper so the
885
+ * third-party crop mechanics never leak outside the design system —
886
+ * consumers only ever see `ul-image-cropper`.
887
+ *
888
+ * Two interaction modes, chosen by whether `aspectRatio` is set:
889
+ * - **Locked** (`aspectRatio` given, e.g. `1` for an avatar): a fixed-size
890
+ * frame; the user drags/zooms the photo underneath it. Best when every
891
+ * output needs the same ratio (avatars, thumbnails).
892
+ * - **Free-form** (`aspectRatio` omitted, the default): a resizable frame
893
+ * over a static photo; the user drags its corners to trim/straighten with
894
+ * no ratio imposed. Best for listing photos, which keep their own shape
895
+ * today (see `um-image-upload`'s auto-width carousel).
896
+ *
897
+ * Emits a resized `File`, ready to hand to any upload call that accepts
898
+ * one — this component only produces the file, it never uploads it.
899
+ *
900
+ * @example Locked 1:1 round (avatar)
901
+ * <ul-image-cropper
902
+ * [(open)]="showCropper"
903
+ * [imageFile]="selectedFile"
904
+ * shape="round"
905
+ * [aspectRatio]="1"
906
+ * [maxOutputSize]="512"
907
+ * (cropped)="onCropped($event)"
908
+ * />
909
+ *
910
+ * @example Free-form rectangle (listing photo)
911
+ * <ul-image-cropper
912
+ * [(open)]="showCropper"
913
+ * [imageFile]="selectedFile"
914
+ * [maxOutputSize]="1920"
915
+ * (cropped)="onCropped($event)"
916
+ * />
917
+ */
918
+ declare class ImageCropperComponent {
919
+ /** Whether the crop modal is open. Supports two-way binding with [(open)]. */
920
+ readonly open: _angular_core.ModelSignal<boolean>;
921
+ /** The source photo to crop. Required for the modal to render its content. */
922
+ readonly imageFile: _angular_core.InputSignal<File | null>;
923
+ /** Visual shape of the crop mask. */
924
+ readonly shape: _angular_core.InputSignal<ImageCropperShape>;
925
+ /**
926
+ * Locks the crop frame to this width/height ratio and switches to
927
+ * pan-and-zoom mode. Omit (or pass null) for a free-form resizable frame
928
+ * with no ratio imposed.
929
+ */
930
+ readonly aspectRatio: _angular_core.InputSignal<number | null>;
931
+ /** Longest side (px) of the final output image; scales down without distorting. */
932
+ readonly maxOutputSize: _angular_core.InputSignal<number>;
933
+ /** Title shown in the modal header. */
934
+ readonly title: _angular_core.InputSignal<string>;
935
+ /** Label for the confirm button. */
936
+ readonly confirmLabel: _angular_core.InputSignal<string>;
937
+ /** Label for the cancel button. */
938
+ readonly cancelLabel: _angular_core.InputSignal<string>;
939
+ /** Label next to the zoom slider (locked-aspect mode only). */
940
+ readonly zoomLabel: _angular_core.InputSignal<string>;
941
+ /** Accessible label for the crop frame. */
942
+ readonly frameAriaLabel: _angular_core.InputSignal<string>;
943
+ /** Emitted with the cropped, resized photo once the user confirms. */
944
+ readonly cropped: _angular_core.OutputEmitterRef<File>;
945
+ /** Emitted when the user cancels or dismisses the modal without cropping. */
946
+ readonly cancelled: _angular_core.OutputEmitterRef<void>;
947
+ /** Emitted when the source photo fails to load in the cropper. */
948
+ readonly loadFailed: _angular_core.OutputEmitterRef<void>;
949
+ private readonly cropperRef;
950
+ protected readonly cropperImageFile: _angular_core.Signal<File | undefined>;
951
+ protected readonly isRound: _angular_core.Signal<boolean>;
952
+ protected readonly isLocked: _angular_core.Signal<boolean>;
953
+ /** ngx-image-cropper always wants a number here; unused while isLocked() is false. */
954
+ protected readonly effectiveAspectRatio: _angular_core.Signal<number>;
955
+ protected readonly frameWidth: _angular_core.Signal<number | undefined>;
956
+ protected readonly frameHeight: _angular_core.Signal<number | undefined>;
957
+ protected readonly minZoom = 1;
958
+ protected readonly maxZoom = 3;
959
+ protected readonly zoomStep = 0.01;
960
+ protected readonly zoom: _angular_core.WritableSignal<number>;
961
+ protected readonly transform: _angular_core.Signal<{
962
+ scale: number;
963
+ }>;
964
+ protected readonly cropperReady: _angular_core.WritableSignal<boolean>;
965
+ constructor();
966
+ protected onZoomInput(event: Event): void;
967
+ protected onConfirm(): Promise<void>;
968
+ protected onCancel(): void;
969
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ImageCropperComponent, never>;
970
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ImageCropperComponent, "ul-image-cropper", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "imageFile": { "alias": "imageFile"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "maxOutputSize": { "alias": "maxOutputSize"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "confirmLabel": { "alias": "confirmLabel"; "required": false; "isSignal": true; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; "isSignal": true; }; "zoomLabel": { "alias": "zoomLabel"; "required": false; "isSignal": true; }; "frameAriaLabel": { "alias": "frameAriaLabel"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "cropped": "cropped"; "cancelled": "cancelled"; "loadFailed": "loadFailed"; }, never, never, true, never>;
971
+ }
972
+
874
973
  type InputType = 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
875
974
  /** Border and hover style: border-only (hover = border only), subtle-tint (hover = border + 5% fill). */
876
975
  type InputAppearance = 'border-only' | 'subtle-tint';
@@ -1389,6 +1488,22 @@ declare class SkeletonComponent {
1389
1488
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonComponent, "ul-skeleton", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "lines": { "alias": "lines"; "required": false; "isSignal": true; }; "borderRadius": { "alias": "borderRadius"; "required": false; "isSignal": true; }; "show": { "alias": "show"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1390
1489
  }
1391
1490
 
1491
+ /**
1492
+ * Presentational step indicator for a multi-step flow (e.g. onboarding,
1493
+ * checkout) — dots connected by a line, current/completed/upcoming states.
1494
+ * Purely visual: it has no notion of step content or navigation, the
1495
+ * consumer owns that. `currentStep` is 1-indexed.
1496
+ */
1497
+ declare class StepperComponent {
1498
+ readonly totalSteps: _angular_core.InputSignal<number>;
1499
+ readonly currentStep: _angular_core.InputSignal<number>;
1500
+ readonly labels: _angular_core.InputSignal<string[]>;
1501
+ readonly ariaLabel: _angular_core.InputSignal<string | null>;
1502
+ protected readonly stepIndexes: _angular_core.Signal<number[]>;
1503
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<StepperComponent, never>;
1504
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<StepperComponent, "ul-stepper", never, { "totalSteps": { "alias": "totalSteps"; "required": true; "isSignal": true; }; "currentStep": { "alias": "currentStep"; "required": true; "isSignal": true; }; "labels": { "alias": "labels"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1505
+ }
1506
+
1392
1507
  type ToastKind = 'info' | 'success' | 'warning' | 'error';
1393
1508
  declare const toastIcon: (kind: ToastKind) => "info" | "alert" | "check_circle" | "cross_circle";
1394
1509
  interface ToastConfig {
@@ -1980,5 +2095,5 @@ declare class TextareaComponent implements FormValueControl<string> {
1980
2095
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TextareaComponent, "ul-textarea", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showRequiredIndicator": { "alias": "showRequiredIndicator"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "minLength": { "alias": "minLength"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "resize": { "alias": "resize"; "required": false; "isSignal": true; }; "groupFocused": { "alias": "groupFocused"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "touched": "touchedChange"; "touch": "touch"; "value": "valueChange"; "inputBlur": "inputBlur"; "inputFocus": "inputFocus"; }, ["customField"], ["[ul-textarea-left-elements]", "[ul-textarea-field]", "[ul-textarea-right-elements]"], true, never>;
1981
2096
  }
1982
2097
 
1983
- export { AccordionComponent, AccordionItemComponent, AreaCodeComponent, AvatarComponent, AvatarGroupComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, CardComponent, CarouselComponent, CarouselItemComponent, CheckboxComponent, CollapseComponent, CustomCurrencyPipe, DockComponent, DockItemComponent, DockItemContentSlotDirective, DropdownComponent, FileInputComponent, FooterComponent, FormFieldHelperComponent, FormFieldLabelComponent, HeroComponent, IconComponent, ImageNotFoundDirective, InputComponent, ListItemComponent, LongPressDirective, MenuComponent, MenuItemsComponent, MenuTriggerComponent, ModalComponent, NavbarAppNameSlotDirective, NavbarAvatarSlotDirective, NavbarComponent, NavbarLogoSlotDirective, NavbarSearchSlotDirective, PeHeroActionsSlotDirective, PeHeroBadgesSlotDirective, PeHeroContentSlotDirective, PeHeroSubtitleSlotDirective, PeHeroTitleSlotDirective, PillComponent, PriceButtonComponent, RadialComponent, RadioComponent, RadioGroupComponent, RichTextComponent, SearchInputComponent, SearchSelectComponent, SelectComponent, SelectableRowComponent, SidebarComponent, SkeletonComponent, StatusComponent, TableComponent, TextareaComponent, TextareaFieldDirective, ToastContainerComponent, ToastService, ToggleComponent, TooltipComponent, createFormFieldIds, getFormFieldDescribedBy, toastIcon };
1984
- export type { ActionsDistribution, AvatarData, BreadcrumbItem, BreadcrumbSeparator, CalendarDay, CalendarMode, CardCaptionSize, CardDirection, CheckboxZoneType, CollapseVariant, Currency, DockItemVariant, DropdownItem, FileInputAppearance, HeroAction, HeroAlignment, HeroSize, IconName, IconSize, IconWeight, InputAppearance, InputType, ListItemTheme, MediaAspectRatio, MenuItem, ModalVariant, PillSize, PillTheme, PillVariant, RadioGroupOption, RichTextSize, RichTextTone, SalePosition, SearchSelectOption, SearchSuggestion, SelectOption, SidebarItem, SkeletonBorderRadius, SkeletonVariant, SortDirection, Status, TableColumn, TextareaResize, TimeSelection, ToastConfig, ToastKind, ToastWithRole, TooltipPosition };
2098
+ export { AccordionComponent, AccordionItemComponent, AreaCodeComponent, AvatarComponent, AvatarGroupComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, CardComponent, CarouselComponent, CarouselItemComponent, CheckboxComponent, CollapseComponent, CustomCurrencyPipe, DockComponent, DockItemComponent, DockItemContentSlotDirective, DropdownComponent, FileInputComponent, FooterComponent, FormFieldHelperComponent, FormFieldLabelComponent, HeroComponent, IconComponent, ImageCropperComponent, ImageNotFoundDirective, InputComponent, ListItemComponent, LongPressDirective, MenuComponent, MenuItemsComponent, MenuTriggerComponent, ModalComponent, NavbarAppNameSlotDirective, NavbarAvatarSlotDirective, NavbarComponent, NavbarLogoSlotDirective, NavbarSearchSlotDirective, PeHeroActionsSlotDirective, PeHeroBadgesSlotDirective, PeHeroContentSlotDirective, PeHeroSubtitleSlotDirective, PeHeroTitleSlotDirective, PillComponent, PriceButtonComponent, RadialComponent, RadioComponent, RadioGroupComponent, RichTextComponent, SearchInputComponent, SearchSelectComponent, SelectComponent, SelectableRowComponent, SidebarComponent, SkeletonComponent, StatusComponent, StepperComponent, TableComponent, TextareaComponent, TextareaFieldDirective, ToastContainerComponent, ToastService, ToggleComponent, TooltipComponent, createFormFieldIds, getFormFieldDescribedBy, toastIcon };
2099
+ export type { ActionsDistribution, AvatarData, AvatarSize, BreadcrumbItem, BreadcrumbSeparator, CalendarDay, CalendarMode, CardCaptionSize, CardDirection, CheckboxZoneType, CollapseVariant, Currency, DockItemVariant, DropdownItem, FileInputAppearance, HeroAction, HeroAlignment, HeroSize, IconName, IconSize, IconWeight, ImageCropperShape, InputAppearance, InputType, ListItemTheme, MediaAspectRatio, MenuItem, ModalVariant, PillSize, PillTheme, PillVariant, RadioGroupOption, RichTextSize, RichTextTone, SalePosition, SearchSelectOption, SearchSuggestion, SelectOption, SidebarItem, SkeletonBorderRadius, SkeletonVariant, SortDirection, Status, TableColumn, TextareaResize, TimeSelection, ToastConfig, ToastKind, ToastWithRole, TooltipPosition };