tailjng 0.0.61 → 0.0.62

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.
@@ -108,7 +108,7 @@ function getComponentList() {
108
108
  },
109
109
  'form-sidebar': {
110
110
  path: "src/lib/components/form/form-sidebar",
111
- dependencies: ["tooltip", "button", "checkbox-switch"],
111
+ dependencies: ["tooltip", "button", "checkbox-switch", "coach-mark"],
112
112
  },
113
113
  'paginator-complete': {
114
114
  path: "src/lib/components/paginator/paginator-complete",
@@ -130,17 +130,21 @@ function getComponentList() {
130
130
  path: "src/lib/components/menu/menu-options-table",
131
131
  dependencies: ["button"],
132
132
  },
133
+ 'options-coach-menu': {
134
+ path: "src/lib/components/menu/options-coach-menu",
135
+ dependencies: ["button", "coach-mark"],
136
+ },
133
137
 
134
138
 
135
139
 
136
140
 
137
141
  'table-crud-complete': {
138
142
  path: "src/lib/components/table/table-crud-complete",
139
- dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "menu-options-table", "dialog", "viewer-image", "select-dropdown", "input"],
143
+ dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "options-coach-menu", "dialog", "viewer-image", "select-dropdown", "input"],
140
144
  },
141
145
  'table-complete': {
142
146
  path: "src/lib/components/table/table-complete",
143
- dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "menu-options-table", "dialog", "viewer-image", "select-dropdown", "input"],
147
+ dependencies: ["button", "paginator-complete", "filter-complete", "checkbox-input", "options-coach-menu", "dialog", "viewer-image", "select-dropdown", "input"],
144
148
  },
145
149
  'theme-generator': {
146
150
  path: "src/lib/components/theme-generator",
@@ -27,7 +27,7 @@ Authors:
27
27
  License:
28
28
  This project is licensed under the BSD 3-Clause - see the LICENSE file for more details.
29
29
 
30
- Version: 0.0.61
30
+ Version: 0.0.62
31
31
  Creation Date: 2025-01-04
32
32
  ===============================================`
33
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailjng",
3
- "version": "0.0.61",
3
+ "version": "0.0.62",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^19.2.0",
6
6
  "@angular/core": "^19.2.0",
@@ -1,101 +1,134 @@
1
1
  <section class="content_form">
2
-
3
- <!-- Overlay -->
4
- @if (openForm) {
5
- <div onKeyPress class="fixed top-0 left-0 w-full h-full bg-black/50 z-[998] transition duration-300" (click)="canCloseOverlay ? onClose() : null"></div>
6
- }
7
-
8
- <!-- Sidebar personalizado -->
9
- @if (openForm) {
10
- <div @sidebarTransition
11
- class="fixed top-0 right-0 h-full max-w-full border border-border dark:border-dark-border rounded-tl-[15px] rounded-bl-[15px] text-white shadow-lg z-[999] flex flex-col"
12
- [style]="style"
13
- [ngClass]="bgColor"
14
- [class.w-[22em]]="size==='small'"
15
- [class.w-[30em]]="size==='medium'"
16
- [class.w-[47em]]="size==='large'"
17
- [class.w-[65em]]="size==='xlarge'"
2
+ <!-- Overlay -->
3
+ @if (openForm) {
4
+ <div
5
+ onKeyPress
6
+ class="fixed top-0 left-0 w-full h-full bg-black/50 z-[999] transition duration-300"
7
+ (click)="canCloseOverlay ? onClose() : null"
8
+ ></div>
9
+ }
10
+
11
+ <!-- Sidebar personalizado -->
12
+ @if (openForm) {
13
+ <div
14
+ @sidebarTransition
15
+ class="fixed top-0 right-0 h-full max-w-full border border-border dark:border-dark-border rounded-tl-[15px] rounded-bl-[15px] text-white shadow-lg z-[999] flex flex-col"
16
+ [style]="style"
17
+ [ngClass]="bgColor"
18
+ [class.w-[22em]]="size === 'small'"
19
+ [class.w-[30em]]="size === 'medium'"
20
+ [class.w-[47em]]="size === 'large'"
21
+ [class.w-[65em]]="size === 'xlarge'"
22
+ >
23
+ <!-- Header -->
24
+ <div
25
+ class="flex p-2 pl-4 pr-4 justify-between items-center bg-primary dark:bg-dark-primary border-b border-border dark:border-dark-border rounded-tl-[15px] font-semibold text-2sm"
26
+ >
27
+ <div class="flex items-center gap-2">
28
+ <span>
29
+ {{
30
+ typeForm !== "none"
31
+ ? typeForm === "create"
32
+ ? "AGREGAR"
33
+ : "ACTUALIZAR"
34
+ : "REGISTROS"
35
+ }}
36
+ {{ typeForm !== "none" ? titleForm : "" }}
37
+ </span>
38
+
39
+ <JButton
40
+ jTooltip="Información"
41
+ jTooltipPosition="bottom"
42
+ jCoachMark
43
+ [coachContent]="coachContentChangePassword"
44
+ coachPosition="bottom"
45
+ coachTrigger="click"
46
+ [icon]="iconsService.icons.info"
47
+ classes="border-none shadow-none p-0 m-0 h-5 w-5 text-white"
48
+ />
49
+ </div>
50
+
51
+ <ng-template #coachContentChangePassword>
52
+ <div class="text-[12px] leading-[15px]">
53
+ <span>
54
+ Las etiquetas con <span class="text-[10px]">✱</span> indican
55
+ campos requeridos.
56
+ </span>
57
+ <br />
58
+ <span>
59
+ <span class="text-red-600 dark:text-red-300">✱</span>
60
+ Obligatorio
61
+ </span>
62
+ <br />
63
+ <span>
64
+ <span class="text-blue-600 dark:text-blue-300">✱</span>
65
+ Condicionado
66
+ </span>
67
+ <br />
68
+ <span>
69
+ <span class="text-purple-600 dark:text-purple-300">✱</span>
70
+ Automático
71
+ </span>
72
+ </div>
73
+ </ng-template>
74
+
75
+ <div class="flex gap-2">
76
+ @for (cb of checkboxes; track $index) {
77
+ @if (cb.isVisible) {
78
+ <JSwitchCheckbox
79
+ onKeyPress
80
+ [title]="cb.title"
81
+ [isChecked]="cb.isChecked"
82
+ [isLoading]="cb.isLoading"
83
+ (click)="cb.onClick(!cb.isChecked, $index)"
84
+ />
85
+ }
86
+ }
87
+ </div>
88
+
89
+ <button
90
+ type="button"
91
+ (click)="onClose()"
92
+ class="p-2 rounded-full border border-border dark:border-dark-border text-white hover:bg-dark-background focus:outline-none cursor-pointer"
18
93
  >
19
- <!-- Header -->
20
- <div class="flex p-2 pl-4 pr-4 justify-between items-center bg-primary dark:bg-dark-primary border-b border-border dark:border-dark-border rounded-tl-[15px] font-semibold text-2sm">
21
- <div class="flex items-center gap-2">
22
- <span>
23
- {{ typeForm !== 'none' ? typeForm === 'create' ? 'AGREGAR' : 'ACTUALIZAR' : 'REGISTROS' }} {{ typeForm !== 'none' ? titleForm : '' }}
24
- </span>
25
-
26
- <div class="cursor-pointer"
27
- [jTooltip]="tooltipContentChangePassword"
28
- [jTooltipPosition]="'bottom'"
29
- [jTooltipOffsetX]="25"
30
- [jTooltipOffsetY]="-20"
31
- >
32
- <lucide-icon [name]="iconsService.icons.info" [size]="15"></lucide-icon>
33
- </div>
34
- </div>
35
-
36
-
37
- <ng-template #tooltipContentChangePassword>
38
- <div class="text-[12px] leading-[15px]">
39
- <span>Las etiquetas con ✱ indican campos requeridos.</span> <br>
40
- <span><span class="text-red-600 dark:text-red-300">✱</span> Obligatorio</span> <br>
41
- <span><span class="text-blue-600 dark:text-blue-300">✱</span> Condicionado</span> <br>
42
- <span><span class="text-purple-600 dark:text-purple-300">✱</span> Automático</span> <br>
43
- </div>
44
- </ng-template>
45
-
46
-
47
- <div class="flex gap-2">
48
- @for (cb of checkboxes; track $index) {
49
- @if (cb.isVisible) {
50
- <JSwitchCheckbox onKeyPress
51
- [title]="cb.title"
52
- [isChecked]="cb.isChecked"
53
- [isLoading]="cb.isLoading"
54
- (click)="cb.onClick(!cb.isChecked, $index)"
55
- />
56
- }
57
- }
58
- </div>
59
-
60
- <button type="button" (click)="onClose()" class="p-2 rounded-full border border-border dark:border-dark-border text-white hover:bg-dark-background focus:outline-none cursor-pointer">
61
- <lucide-icon [name]="iconsService.icons.close" size="16"></lucide-icon>
62
- </button>
63
- </div>
64
-
65
-
66
- <!-- Content -->
67
- <div class="p-4 flex-1 overflow-x-hidden overflow-y-auto scroll-element">
68
- @if (formTemplate) {
69
- <ng-container [ngTemplateOutlet]="formTemplate"></ng-container>
70
- }
71
- </div>
72
-
73
-
74
- <!-- Footer -->
75
- @if (typeForm !== 'none') {
76
- <div class="p-4 border-t border-border dark:border-dark-border rounded-bl-[15px] flex justify-center gap-3">
77
-
78
- <JButton
79
- type="submit"
80
- (clicked)="onSubmit()"
81
- classes="primary"
82
- [icon]="iconsService.icons.save"
83
- [isLoading]="isLoading"
84
- >
85
- {{typeForm === 'create' ? 'AGREGAR' : 'ACTUALIZAR'}}
86
- </JButton>
87
-
88
- <JButton
89
- type="button"
90
- (clicked)="onClose()"
91
- classes="secondary"
92
- [icon]="iconsService.icons.error"
93
- text="CANCELAR"
94
- />
95
-
96
- </div>
94
+ <lucide-icon
95
+ [name]="iconsService.icons.close"
96
+ size="16"
97
+ ></lucide-icon>
98
+ </button>
99
+ </div>
100
+
101
+ <!-- Content -->
102
+ <div class="p-4 flex-1 overflow-x-hidden overflow-y-auto scroll-element">
103
+ @if (formTemplate) {
104
+ <ng-container [ngTemplateOutlet]="formTemplate"></ng-container>
97
105
  }
98
- </div>
99
- }
106
+ </div>
100
107
 
101
- </section>
108
+ <!-- Footer -->
109
+ @if (typeForm !== "none") {
110
+ <div
111
+ class="p-4 border-t border-border dark:border-dark-border rounded-bl-[15px] flex justify-center gap-3"
112
+ >
113
+ <JButton
114
+ type="submit"
115
+ (clicked)="onSubmit()"
116
+ classes="primary"
117
+ [icon]="iconsService.icons.save"
118
+ [isLoading]="isLoading"
119
+ >
120
+ {{ typeForm === "create" ? "AGREGAR" : "ACTUALIZAR" }}
121
+ </JButton>
122
+
123
+ <JButton
124
+ type="button"
125
+ (clicked)="onClose()"
126
+ classes="secondary"
127
+ [icon]="iconsService.icons.error"
128
+ text="CANCELAR"
129
+ />
130
+ </div>
131
+ }
132
+ </div>
133
+ }
134
+ </section>
@@ -7,11 +7,12 @@ import { DynamicCheckbox, FormType, JIconsService } from 'tailjng';
7
7
  import { JTooltipDirective } from '../../tooltip/tooltip.directive';
8
8
  import { JButtonComponent } from '../../button/button.component';
9
9
  import { JSwitchCheckboxComponent } from '../../checkbox/checkbox-switch/switch-checkbox.component';
10
+ import { JCoachMarkDirective } from '../../coach-mark/coach-mark.directive';
10
11
 
11
12
  @Component({
12
13
  selector: 'JSidebarForm',
13
14
  standalone: true,
14
- imports: [LucideAngularModule, JButtonComponent, JTooltipDirective, ReactiveFormsModule, FormsModule, CommonModule, JSwitchCheckboxComponent],
15
+ imports: [LucideAngularModule, JButtonComponent, JTooltipDirective, ReactiveFormsModule, FormsModule, CommonModule, JSwitchCheckboxComponent, JCoachMarkDirective],
15
16
  templateUrl: './sidebar-form.component.html',
16
17
  styleUrl: './sidebar-form.component.scss',
17
18
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
@@ -61,4 +62,4 @@ export class JSidebarFormComponent {
61
62
  this.onClose();
62
63
  }
63
64
  }
64
- }
65
+ }
@@ -0,0 +1,35 @@
1
+ @media (max-width: 400px) {
2
+ .input-container {
3
+ width: 100%;
4
+ }
5
+
6
+ input[type="date"] {
7
+ appearance: none !important;
8
+ -webkit-appearance: none !important;
9
+ }
10
+
11
+ input[type="date"]::-webkit-calendar-picker-indicator {
12
+ opacity: 0 !important;
13
+ display: none !important;
14
+ -webkit-appearance: none !important;
15
+ }
16
+
17
+ input[type="date"]:not(:valid) {
18
+ color: transparent !important;
19
+ }
20
+
21
+ input[type="date"]:not(:valid)::before {
22
+ content: attr(placeholder) !important;
23
+ color: rgb(148 163 184) !important;
24
+ }
25
+ }
26
+
27
+ .date-fake-placeholder {
28
+ display: none;
29
+ }
30
+
31
+ @media (pointer: coarse) {
32
+ .date-fake-placeholder {
33
+ display: block;
34
+ }
35
+ }
@@ -1,29 +1,39 @@
1
1
  <div class="relative w-full">
2
- <input
3
- [type]="type"
4
- [id]="id"
5
- [name]="name ?? ''"
6
- [placeholder]="placeholder"
7
- [value]="value"
8
- (input)="onInput($event)"
9
- [required]="required"
10
- [disabled]="isDisabled"
11
- (blur)="onTouched()"
12
- [ngClass]="combinedNgClass"
13
- [class]="classes"
14
- class="input w-full h-[40px] max-[400px]:h-[35px] text-[12px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white placeholder:text-muted-foreground/70 dark:placeholder:text-dark-muted-foreground/70 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-dark-primary transition duration-200 resize-y disabled:opacity-60 disabled:cursor-not-allowed"
15
- />
2
+ @if (type === 'date' && !value && placeholder) {
3
+ <span
4
+ class="date-fake-placeholder pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[12px] text-muted-foreground/70 dark:text-dark-muted-foreground/70 z-[1]"
5
+ >
6
+ {{ placeholder }}
7
+ </span>
8
+ }
16
9
 
17
- @if (value && clearButton) {
18
- <button type="button"
19
- class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 text-gray-400 hover:text-gray-500 pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
20
- (click)="clearInput()"
21
- [disabled]="isDisabled"
22
- [ngClass]="{
23
- 'cursor-not-allowed opacity-50': isDisabled
24
- }"
25
- >
26
- <lucide-icon [name]="iconsService.icons.close" class="w-4 h-4" />
27
- </button>
28
- }
29
- </div>
10
+ <input
11
+ [type]="type"
12
+ [id]="id"
13
+ [name]="name ?? ''"
14
+ [placeholder]="placeholder"
15
+ [value]="value"
16
+ (input)="onInput($event)"
17
+ [required]="required"
18
+ [disabled]="isDisabled"
19
+ [readonly]="isReadonly"
20
+ (blur)="onTouched()"
21
+ [ngClass]="combinedNgClass"
22
+ [class]="classes"
23
+ class="input w-full h-[40px] max-[400px]:h-[35px] text-[12px] bg-background dark:bg-dark-background border border-border dark:border-dark-border text-black dark:text-white placeholder:text-muted-foreground/70 dark:placeholder:text-dark-muted-foreground/70 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-dark-primary transition duration-200 resize-y disabled:opacity-60 disabled:cursor-not-allowed"
24
+ />
25
+
26
+ @if (value && clearButton) {
27
+ <button
28
+ type="button"
29
+ class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 text-gray-400 hover:text-gray-500 pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
30
+ (click)="clearInput()"
31
+ [disabled]="isDisabled"
32
+ [ngClass]="{
33
+ 'cursor-not-allowed opacity-50': isDisabled,
34
+ }"
35
+ >
36
+ <lucide-icon [name]="iconsService.icons.close" class="w-4 h-4" />
37
+ </button>
38
+ }
39
+ </div>
@@ -26,6 +26,7 @@ export class JInputComponent implements ControlValueAccessor {
26
26
  @Input() placeholder: string = '';
27
27
 
28
28
  @Input() isDisabled: boolean = false;
29
+ @Input() isReadonly: boolean = false;
29
30
  @Input() required: boolean = false;
30
31
  @Input() clearButton: boolean = false;
31
32
 
@@ -0,0 +1,53 @@
1
+ <div class="relative isolate">
2
+ <JButton
3
+ onKeyPress
4
+ jCoachMark
5
+ [contentTemplate]="customTemplateActions"
6
+ [isDescriptionFormatted]="true"
7
+ coachPosition="bottom-left"
8
+ coachTrigger="click"
9
+ [coachMaxWidth]="'170px'"
10
+ [coachSpotlight]="false"
11
+ [icon]="iconsService.icons.ellipsisVertical"
12
+ [iconSize]="20"
13
+ classes="secondary w-[35px] h-[35px] rounded-full"
14
+ (clicked)="handleClickGeneral()"
15
+ />
16
+
17
+ <ng-template #customTemplateActions>
18
+ <div class="flex flex-col gap-2">
19
+ @if (optionsTable.length > 0) {
20
+ @for (option of optionsTable; track $index) {
21
+ @if (getIsVisible(option, group)) {
22
+ <div
23
+ class="w-full hover:bg-primary/10 dark:hover:bg-dark-primary/10 text-[10px]"
24
+ >
25
+ <JButton
26
+ onKeyPress
27
+ [icon]="getIcon(option.icon, group)"
28
+ [iconSize]="20"
29
+ (clicked)="handleClick(option, group)"
30
+ [tooltip]="getTooltip(option.tooltip ?? '', group)"
31
+ [tooltipPosition]="option.tooltipPosition ?? 'top'"
32
+ [disabled]="getDisabled(option, group)"
33
+ [isLoading]="false"
34
+ [classes]="
35
+ 'w-full text-left justify-start ' + (option.classes ?? '')
36
+ "
37
+ [ngClasses]="mergeNgClasses(option.ngClass, group)"
38
+ >
39
+ {{ getTooltip(option.text ?? "", group) }}
40
+ </JButton>
41
+ </div>
42
+ }
43
+ }
44
+ } @else {
45
+ <div
46
+ class="text-center text-gray-500 dark:text-dark-text-secondary text-xs"
47
+ >
48
+ No hay opciones disponibles
49
+ </div>
50
+ }
51
+ </div>
52
+ </ng-template>
53
+ </div>
@@ -0,0 +1,41 @@
1
+ import { Component, Input, Output, EventEmitter, ElementRef, OnDestroy, ViewChild, AfterViewInit, Renderer2 } from '@angular/core';
2
+ import { LucideAngularModule } from 'lucide-angular';
3
+ import { JButtonComponent } from '../../button/button.component';
4
+ import { JIconsService } from 'tailjng';
5
+ import { JCoachMarkDirective } from '../../coach-mark/coach-mark.directive';
6
+
7
+ @Component({
8
+ selector: 'JOptionsCoachMenu',
9
+ imports: [LucideAngularModule, JButtonComponent, JCoachMarkDirective],
10
+ templateUrl: './options-coach-menu.component.html',
11
+ styleUrl: './options-coach-menu.component.scss'
12
+ })
13
+ export class JOptionsCoachMenuComponent {
14
+
15
+ @Input() optionsTable: any[] = [];
16
+ @Input() group: any;
17
+ @Input() rowId: string | number | null = null;
18
+
19
+ @Input() getIcon: (icon: any, group: any) => any = () => null;
20
+ @Input() getTooltip: (tooltip: string, group: any) => string = () => '';
21
+ @Input() getDisabled: (option: any, group: any) => boolean = () => false;
22
+ @Input() getIsVisible: (option: any, group: any) => boolean = () => true;
23
+ @Input() mergeNgClasses: (ngClass: any, group: any) => any = () => '';
24
+ @Input() isAditionalButtonLoading: (type: string, id: any) => boolean = () => false;
25
+
26
+ @Output() clicked = new EventEmitter<{ option: any; group: any }>();
27
+
28
+
29
+ constructor(
30
+ public readonly iconsService: JIconsService,
31
+ ) { }
32
+
33
+ handleClick(option: any, group: any): void {
34
+ this.clicked.emit({ option, group });
35
+ this.handleClickGeneral();
36
+ }
37
+
38
+ handleClickGeneral(): void {
39
+ document.body.click();
40
+ }
41
+ }
@@ -493,7 +493,7 @@
493
493
  >
494
494
  <div class="flex justify-center items-center">
495
495
  @if (optionsType === "dropdown") {
496
- <JOptionsTableMenu
496
+ <JOptionsCoachMenu
497
497
  [optionsTable]="optionsTable"
498
498
  [group]="item"
499
499
  [rowId]="'group_' + item.id || 'group_' + $index"
@@ -800,7 +800,7 @@
800
800
  class="relative overflow-visible flex justify-center items-center space-x-2 min-w-[50px] px-4 py-2 h-[50px]"
801
801
  >
802
802
  @if (optionsType === "dropdown") {
803
- <JOptionsTableMenu
803
+ <JOptionsCoachMenu
804
804
  [optionsTable]="optionsTable"
805
805
  [group]="group"
806
806
  [rowId]="
@@ -13,16 +13,16 @@ import { JCompletePaginatorComponent } from '../../paginator/paginator-complete/
13
13
  import { JCompleteFilterComponent } from '../../filter/filter-complete/complete-filter.component';
14
14
  import { JButtonComponent } from '../../button/button.component';
15
15
  import { JInputCheckboxComponent } from '../../checkbox/checkbox-input/input-checkbox.component';
16
- import { JOptionsTableMenuComponent } from '../../menu/menu-options-table/options-table-menu.component';
17
16
  import { JDialogComponent } from '../../dialog/dialog.component';
18
17
  import { JDropdownSelectComponent } from '../../select/select-dropdown/dropdown-select.component';
19
18
  import { JInputComponent } from '../../input/input/input.component';
20
19
  import { JImageViewerComponent } from '../../viewer/viewer-image/image-viewer.component';
20
+ import { JOptionsCoachMenuComponent } from '../../menu/options-coach-menu/options-coach-menu.component';
21
21
 
22
22
  @Component({
23
23
  selector: 'JCompleteCrudTable',
24
24
  standalone: true,
25
- imports: [CommonModule, FormsModule, JCompletePaginatorComponent, JCompleteFilterComponent, LucideAngularModule, JButtonComponent, JInputCheckboxComponent, JOptionsTableMenuComponent, JDialogComponent, JImageViewerComponent, JDropdownSelectComponent, JInputComponent],
25
+ imports: [CommonModule, FormsModule, JCompletePaginatorComponent, JCompleteFilterComponent, LucideAngularModule, JButtonComponent, JInputCheckboxComponent, JDialogComponent, JImageViewerComponent, JDropdownSelectComponent, JInputComponent, JOptionsCoachMenuComponent],
26
26
  templateUrl: './complete-crud-table.component.html',
27
27
  styleUrl: './complete-crud-table.component.scss',
28
28
  animations: [