@up_si_vale/sivale-componentes-angular 1.0.0 → 1.0.2

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 (94) hide show
  1. package/esm2022/lib/atoms/button/button.component.mjs +55 -0
  2. package/esm2022/lib/atoms/checkbox/checkbox.component.mjs +174 -0
  3. package/esm2022/lib/atoms/date-picker/date-picker.component.mjs +835 -0
  4. package/esm2022/lib/atoms/input/input.component.mjs +218 -0
  5. package/esm2022/lib/atoms/loader/loader.component.mjs +81 -0
  6. package/esm2022/lib/atoms/radio/radio.component.mjs +142 -0
  7. package/esm2022/lib/atoms/textarea/textarea.component.mjs +126 -0
  8. package/esm2022/lib/directives/asset-source.directive.mjs +68 -0
  9. package/esm2022/lib/directives/icon-source.directive.mjs +65 -0
  10. package/esm2022/lib/directives/no-leading-space.directive.mjs +24 -0
  11. package/esm2022/lib/directives/only-letters.directive.mjs +25 -0
  12. package/esm2022/lib/directives/only-number.directive.mjs +21 -0
  13. package/esm2022/lib/directives/rfc.directive.mjs +67 -0
  14. package/esm2022/lib/directives/tooltip.directive.mjs +199 -0
  15. package/esm2022/lib/models/snackbar.models.mjs +2 -0
  16. package/esm2022/lib/molecules/alert/alert.component.mjs +79 -0
  17. package/esm2022/lib/molecules/copy-input/copy-input.component.mjs +46 -0
  18. package/esm2022/lib/molecules/multiselect/multiselect.component.mjs +466 -0
  19. package/esm2022/lib/molecules/option/option.component.mjs +55 -0
  20. package/esm2022/lib/molecules/phone-input/phone-input.component.mjs +64 -0
  21. package/esm2022/lib/molecules/select/select.component.mjs +498 -0
  22. package/esm2022/lib/molecules/snackbar/snackbar.component.mjs +581 -0
  23. package/esm2022/lib/organisms/sidebar/sidebar-icon.component.mjs +91 -0
  24. package/esm2022/lib/organisms/sidebar/sidebar.component.mjs +115 -0
  25. package/esm2022/lib/services/snackbar.service.mjs +96 -0
  26. package/esm2022/lib/tokens/asset-base-url.token.mjs +10 -0
  27. package/esm2022/public-api.mjs +37 -0
  28. package/esm2022/up_si_vale-sivale-componentes-angular.mjs +5 -0
  29. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs +4116 -0
  30. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs.map +1 -0
  31. package/index.d.ts +5 -0
  32. package/lib/atoms/button/button.component.d.ts +20 -0
  33. package/lib/atoms/checkbox/checkbox.component.d.ts +31 -0
  34. package/lib/atoms/date-picker/date-picker.component.d.ts +134 -0
  35. package/lib/atoms/input/input.component.d.ts +35 -0
  36. package/lib/atoms/loader/loader.component.d.ts +10 -0
  37. package/lib/atoms/radio/radio.component.d.ts +25 -0
  38. package/lib/atoms/textarea/textarea.component.d.ts +27 -0
  39. package/lib/directives/asset-source.directive.d.ts +19 -0
  40. package/lib/directives/icon-source.directive.d.ts +18 -0
  41. package/lib/directives/no-leading-space.directive.d.ts +6 -0
  42. package/lib/directives/only-letters.directive.d.ts +7 -0
  43. package/lib/directives/only-number.directive.d.ts +6 -0
  44. package/lib/directives/rfc.directive.d.ts +12 -0
  45. package/lib/directives/tooltip.directive.d.ts +27 -0
  46. package/{src/lib/models/snackbar.models.ts → lib/models/snackbar.models.d.ts} +8 -10
  47. package/lib/molecules/alert/alert.component.d.ts +29 -0
  48. package/lib/molecules/copy-input/copy-input.component.d.ts +14 -0
  49. package/lib/molecules/multiselect/multiselect.component.d.ts +74 -0
  50. package/lib/molecules/option/option.component.d.ts +19 -0
  51. package/lib/molecules/phone-input/phone-input.component.d.ts +12 -0
  52. package/lib/molecules/select/select.component.d.ts +88 -0
  53. package/lib/molecules/snackbar/snackbar.component.d.ts +17 -0
  54. package/lib/organisms/sidebar/sidebar-icon.component.d.ts +8 -0
  55. package/lib/organisms/sidebar/sidebar.component.d.ts +47 -0
  56. package/lib/services/snackbar.service.d.ts +40 -0
  57. package/{src/lib/tokens/asset-base-url.token.ts → lib/tokens/asset-base-url.token.d.ts} +1 -5
  58. package/package.json +39 -28
  59. package/{src/public-api.ts → public-api.d.ts} +3 -15
  60. package/ng-package.json +0 -9
  61. package/src/lib/atoms/button/button.component.html +0 -21
  62. package/src/lib/atoms/button/button.component.scss +0 -242
  63. package/src/lib/atoms/button/button.component.ts +0 -43
  64. package/src/lib/atoms/checkbox/checkbox.component.scss +0 -131
  65. package/src/lib/atoms/checkbox/checkbox.component.ts +0 -130
  66. package/src/lib/atoms/date-picker/date-picker.component.html +0 -295
  67. package/src/lib/atoms/date-picker/date-picker.component.scss +0 -1002
  68. package/src/lib/atoms/date-picker/date-picker.component.ts +0 -942
  69. package/src/lib/atoms/input/input.component.ts +0 -239
  70. package/src/lib/atoms/loader/loader.component.scss +0 -144
  71. package/src/lib/atoms/loader/loader.component.ts +0 -44
  72. package/src/lib/atoms/radio/radio.component.scss +0 -115
  73. package/src/lib/atoms/radio/radio.component.ts +0 -103
  74. package/src/lib/atoms/textarea/textarea.component.ts +0 -155
  75. package/src/lib/directives/asset-source.directive.ts +0 -64
  76. package/src/lib/directives/icon-source.directive.ts +0 -74
  77. package/src/lib/directives/no-leading-space.directive.ts +0 -18
  78. package/src/lib/directives/only-letters.directive.ts +0 -21
  79. package/src/lib/directives/only-number.directive.ts +0 -15
  80. package/src/lib/directives/rfc.directive.ts +0 -60
  81. package/src/lib/directives/tooltip.directive.ts +0 -211
  82. package/src/lib/molecules/copy-input/copy-input.component.html +0 -29
  83. package/src/lib/molecules/copy-input/copy-input.component.scss +0 -101
  84. package/src/lib/molecules/copy-input/copy-input.component.ts +0 -41
  85. package/src/lib/molecules/multiselect/multiselect.component.scss +0 -298
  86. package/src/lib/molecules/multiselect/multiselect.component.ts +0 -487
  87. package/src/lib/molecules/option/option.component.ts +0 -45
  88. package/src/lib/molecules/phone-input/phone-input.component.scss +0 -78
  89. package/src/lib/molecules/phone-input/phone-input.component.ts +0 -43
  90. package/src/lib/molecules/select/select.component.ts +0 -482
  91. package/src/lib/molecules/snackbar/snackbar.component.scss +0 -201
  92. package/src/lib/molecules/snackbar/snackbar.component.ts +0 -321
  93. package/src/lib/services/snackbar.service.ts +0 -103
  94. package/tsconfig.json +0 -31
@@ -0,0 +1,88 @@
1
+ import { ElementRef, OnDestroy, Renderer2, QueryList, AfterContentInit } from '@angular/core';
2
+ import { ControlValueAccessor } from '@angular/forms';
3
+ import { OptionComponent } from '../option/option.component';
4
+ import * as i0 from "@angular/core";
5
+ export declare class SelectPrefixDirective {
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<SelectPrefixDirective, never>;
7
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SelectPrefixDirective, "[prefix]", never, {}, {}, never, never, true, never>;
8
+ }
9
+ export declare class SelectSuffixDirective {
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<SelectSuffixDirective, never>;
11
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SelectSuffixDirective, "[suffix]", never, {}, {}, never, never, true, never>;
12
+ }
13
+ export interface SelectOption {
14
+ value: any;
15
+ label: string;
16
+ disabled?: boolean;
17
+ }
18
+ export declare class SelectComponent implements ControlValueAccessor, OnDestroy, AfterContentInit {
19
+ private renderer;
20
+ private document;
21
+ label: string;
22
+ id: string;
23
+ placeholder: string;
24
+ options: SelectOption[] | any[];
25
+ hasError: boolean;
26
+ errorMessage: string;
27
+ disabled: boolean;
28
+ unstyled: boolean;
29
+ displayKey: string;
30
+ valueKey: string;
31
+ customClass: string;
32
+ trigger: ElementRef;
33
+ contentOptions: QueryList<OptionComponent>;
34
+ prefixDirective: SelectPrefixDirective;
35
+ suffixDirective: SelectSuffixDirective;
36
+ get hasPrefix(): boolean;
37
+ get hasSuffix(): boolean;
38
+ value: any;
39
+ isOpen: boolean;
40
+ onChange: any;
41
+ onTouched: any;
42
+ private _usingContentOptions;
43
+ private dropdownElement;
44
+ private backdropElement;
45
+ private scrollHandler;
46
+ private resizeHandler;
47
+ constructor(renderer: Renderer2, document: Document);
48
+ ngAfterContentInit(): void;
49
+ ngOnDestroy(): void;
50
+ onEsc(): void;
51
+ handleBlur(): void;
52
+ /**
53
+ * Get all options (from content or input)
54
+ */
55
+ private getAllOptions;
56
+ /**
57
+ * Get display label from option
58
+ */
59
+ getOptionLabel(option: any): string;
60
+ /**
61
+ * Get value from option
62
+ */
63
+ getOptionValue(option: any): any;
64
+ /**
65
+ * Check if option is disabled
66
+ */
67
+ isOptionDisabled(option: any): boolean;
68
+ onDocumentClick(event: MouseEvent): void;
69
+ toggleDropdown(event: Event): void;
70
+ private openDropdown;
71
+ private calculatePosition;
72
+ private addRepositionListeners;
73
+ private updateDropdownPosition;
74
+ private createOptionElement;
75
+ private createCheckIcon;
76
+ closeDropdown(): void;
77
+ private destroyDropdown;
78
+ selectOption(option: any): void;
79
+ isSelected(value: any): boolean;
80
+ isEmptyValue(value: any): boolean;
81
+ getSelectedLabel(): string;
82
+ writeValue(value: any): void;
83
+ registerOnChange(fn: any): void;
84
+ registerOnTouched(fn: any): void;
85
+ setDisabledState(isDisabled: boolean): void;
86
+ static ɵfac: i0.ɵɵFactoryDeclaration<SelectComponent, never>;
87
+ static ɵcmp: i0.ɵɵComponentDeclaration<SelectComponent, "app-select", never, { "label": { "alias": "label"; "required": false; }; "id": { "alias": "id"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "options": { "alias": "options"; "required": false; }; "hasError": { "alias": "hasError"; "required": false; }; "errorMessage": { "alias": "errorMessage"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "unstyled": { "alias": "unstyled"; "required": false; }; "displayKey": { "alias": "displayKey"; "required": false; }; "valueKey": { "alias": "valueKey"; "required": false; }; "customClass": { "alias": "customClass"; "required": false; }; }, {}, ["prefixDirective", "suffixDirective", "contentOptions"], ["[prefix]", "[suffix]", "*"], true, never>;
88
+ }
@@ -0,0 +1,17 @@
1
+ import { OnInit, OnDestroy } from '@angular/core';
2
+ import { SnackbarService } from '../../services/snackbar.service';
3
+ import { SnackbarData } from '../../models/snackbar.models';
4
+ import * as i0 from "@angular/core";
5
+ export declare class SnackbarComponent implements OnInit, OnDestroy {
6
+ private snackbarService;
7
+ snackbars: SnackbarData[];
8
+ private subscriptions;
9
+ constructor(snackbarService: SnackbarService);
10
+ ngOnInit(): void;
11
+ ngOnDestroy(): void;
12
+ getSnackbarsByPosition(position: string): SnackbarData[];
13
+ dismiss(id: string): void;
14
+ handleAction(snackbar: SnackbarData): void;
15
+ static ɵfac: i0.ɵɵFactoryDeclaration<SnackbarComponent, never>;
16
+ static ɵcmp: i0.ɵɵComponentDeclaration<SnackbarComponent, "app-snackbar", never, {}, {}, never, never, true, never>;
17
+ }
@@ -0,0 +1,8 @@
1
+ import * as i0 from "@angular/core";
2
+ export type SidebarIconName = 'dashboard' | 'file-users' | 'card' | 'logout' | 'chevron-down' | 'settings' | 'user' | 'home';
3
+ export declare class SidebarIconComponent {
4
+ name: SidebarIconName;
5
+ size: number;
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<SidebarIconComponent, never>;
7
+ static ɵcmp: i0.ɵɵComponentDeclaration<SidebarIconComponent, "svu-sidebar-icon", never, { "name": { "alias": "name"; "required": false; }; "size": { "alias": "size"; "required": false; }; }, {}, never, never, true, never>;
8
+ }
@@ -0,0 +1,47 @@
1
+ import { EventEmitter, ElementRef, TemplateRef } from '@angular/core';
2
+ import { IsActiveMatchOptions } from '@angular/router';
3
+ import { SidebarIconName } from './sidebar-icon.component';
4
+ import * as i0 from "@angular/core";
5
+ export interface SidebarItem {
6
+ label: string;
7
+ icon?: SidebarIconName;
8
+ route?: string;
9
+ /** Subset match para que el padre se marque activo aunque la ruta hija no esté exacta. */
10
+ exact?: boolean;
11
+ children?: SidebarItem[];
12
+ }
13
+ export declare class SidebarComponent {
14
+ private hostRef;
15
+ /** Items del menú (datos-driven). Soporta children para sub-navegación. */
16
+ items: SidebarItem[];
17
+ /** Logo: si se pasa la URL se renderiza; alternativamente proyecta contenido con `[sidebarLogo]`. */
18
+ logoSrc?: string;
19
+ logoAlt: string;
20
+ /** Footer hibrido: si se pasan los inputs se usa el footer por defecto.
21
+ * Para footer custom, proyectar con `[sidebarFooter]` (gana sobre los inputs). */
22
+ userName?: string;
23
+ userEmail?: string;
24
+ /** Si no se pasa, se usa la primera letra de userName. */
25
+ userInitial?: string;
26
+ /** Mostrar/ocultar el botón de logout en el menú de cuenta. */
27
+ showLogout: boolean;
28
+ logoutLabel: string;
29
+ /** Click en un item (incluye expandibles y hojas). */
30
+ itemClick: EventEmitter<SidebarItem>;
31
+ logout: EventEmitter<void>;
32
+ logoTpl?: TemplateRef<unknown>;
33
+ footerTpl?: TemplateRef<unknown>;
34
+ expandedKeys: Set<string>;
35
+ accountMenuOpen: boolean;
36
+ readonly subsetMatch: IsActiveMatchOptions;
37
+ readonly exactMatch: IsActiveMatchOptions;
38
+ constructor(hostRef: ElementRef<HTMLElement>);
39
+ get computedInitial(): string;
40
+ isExpanded(item: SidebarItem): boolean;
41
+ onItemClick(item: SidebarItem): void;
42
+ toggleAccountMenu(): void;
43
+ onLogoutClick(): void;
44
+ onDocumentClick(event: Event): void;
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<SidebarComponent, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<SidebarComponent, "svu-sidebar", never, { "items": { "alias": "items"; "required": false; }; "logoSrc": { "alias": "logoSrc"; "required": false; }; "logoAlt": { "alias": "logoAlt"; "required": false; }; "userName": { "alias": "userName"; "required": false; }; "userEmail": { "alias": "userEmail"; "required": false; }; "userInitial": { "alias": "userInitial"; "required": false; }; "showLogout": { "alias": "showLogout"; "required": false; }; "logoutLabel": { "alias": "logoutLabel"; "required": false; }; }, { "itemClick": "itemClick"; "logout": "logout"; }, ["logoTpl", "footerTpl"], never, true, never>;
47
+ }
@@ -0,0 +1,40 @@
1
+ import { SnackbarConfig, SnackbarData, SnackbarPosition } from '../models/snackbar.models';
2
+ import * as i0 from "@angular/core";
3
+ export declare class SnackbarService {
4
+ private snackbarSubject;
5
+ snackbar$: import("rxjs").Observable<SnackbarData>;
6
+ private dismissSubject;
7
+ dismiss$: import("rxjs").Observable<string>;
8
+ private snackbarIdCounter;
9
+ constructor();
10
+ /**
11
+ * Show success snackbar
12
+ */
13
+ success(message: string, duration?: number, position?: SnackbarPosition): void;
14
+ /**
15
+ * Show error snackbar
16
+ */
17
+ error(message: string, duration?: number, position?: SnackbarPosition): void;
18
+ /**
19
+ * Show warning snackbar
20
+ */
21
+ warning(message: string, duration?: number, position?: SnackbarPosition): void;
22
+ /**
23
+ * Show info snackbar
24
+ */
25
+ info(message: string, duration?: number, position?: SnackbarPosition): void;
26
+ /**
27
+ * Show snackbar with custom configuration
28
+ */
29
+ show(config: SnackbarConfig): void;
30
+ /**
31
+ * Dismiss specific snackbar by id
32
+ */
33
+ dismiss(id: string): void;
34
+ /**
35
+ * Dismiss all snackbars
36
+ */
37
+ dismissAll(): void;
38
+ static ɵfac: i0.ɵɵFactoryDeclaration<SnackbarService, never>;
39
+ static ɵprov: i0.ɵɵInjectableDeclaration<SnackbarService>;
40
+ }
@@ -1,10 +1,6 @@
1
1
  import { InjectionToken } from '@angular/core';
2
-
3
2
  /**
4
3
  * Base URL para los assets remotos del microfrontend (íconos, imágenes).
5
4
  * El consumidor debe proveerlo, normalmente con el valor de `environment.mfAssetsUrl`.
6
5
  */
7
- export const ASSET_BASE_URL = new InjectionToken<string>('ASSET_BASE_URL', {
8
- providedIn: 'root',
9
- factory: () => ''
10
- });
6
+ export declare const ASSET_BASE_URL: InjectionToken<string>;
package/package.json CHANGED
@@ -1,40 +1,51 @@
1
1
  {
2
2
  "name": "@up_si_vale/sivale-componentes-angular",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Librería de componentes Angular standalone (atoms + molecules) para los frontends de Sivale.",
5
+ "author": "Up Sí Vale — Frontend Team",
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://dev.azure.com/UP-SiVale/SI%20VALE%20Agile/_git/biblioteca_componentes_angular_sivale"
10
+ },
11
+ "keywords": [
12
+ "angular",
13
+ "componentes",
14
+ "ui",
15
+ "design-system",
16
+ "sivale",
17
+ "standalone"
18
+ ],
5
19
  "publishConfig": {
6
- "access": "restricted"
7
- },
8
- "scripts": {
9
- "build": "ng-packagr -p ng-package.json",
10
- "build:watch": "ng-packagr -p ng-package.json --watch",
11
- "prepublishOnly": "npm run build"
20
+ "access": "public"
12
21
  },
13
22
  "peerDependencies": {
14
- "@angular/common": "^17.3.0",
15
- "@angular/core": "^17.3.0",
16
- "@angular/forms": "^17.3.0",
23
+ "@angular/common": ">=17.3.0 <22.0.0",
24
+ "@angular/core": ">=17.3.0 <22.0.0",
25
+ "@angular/forms": ">=17.3.0 <22.0.0",
26
+ "@angular/router": ">=17.3.0 <22.0.0",
17
27
  "@up_si_vale/sivale-design-styles": "^1.0.15",
18
28
  "rxjs": "^7.8.0"
19
29
  },
20
30
  "dependencies": {
21
31
  "tslib": "^2.3.0"
22
32
  },
23
- "devDependencies": {
24
- "@angular/common": "^17.3.0",
25
- "@angular/compiler": "^17.3.0",
26
- "@angular/compiler-cli": "^17.3.0",
27
- "@angular/core": "^17.3.0",
28
- "@angular/forms": "^17.3.0",
29
- "ng-packagr": "^17.3.0",
30
- "rxjs": "^7.8.0",
31
- "tslib": "^2.3.0",
32
- "typescript": "~5.4.2",
33
- "zone.js": "~0.14.3"
34
- },
35
- "sideEffects": false,
36
- "main": "index.js",
37
- "keywords": [],
38
- "author": "",
39
- "license": "ISC"
40
- }
33
+ "sideEffects": [
34
+ "./elements/**/*.ts",
35
+ "./**/*.scss",
36
+ "./**/*.css"
37
+ ],
38
+ "module": "fesm2022/up_si_vale-sivale-componentes-angular.mjs",
39
+ "typings": "index.d.ts",
40
+ "exports": {
41
+ "./package.json": {
42
+ "default": "./package.json"
43
+ },
44
+ ".": {
45
+ "types": "./index.d.ts",
46
+ "esm2022": "./esm2022/up_si_vale-sivale-componentes-angular.mjs",
47
+ "esm": "./esm2022/up_si_vale-sivale-componentes-angular.mjs",
48
+ "default": "./fesm2022/up_si_vale-sivale-componentes-angular.mjs"
49
+ }
50
+ }
51
+ }
@@ -1,17 +1,6 @@
1
- /*
2
- * Public API Surface of @up_si_vale/sivale-componentes-angular
3
- */
4
-
5
- // Tokens
6
1
  export * from './lib/tokens/asset-base-url.token';
7
-
8
- // Models
9
2
  export * from './lib/models/snackbar.models';
10
-
11
- // Services
12
3
  export * from './lib/services/snackbar.service';
13
-
14
- // Directives
15
4
  export * from './lib/directives/asset-source.directive';
16
5
  export * from './lib/directives/icon-source.directive';
17
6
  export * from './lib/directives/only-number.directive';
@@ -19,8 +8,6 @@ export * from './lib/directives/only-letters.directive';
19
8
  export * from './lib/directives/rfc.directive';
20
9
  export * from './lib/directives/no-leading-space.directive';
21
10
  export * from './lib/directives/tooltip.directive';
22
-
23
- // Atoms
24
11
  export * from './lib/atoms/button/button.component';
25
12
  export * from './lib/atoms/input/input.component';
26
13
  export * from './lib/atoms/textarea/textarea.component';
@@ -28,11 +15,12 @@ export * from './lib/atoms/checkbox/checkbox.component';
28
15
  export * from './lib/atoms/radio/radio.component';
29
16
  export * from './lib/atoms/date-picker/date-picker.component';
30
17
  export * from './lib/atoms/loader/loader.component';
31
-
32
- // Molecules
18
+ export * from './lib/organisms/sidebar/sidebar-icon.component';
19
+ export * from './lib/organisms/sidebar/sidebar.component';
33
20
  export * from './lib/molecules/option/option.component';
34
21
  export * from './lib/molecules/select/select.component';
35
22
  export * from './lib/molecules/multiselect/multiselect.component';
36
23
  export * from './lib/molecules/phone-input/phone-input.component';
37
24
  export * from './lib/molecules/copy-input/copy-input.component';
38
25
  export * from './lib/molecules/snackbar/snackbar.component';
26
+ export * from './lib/molecules/alert/alert.component';
package/ng-package.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "$schema": "./node_modules/ng-packagr/ng-package.schema.json",
3
- "dest": "./dist",
4
- "lib": {
5
- "entryFile": "src/public-api.ts",
6
- "styleIncludePaths": []
7
- },
8
- "assets": []
9
- }
@@ -1,21 +0,0 @@
1
- <button
2
- [type]="type"
3
- [class]="buttonClasses"
4
- [disabled]="disabled || loading"
5
- [id]="id"
6
- [attr.aria-label]="ariaLabel"
7
- [attr.aria-busy]="loading"
8
- (click)="handleClick($event)">
9
-
10
- <!-- Loading spinner -->
11
- <span *ngIf="loading" class="svu-btn__spinner">
12
- <svg class="svu-spinner" viewBox="0 0 24 24">
13
- <circle class="svu-spinner__circle" cx="12" cy="12" r="10" fill="none" stroke-width="3"></circle>
14
- </svg>
15
- </span>
16
-
17
- <!-- Content -->
18
- <span [class.svu-btn__content--hidden]="loading" class="svu-btn__content">
19
- <ng-content></ng-content>
20
- </span>
21
- </button>
@@ -1,242 +0,0 @@
1
- .svu-btn {
2
- position: relative;
3
- display: inline-flex;
4
- align-items: center;
5
- justify-content: center;
6
- gap: 0.5rem;
7
- font-family: 'Quicksand', sans-serif;
8
- font-weight: 600;
9
- border: none;
10
- border-radius: 8px;
11
- cursor: pointer;
12
- transition: all 0.2s ease-in-out;
13
- outline: none !important;
14
- text-decoration: none;
15
- white-space: nowrap;
16
- width: 100%;
17
-
18
- &:focus-visible {
19
- outline: 2px solid transparent;
20
- outline-offset: 2px;
21
- }
22
-
23
- // Sizes
24
- &--small {
25
- padding: 0.5rem 1rem;
26
- font-size: 0.875rem;
27
- line-height: 1.25rem;
28
- height: inherit;
29
- }
30
-
31
- &--medium {
32
- padding: 0.75rem 1.5rem;
33
- font-size: 1rem;
34
- line-height: 1.5rem;
35
- }
36
-
37
- &--large {
38
- padding: 1rem 2rem;
39
- font-size: 1.125rem;
40
- line-height: 1.75rem;
41
- }
42
-
43
- // Full width
44
- &--full-width {
45
- width: 100%;
46
- }
47
-
48
- // Primary variant
49
- &--primary {
50
- background: #364B9F;
51
- color: white;
52
-
53
- &:hover:not(:disabled):not(.btn--loading) {
54
- background: #2A3B7F;
55
- transform: translateY(-1px);
56
- box-shadow: 0 4px 12px rgba(54, 75, 159, 0.3);
57
- }
58
-
59
- &:active:not(:disabled):not(.btn--loading) {
60
- transform: translateY(0);
61
- background: #1F2D5F;
62
- }
63
-
64
- &:focus-visible {
65
- box-shadow: 0 0 0 3px rgba(54, 75, 159, 0.3);
66
- }
67
- }
68
-
69
- // Secondary variant
70
- &--secondary {
71
- background: #F3F4F6;
72
- color: #374151;
73
-
74
- &:hover:not(:disabled):not(.btn--loading) {
75
- background: #E5E7EB;
76
- transform: translateY(-1px);
77
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
78
- }
79
-
80
- &:active:not(:disabled):not(.btn--loading) {
81
- transform: translateY(0);
82
- }
83
-
84
- &:focus-visible {
85
- box-shadow: 0 0 0 3px rgba(55, 65, 81, 0.2);
86
- }
87
- }
88
-
89
- // Outline variant
90
- &--outline {
91
- background: transparent;
92
- color: #364B9F;
93
- border: 1px solid #364B9F;
94
-
95
- &:hover:not(:disabled):not(.btn--loading) {
96
- background: rgba(54, 75, 159, 0.05);
97
- border-color: #2A3B7F;
98
- color: #2A3B7F;
99
- transform: translateY(-1px);
100
- }
101
-
102
- &:active:not(:disabled):not(.btn--loading) {
103
- transform: translateY(0);
104
- background: rgba(54, 75, 159, 0.1);
105
- }
106
-
107
- &:focus-visible {
108
- box-shadow: 0 0 0 3px rgba(54, 75, 159, 0.2);
109
- }
110
- }
111
-
112
- // Ghost variant
113
- &--ghost {
114
- background: transparent;
115
- color: #364B9F;
116
-
117
- &:hover:not(:disabled):not(.btn--loading) {
118
- background: rgba(54, 75, 159, 0.1);
119
- transform: translateY(-1px);
120
- }
121
-
122
- &:active:not(:disabled):not(.btn--loading) {
123
- transform: translateY(0);
124
- background: rgba(54, 75, 159, 0.15);
125
- }
126
-
127
- &:focus-visible {
128
- box-shadow: 0 0 0 3px rgba(54, 75, 159, 0.2);
129
- }
130
- }
131
-
132
- // Danger variant
133
- &--danger {
134
- background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
135
- color: white;
136
-
137
- &:hover:not(:disabled):not(.btn--loading) {
138
- background: linear-gradient(135deg, #DC2626 0%, #B91C1C 100%);
139
- transform: translateY(-1px);
140
- box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
141
- }
142
-
143
- &:active:not(:disabled):not(.btn--loading) {
144
- transform: translateY(0);
145
- }
146
-
147
- &:focus-visible {
148
- box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.3);
149
- }
150
- }
151
-
152
- // Success variant
153
- &--success {
154
- background: linear-gradient(135deg, #10B981 0%, #059669 100%);
155
- color: white;
156
-
157
- &:hover:not(:disabled):not(.btn--loading) {
158
- background: linear-gradient(135deg, #059669 0%, #047857 100%);
159
- transform: translateY(-1px);
160
- box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
161
- }
162
-
163
- &:active:not(:disabled):not(.btn--loading) {
164
- transform: translateY(0);
165
- }
166
-
167
- &:focus-visible {
168
- box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.3);
169
- }
170
- }
171
-
172
- // Disabled state
173
- &:disabled,
174
- &--disabled {
175
- opacity: 0.5;
176
- cursor: not-allowed;
177
- transform: none !important;
178
- box-shadow: none !important;
179
- }
180
-
181
- // Loading state
182
- &--loading {
183
- cursor: wait;
184
- pointer-events: none;
185
- }
186
-
187
- &__spinner {
188
- position: absolute;
189
- left: 50%;
190
- top: 50%;
191
- transform: translate(-50%, -50%);
192
- display: flex;
193
- align-items: center;
194
- justify-content: center;
195
- }
196
-
197
- &__content {
198
- display: flex;
199
- align-items: center;
200
- gap: 0.5rem;
201
-
202
- &--hidden {
203
- visibility: hidden;
204
- }
205
- }
206
- }
207
-
208
- // Spinner animation
209
- .svu-spinner {
210
- width: 1.25rem;
211
- height: 1.25rem;
212
- animation: svu-spin 0.8s linear infinite;
213
-
214
- &__circle {
215
- stroke: currentColor;
216
- stroke-dasharray: 50;
217
- stroke-dashoffset: 25;
218
- stroke-linecap: round;
219
- animation: svu-spinner-dash 1.5s ease-in-out infinite;
220
- }
221
- }
222
-
223
- @keyframes svu-spin {
224
- to {
225
- transform: rotate(360deg);
226
- }
227
- }
228
-
229
- @keyframes svu-spinner-dash {
230
- 0% {
231
- stroke-dasharray: 1, 150;
232
- stroke-dashoffset: 0;
233
- }
234
- 50% {
235
- stroke-dasharray: 90, 150;
236
- stroke-dashoffset: -35;
237
- }
238
- 100% {
239
- stroke-dasharray: 90, 150;
240
- stroke-dashoffset: -124;
241
- }
242
- }
@@ -1,43 +0,0 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
-
4
- export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'success';
5
- export type ButtonSize = 'small' | 'medium' | 'large';
6
- export type ButtonType = 'button' | 'submit' | 'reset';
7
-
8
- @Component({
9
- selector: 'app-button',
10
- standalone: true,
11
- imports: [CommonModule],
12
- templateUrl: './button.component.html',
13
- styleUrls: ['./button.component.scss']
14
- })
15
- export class ButtonComponent {
16
- @Input() variant: ButtonVariant = 'primary';
17
- @Input() size: ButtonSize = 'medium';
18
- @Input() type: ButtonType = 'button';
19
- @Input() disabled: boolean = false;
20
- @Input() loading: boolean = false;
21
- @Input() fullWidth: boolean = false;
22
- @Input() id?: string;
23
- @Input() ariaLabel?: string;
24
-
25
- @Output() onClick = new EventEmitter<MouseEvent>();
26
-
27
- get buttonClasses(): string {
28
- return [
29
- 'svu-btn',
30
- `svu-btn--${this.variant}`,
31
- `svu-btn--${this.size}`,
32
- this.fullWidth ? 'svu-btn--full-width' : '',
33
- this.loading ? 'svu-btn--loading' : '',
34
- this.disabled ? 'svu-btn--disabled' : ''
35
- ].filter(Boolean).join(' ');
36
- }
37
-
38
- handleClick(event: MouseEvent): void {
39
- if (!this.disabled && !this.loading) {
40
- this.onClick.emit(event);
41
- }
42
- }
43
- }