fx-form-builder-wrapper 0.0.11

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 (34) hide show
  1. package/README.md +24 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +16 -0
  4. package/src/lib/components/button/button.component.css +0 -0
  5. package/src/lib/components/button/button.component.html +1 -0
  6. package/src/lib/components/button/button.component.ts +24 -0
  7. package/src/lib/components/dynamic-table/dynamic-table.component.css +0 -0
  8. package/src/lib/components/dynamic-table/dynamic-table.component.html +69 -0
  9. package/src/lib/components/dynamic-table/dynamic-table.component.ts +201 -0
  10. package/src/lib/components/fx-form-component/fx-form-component.component.ts +64 -0
  11. package/src/lib/components/toggle/toggle.component.css +51 -0
  12. package/src/lib/components/toggle/toggle.component.html +12 -0
  13. package/src/lib/components/toggle/toggle.component.ts +33 -0
  14. package/src/lib/components/toggle-button/toggle-button.component.css +22 -0
  15. package/src/lib/components/toggle-button/toggle-button.component.html +10 -0
  16. package/src/lib/components/toggle-button/toggle-button.component.ts +40 -0
  17. package/src/lib/components/uploader/uploader.component.css +49 -0
  18. package/src/lib/components/uploader/uploader.component.html +23 -0
  19. package/src/lib/components/uploader/uploader.component.ts +59 -0
  20. package/src/lib/custom-controls/dispatch-to-clinic/dispatch-to-clinic.component.html +78 -0
  21. package/src/lib/custom-controls/dispatch-to-clinic/dispatch-to-clinic.component.ts +44 -0
  22. package/src/lib/fx-builder-wrapper.component.ts +64 -0
  23. package/src/lib/fx-builder-wrapper.service.ts +34 -0
  24. package/src/lib/panel/configuration-panel/configuration-panel.component.css +65 -0
  25. package/src/lib/panel/configuration-panel/configuration-panel.component.html +96 -0
  26. package/src/lib/panel/configuration-panel/configuration-panel.component.ts +90 -0
  27. package/src/lib/panel/settings-panel/settings-panel.component.css +30 -0
  28. package/src/lib/panel/settings-panel/settings-panel.component.html +28 -0
  29. package/src/lib/panel/settings-panel/settings-panel.component.ts +23 -0
  30. package/src/public-api.ts +7 -0
  31. package/src/styles/styles.css +22 -0
  32. package/tsconfig.lib.json +15 -0
  33. package/tsconfig.lib.prod.json +11 -0
  34. package/tsconfig.spec.json +15 -0
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # FxBuilderWrapper
2
+
3
+ This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.2.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Run `ng generate component component-name --project fx-builder-wrapper` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project fx-builder-wrapper`.
8
+ > Note: Don't forget to add `--project fx-builder-wrapper` or else it will be added to the default project in your `angular.json` file.
9
+
10
+ ## Build
11
+
12
+ Run `ng build fx-builder-wrapper` to build the project. The build artifacts will be stored in the `dist/` directory.
13
+
14
+ ## Publishing
15
+
16
+ After building your library with `ng build fx-builder-wrapper`, go to the dist folder `cd dist/fx-builder-wrapper` and run `npm publish`.
17
+
18
+ ## Running unit tests
19
+
20
+ Run `ng test fx-builder-wrapper` to execute the unit tests via [Karma](https://karma-runner.github.io).
21
+
22
+ ## Further help
23
+
24
+ To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/fx-builder-wrapper",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ }
7
+ }
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "fx-form-builder-wrapper",
3
+ "version": "0.0.11",
4
+ "peerDependencies": {
5
+ "@angular/common": "^18.2.0",
6
+ "@angular/core": "^18.2.0",
7
+ "@instantsys-labs/fx": "2.0.2",
8
+ "uuid": "^11.0.5",
9
+ "primeng": "^18.0.2",
10
+ "tailwindcss-primeui": "^0.4.0"
11
+ },
12
+ "dependencies": {
13
+ "tslib": "^2.3.0"
14
+ },
15
+ "sideEffects": false
16
+ }
File without changes
@@ -0,0 +1 @@
1
+ <p>button works!</p>
@@ -0,0 +1,24 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { ChangeDetectorRef, Component } from '@angular/core';
3
+ import { FxBaseComponent, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
4
+
5
+ @Component({
6
+ selector: 'lib-button',
7
+ standalone: true,
8
+ imports: [CommonModule],
9
+ templateUrl: './button.component.html',
10
+ styleUrl: './button.component.css'
11
+ })
12
+ export class ButtonComponent extends FxBaseComponent {
13
+ constructor(private cdr: ChangeDetectorRef) {
14
+ super(cdr)
15
+ }
16
+
17
+ protected settings(): FxSetting[] {
18
+ return [new FxStringSetting({ key: 'heading-text', $title: 'Heading Text', value: 'My Default Value' })];
19
+ }
20
+
21
+ protected validations(): FxValidation[] {
22
+ return [FxValidatorService.required];
23
+ }
24
+ }
@@ -0,0 +1,69 @@
1
+ <fx-settings-panel [fxData]="fxData" (configuration)="onChangeConfiguration($event)">
2
+ <div style="padding: 0 1.5rem;" *ngIf="fxData">
3
+ <table style="width: 100%;">
4
+ <thead>
5
+ <tr>
6
+ <th *ngFor="let column of tableConfig.columns">{{ column.header }}</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <tr *ngFor="let row of tableConfig.rows; let rowIndex = index">
11
+ <td style="text-align: center;" *ngFor="let column of tableConfig.columns">
12
+ <ng-container [ngSwitch]="column.cellType">
13
+ <span [class]="column?.className" *ngSwitchCase="'text'">{{row[column.header]}}</span>
14
+
15
+ <input [class]="column?.className" *ngSwitchCase="'input-text'"
16
+ [(ngModel)]="row[column.header]" />
17
+
18
+ <input [class]="column?.className" *ngSwitchCase="'input-number'" type="number"
19
+ [(ngModel)]="row[column.header]" />
20
+
21
+ <select [class]="column?.className" *ngSwitchCase="'dropdown'"
22
+ [(ngModel)]="row[column.header]">
23
+ <option *ngFor="let option of column?.options" [value]="option?.optionValue">
24
+ {{ option?.optionName }}
25
+ </option>
26
+ </select>
27
+
28
+ <select [class]="column?.className" style="width: 60%;" *ngSwitchCase="'smart-dropdown'"
29
+ [(ngModel)]="row[column.header]">
30
+ <option *ngFor="let option of smartDropdownOptions[column.header]" [value]="option?.value">
31
+ {{option?.name }}
32
+ </option>
33
+ </select>
34
+
35
+ <input [class]="column?.className" *ngSwitchCase="'checkbox'" type="checkbox"
36
+ [(ngModel)]="row[column.header]" />
37
+
38
+ <input name="radio-{{rowIndex}}" [class]="column?.className" *ngSwitchCase="'radio'" type="radio"
39
+ [(ngModel)]="row[column.header]" />
40
+
41
+ <div [class]="column?.className" style="display: flex; justify-content: center; gap: 10px;"
42
+ *ngSwitchCase="'radio-group'">
43
+ <label *ngFor="let option of column.options">
44
+ <input name="radio-group-{{rowIndex}}" type="radio" [value]="option?.optionName"
45
+ [(ngModel)]="row[column.header]" />
46
+ {{ option?.optionName }}
47
+ </label>
48
+ </div>
49
+
50
+ <ng-container *ngSwitchCase="'file-upload'">
51
+ <div style="display: flex; flex-direction: column; align-items: center;">
52
+ <img width="100" *ngIf="uploadedImages[rowIndex]" [src]="uploadedImages[rowIndex]"
53
+ alt="Uploaded Image" (click)="deleteFile(uploadedImages[rowIndex], rowIndex)"/>
54
+ <input [class]="column?.className" type="file" name="file" #uploadFile [(ngModel)]="row[column.header]" hidden multiple
55
+ (change)="uploadImage($event, rowIndex)" />
56
+ <button (click)="uploadFile.click()">Upload</button>
57
+ </div>
58
+ </ng-container>
59
+
60
+ <ng-container *ngSwitchCase="'textarea'">
61
+ <textarea [class]="column?.className" name="" id="" cols="30" rows="2"></textarea>
62
+ </ng-container>
63
+ </ng-container>
64
+ </td>
65
+ </tr>
66
+ </tbody>
67
+ </table>
68
+ </div>
69
+ </fx-settings-panel>
@@ -0,0 +1,201 @@
1
+ import { AfterViewInit, ChangeDetectorRef, Component, inject, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
4
+ import { HttpClient } from '@angular/common/http';
5
+ import { FxBaseComponent, FxMode, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
6
+ import { SettingsPanelComponent } from '../../panel/settings-panel/settings-panel.component';
7
+ import { FxBuilderWrapperService } from '../../fx-builder-wrapper.service';
8
+ import {Subject, takeUntil } from 'rxjs';
9
+
10
+ export interface TableColumnConfig {
11
+ header: string;
12
+ cellType: 'text' | 'input-text' | 'input-number' | 'dropdown' | 'smart-dropdown' | 'checkbox' | 'radio' | 'radio-group' | 'file-upload' | 'textarea';
13
+ placeholder?: string;
14
+ options?: string[];
15
+ apiUrl?: string;
16
+ valueKey?: string;
17
+ labelKey?: string;
18
+ className?: string;
19
+ }
20
+ export interface TableConfig {
21
+ columns: TableColumnConfig[];
22
+ rows: any[];
23
+ }
24
+ @Component({
25
+ selector: 'fx-dynamic-table',
26
+ standalone: true,
27
+ imports: [CommonModule, FormsModule, SettingsPanelComponent, ReactiveFormsModule],
28
+ templateUrl: './dynamic-table.component.html',
29
+ styleUrl: './dynamic-table.component.css',
30
+ })
31
+
32
+ export class DynamicTableComponent extends FxBaseComponent implements OnInit, AfterViewInit, OnDestroy {
33
+ @Input() tableRows: Array<any> = [];
34
+ @Input() previewType: FxMode = FxMode.VIEW;
35
+ @Input() tableConfig: any = {
36
+ columns: [
37
+ { header: 'Column 1', cellType: 'text' },
38
+ { header: 'Column 2', cellType: 'text' },
39
+ { header: 'Column 3', cellType: 'text' },
40
+ { header: 'Column 4', cellType: 'text' },
41
+ { header: 'Column 5', cellType: 'text' },
42
+ ],
43
+ };
44
+
45
+ private destroy$ = new Subject<Boolean>();
46
+ public uploadedImages: Array<string | null> = [];
47
+ public tableFormControl = new FormControl();
48
+ public smartDropdownOptions: { [key: string]: Array<{ name: string, value: string }> } = {};
49
+ private http = inject(HttpClient);
50
+ constructor(private cdr: ChangeDetectorRef, private fxBuilderWrapperService: FxBuilderWrapperService) {
51
+ super(cdr);
52
+ this.onInit.subscribe((fxData)=>{
53
+ this._register(this.tableFormControl);
54
+ })
55
+ }
56
+
57
+ public ngOnInit(): void {
58
+ this.fxBuilderWrapperService.variables$.pipe(
59
+ takeUntil(this.destroy$)).subscribe((variables: any) => {
60
+ if(variables) {
61
+ let dynamicTableValues: any;
62
+ for(const [key, value] of Object.entries(variables)) {
63
+ if(key.includes('dynamic-table')) {
64
+ dynamicTableValues = value;
65
+ }
66
+ }
67
+ if(Object.keys(dynamicTableValues).length) {
68
+ const fileHeaderName = dynamicTableValues?.columns.find((f: any) => f.cellType === 'file-upload')?.header;
69
+ dynamicTableValues?.rows?.forEach((item: any, index: number) => {
70
+ this.uploadedImages[index] = item[fileHeaderName] ? item[fileHeaderName]: null;
71
+ })
72
+ this.tableConfig = dynamicTableValues;
73
+ this.fxData.value = this.tableConfig;
74
+ this.tableFormControl.reset();
75
+ this.tableFormControl.setValue(this.tableConfig);
76
+ }
77
+ }
78
+ })
79
+ }
80
+
81
+ public ngAfterViewInit(): void {
82
+ setTimeout(() => {
83
+ if(this.fxData?.value && Object.keys(this.fxData?.value)?.length != 0) {
84
+ this.tableConfig = this.fxData.value;
85
+ this.fetchSmartDropdownData();
86
+ }
87
+ }, 100)
88
+ }
89
+
90
+ protected fetchSmartDropdownData(): void {
91
+ this.tableConfig.columns
92
+ .filter((column: TableColumnConfig) => column.cellType === 'smart-dropdown' && column?.apiUrl)
93
+ .forEach((column: TableColumnConfig) => {
94
+ this.http.get<any>(column.apiUrl!).subscribe((response: any) => {
95
+ this.smartDropdownOptions[column.header] = response.map((item: any) => ({
96
+ value: item[column.valueKey!],
97
+ name: item[column.labelKey!],
98
+ }));
99
+ });
100
+ });
101
+ }
102
+
103
+ public uploadImage(event: Event, rowIndex: number): void {
104
+ const file = (event.target as HTMLInputElement).files?.[0];
105
+ if (file) {
106
+ const reader = new FileReader();
107
+ reader.onload = () => {
108
+ this.uploadedImages[rowIndex] = reader.result as string;
109
+ };
110
+ reader.readAsDataURL(file);
111
+ }
112
+ }
113
+
114
+ protected settings(): FxSetting[] {
115
+ return [
116
+ new FxStringSetting({ key: 'column-size', $title: 'No. of columns', value: 1 }),
117
+ new FxStringSetting({ key: 'table-config', $title: 'Table Configuration', value: {} }),
118
+ ];
119
+ }
120
+
121
+ protected validations(): FxValidation[] {
122
+ return [FxValidatorService.required];
123
+ }
124
+
125
+ public getArray(count: number): number[] {
126
+ return Array.from({ length: count });
127
+ }
128
+
129
+ public onChangeConfiguration(event: any): void {
130
+ const columns = event.columns.map((col: any) => {
131
+ return {
132
+ header: col?.header,
133
+ cellType: col?.cellType,
134
+ placeholder: col?.placeholder,
135
+ options: col?.options,
136
+ apiUrl: col?.apiUrl,
137
+ valueKey: col?.valueKey,
138
+ labelKey: col?.labelKey,
139
+ className: col?.className,
140
+ apiKey: col?.apiKey
141
+ }
142
+ });
143
+ if(!event?.enableAPI) {
144
+ this.tableConfig.columns = columns;
145
+ this.tableConfig.rows = Array.from({ length: +event?.rows }, (e, index) => ({ name: `SKU-${index + 1}`, age: index % 2 !== 0, gender: 'male' }))
146
+ this.fetchSmartDropdownData();
147
+ }
148
+ if(event?.enableAPI) {
149
+ this.drawTable(event, columns)
150
+ this.tableConfig = {
151
+ columns: columns,
152
+ rows: []
153
+ };
154
+ }
155
+
156
+ this.fxData.value = this.tableConfig;
157
+ this.tableFormControl.reset();
158
+ this.tableFormControl.setValue(this.tableConfig);
159
+ }
160
+
161
+ private updateSettings(): void{
162
+ if(this.fxData.settings){
163
+ for(let setting of this.fxData.settings){
164
+ if(setting.key === 'table-config'){
165
+ setting.value = this.tableConfig;
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ public drawTable(event: any, columns: any): void {
172
+ let rows;
173
+ this.http.get(event.api).subscribe((res: any) => {
174
+ if(res) {
175
+ rows = res.map((item: any) => {
176
+ const newObj: Record<string, any> = {};
177
+ columns.forEach((col: any) => {
178
+ newObj[col.header] = item[col.apiKey];
179
+ });
180
+ return newObj;
181
+ });
182
+ this.tableConfig = {
183
+ columns,
184
+ rows
185
+ }
186
+ this.fxData.value = this.tableConfig;
187
+ this.tableFormControl.reset();
188
+ this.tableFormControl.setValue(this.tableConfig);
189
+ }
190
+ })
191
+ }
192
+
193
+ public deleteFile(file: any, index: number): void {
194
+ this.uploadedImages.splice(index, 1, null);
195
+ }
196
+
197
+ public ngOnDestroy(): void {
198
+ this.destroy$.next(true);
199
+ this.destroy$.complete();
200
+ }
201
+ }
@@ -0,0 +1,64 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
3
+ import { FxForm, FxFormComponent } from '@instantsys-labs/fx';
4
+ import { DispatchToClinicComponent } from '../../custom-controls/dispatch-to-clinic/dispatch-to-clinic.component';
5
+ import { FxBuilderWrapperService } from '../../fx-builder-wrapper.service';
6
+ import { DynamicTableComponent } from '../dynamic-table/dynamic-table.component';
7
+ import { ToggleButtonComponent } from '../toggle-button/toggle-button.component';
8
+ import { UploaderComponent } from '../uploader/uploader.component';
9
+ import { ToggleComponent } from '../toggle/toggle.component';
10
+
11
+ @Component({
12
+ selector: 'fx-form-component',
13
+ standalone: true,
14
+ imports: [CommonModule, FxFormComponent],
15
+ template: `
16
+ <fx-form
17
+ [fxForm]="fxForm"
18
+ [value]="variables"
19
+ (onSubmit)="onSubmit($event)"
20
+ #form
21
+ >
22
+ </fx-form>
23
+ `,
24
+ })
25
+ export class FxFormWrapperComponent implements OnChanges, OnInit {
26
+ @ViewChild('form') form!: FxFormComponent;
27
+ @Input() fxForm!: FxForm;
28
+ @Input() variables: any;
29
+ @Output() fxFormSubmit = new EventEmitter<any>();
30
+
31
+ constructor(private fxWrapperService: FxBuilderWrapperService) { }
32
+
33
+ public ngOnChanges(changes: SimpleChanges): void {
34
+ if('variables' in changes && !changes['fxForm']) {
35
+ this.fxWrapperService.variables$.next(this.variables);
36
+ }
37
+ }
38
+
39
+ public ngOnInit(): void {
40
+ if (!Boolean(this.fxWrapperService.getComponent('dispatch-to-clinic'))) {
41
+ this.fxWrapperService.registerCustomComponent('Dispatch To Clinic', 'dispatch-to-clinic', DispatchToClinicComponent);
42
+ }
43
+ if (!Boolean(this.fxWrapperService.getComponent('dynamic-table'))) {
44
+ this.fxWrapperService.registerCustomComponent('Dynamic Table', 'dynamic-table', DynamicTableComponent);
45
+ }
46
+ if (!Boolean(this.fxWrapperService.getComponent('toggle-button'))) {
47
+ this.fxWrapperService.registerCustomComponent('Toggle Button', 'toggle-button', ToggleButtonComponent);
48
+ }
49
+ if (!Boolean(this.fxWrapperService.getComponent('uploader'))) {
50
+ this.fxWrapperService.registerCustomComponent('Uploader', 'uploader', UploaderComponent);
51
+ }
52
+ if (!Boolean(this.fxWrapperService.getComponent('toggle'))) {
53
+ this.fxWrapperService.registerCustomComponent('Toggle', 'toggle', ToggleComponent);
54
+ }
55
+ }
56
+
57
+ public onSubmit(event: any): void {
58
+ this.fxFormSubmit.emit(event);
59
+ }
60
+
61
+ public submit(): void {
62
+ this.form.submit();
63
+ }
64
+ }
@@ -0,0 +1,51 @@
1
+ label {
2
+ position: relative;
3
+ white-space: nowrap;
4
+ border-radius: 0;
5
+ border: 0 solid #999999;
6
+ margin: 0 14px 0 0;
7
+ width: 120px;
8
+ height: auto;
9
+ padding: 0;
10
+ text-align: center;
11
+ cursor: pointer;
12
+ }
13
+
14
+ .form-radio {
15
+ background-color: #DAE6F0;
16
+ color: white;
17
+ box-shadow: none;
18
+ transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
19
+ border: 1px solid #DEDEDE;
20
+ padding: 9px 10px;
21
+ margin: 0;
22
+ white-space: nowrap;
23
+ width: 100%;
24
+ height: 38px;
25
+ background-image: none;
26
+ border-radius: 4px;
27
+ }
28
+
29
+ .form-radio:checked {
30
+ background-color: #ADD8E6;
31
+ border-color: #9BBBD6;
32
+ }
33
+
34
+ .form-radio:focus {
35
+ box-shadow: 0 0 0 2px #fff, 0 0 0 4px #9dc1fb, 0 1px 2px 0 black;
36
+ background-color: #ADD8E6;
37
+ }
38
+
39
+ .form-radio:hover {
40
+ border-color: #4682B4;
41
+ }
42
+
43
+ span {
44
+ position: absolute;
45
+ left: 0;
46
+ right: 0;
47
+ top: 8px;
48
+ bottom: 0;
49
+ margin: 0;
50
+ padding: 0;
51
+ }
@@ -0,0 +1,12 @@
1
+ <fx-component [fxData]="fxData">
2
+ <div style="display: flex;">
3
+ <label>
4
+ <input [formControl]="toggleControl" type="radio" name="radio_grp" class="form-radio mr-3" value="true">
5
+ <span class="mt-1">{{setting('accept')}}</span>
6
+ </label>
7
+ <label>
8
+ <input [formControl]="toggleControl" type="radio" name="radio_grp" class="form-radio mr-3" value="false">
9
+ <span class="mt-1">{{setting('reject')}}</span>
10
+ </label>
11
+ </div>
12
+ </fx-component>
@@ -0,0 +1,33 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { ChangeDetectorRef, Component, inject } from '@angular/core';
3
+ import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
4
+ import { FxBaseComponent, FxComponent, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
5
+
6
+ @Component({
7
+ selector: 'fx-toggle',
8
+ standalone: true,
9
+ imports: [CommonModule, FxComponent, FormsModule, ReactiveFormsModule],
10
+ templateUrl: './toggle.component.html',
11
+ styleUrl: './toggle.component.css'
12
+ })
13
+ export class ToggleComponent extends FxBaseComponent {
14
+ public toggleControl = new FormControl<boolean>(false)
15
+
16
+ constructor(private cdr: ChangeDetectorRef) {
17
+ super(cdr)
18
+ this.onInit.subscribe((fxData)=>{
19
+ this._register(this.toggleControl);
20
+ })
21
+ }
22
+
23
+ protected settings(): FxSetting[] {
24
+ return [
25
+ new FxStringSetting({ key: 'accept', $title: 'Accept Text', value: 'Yes' }),
26
+ new FxStringSetting({ key: 'reject', $title: 'Reject Text', value: 'No' })
27
+ ];
28
+ }
29
+
30
+ protected validations(): FxValidation[] {
31
+ return [FxValidatorService.required];
32
+ }
33
+ }
@@ -0,0 +1,22 @@
1
+ .custom-toggle-btn {
2
+ padding: 10px 20px;
3
+ font-size: 16px;
4
+ font-weight: bold;
5
+ color: white;
6
+ border: none;
7
+ border-radius: 5px;
8
+ cursor: pointer;
9
+ background-color: #ccc;
10
+ transition: background-color 0.3s;
11
+ }
12
+
13
+ .custom-toggle-btn.active {
14
+ background-color: #4caf50;
15
+ }
16
+
17
+ .custom-toggle-btn:hover {
18
+ opacity: 0.9;
19
+ }
20
+
21
+
22
+
@@ -0,0 +1,10 @@
1
+ <fx-component [fxData]="fxData">
2
+ <button
3
+ class="custom-toggle-btn"
4
+ [class]="setting('classes') ? setting('classes'): ''"
5
+ [class.active]="toggleBtnControl.value"
6
+ (click)="toggle()"
7
+ >
8
+ {{ toggleBtnControl.value ? setting('active-text') : setting('inactive-text') }}
9
+ </button>
10
+ </fx-component>
@@ -0,0 +1,40 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
3
+ import { FormControl, FormsModule, ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
4
+ import { FxBaseComponent, FxComponent, FxIconSetting, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
5
+
6
+ @Component({
7
+ selector: 'lib-toggle-button',
8
+ standalone: true,
9
+ imports: [CommonModule, FxComponent, ReactiveFormsModule, FormsModule],
10
+ templateUrl: './toggle-button.component.html',
11
+ styleUrl: './toggle-button.component.css'
12
+ })
13
+ export class ToggleButtonComponent extends FxBaseComponent {
14
+ public toggleBtnControl = new UntypedFormControl(false);
15
+ public isToggled = false;
16
+
17
+ constructor(private cdr: ChangeDetectorRef) {
18
+ super(cdr);
19
+ this.onInit.subscribe((fxData)=>{
20
+ this._register(this.toggleBtnControl);
21
+ })
22
+ }
23
+
24
+ public toggle(): void {
25
+ this.isToggled = !this.toggleBtnControl.value;
26
+ this.toggleBtnControl.setValue(this.isToggled);
27
+ }
28
+
29
+ protected settings(): FxSetting[] {
30
+ return [
31
+ new FxStringSetting({ key: 'classes', $title: 'Classes', value: '' }),
32
+ new FxStringSetting({ key: 'active-text', $title: 'Active Text', value: 'On' }),
33
+ new FxStringSetting({ key: 'inactive-text', $title: 'Inactive Text', value: 'Off' }),
34
+ ];
35
+ }
36
+
37
+ protected validations(): FxValidation[] {
38
+ return [FxValidatorService.required];
39
+ }
40
+ }
@@ -0,0 +1,49 @@
1
+ .custom-upload {
2
+ display: flex;
3
+ flex-direction: row;
4
+ align-items: flex-start;
5
+ }
6
+
7
+ .custom-upload button {
8
+ padding: 10px 20px;
9
+ font-size: 16px;
10
+ font-weight: bold;
11
+ color: white;
12
+ background-color: #007bff;
13
+ border: none;
14
+ border-radius: 5px;
15
+ cursor: pointer;
16
+ transition: background-color 0.3s;
17
+ }
18
+
19
+ .custom-upload button:hover {
20
+ background-color: #0056b3;
21
+ }
22
+
23
+ .custom-upload .file-list {
24
+ display: flex;
25
+ /* margin-top: 10px; */
26
+ }
27
+
28
+ .custom-upload .file-list p {
29
+ margin: 0;
30
+ padding: 5px;
31
+ background-color: #f1f1f1;
32
+ border: 1px solid #ddd;
33
+ border-radius: 3px;
34
+ font-size: 14px;
35
+ }
36
+
37
+ .custom-upload .file-list > div {
38
+ display: flex;
39
+ flex-direction: column;
40
+ align-items: center;
41
+ justify-content: center;
42
+ }
43
+
44
+ .custom-upload .file-list .file-thumbnail {
45
+ width: 100px;
46
+ height: 100px;
47
+ object-fit: contain;
48
+ }
49
+
@@ -0,0 +1,23 @@
1
+ <fx-component [fxData]="fxData">
2
+ <div class="custom-upload">
3
+ <button type="button" (click)="fileInput.click()">
4
+ {{setting('upload-text')}}
5
+ </button>
6
+ <input
7
+ #fileInput
8
+ type="file"
9
+ [multiple]="setting('multiple-upload')"
10
+ (change)="onFileSelected($event)"
11
+ [formControl]="uploadFileControl"
12
+ hidden
13
+ />
14
+ <div class="file-list">
15
+ <ng-container *ngIf="uploadedFiles?.length">
16
+ <div (click)="deleteFile(file?.id)" *ngFor="let file of uploadedFiles">
17
+ <img class="file-thumbnail" style="border-radius: 4px" [src]="file?.previewUrl" alt="">
18
+ <!-- <p>{{file?.name}}</p> -->
19
+ </div>
20
+ </ng-container>
21
+ </div>
22
+ </div>
23
+ </fx-component>