@allsorter/ui-components 0.0.408 → 0.0.412

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 (27) hide show
  1. package/fesm2022/allsorter-ui-components.mjs +134 -61
  2. package/fesm2022/allsorter-ui-components.mjs.map +1 -1
  3. package/lib/editable-form-wrapper/editable-form-wrapper.component.d.ts +6 -1
  4. package/lib/loader/loader.component.d.ts +7 -2
  5. package/lib/newresumeheader/newresumeheader.component.d.ts +3 -1
  6. package/lib/responsive-layout/responsive-layout.component.d.ts +1 -0
  7. package/lib/toggle-buttons/toggle-buttons.component.d.ts +2 -0
  8. package/package.json +1 -1
  9. package/src/lib/button/button.component.scss +1 -0
  10. package/src/lib/candidate-section/candidate-section.component.html +13 -17
  11. package/src/lib/candidate-section/candidate-section.component.scss +1 -0
  12. package/src/lib/custom-editor/custom-editor.component.scss +1 -1
  13. package/src/lib/editable-form-wrapper/editable-form-wrapper.component.html +0 -7
  14. package/src/lib/editable-form-wrapper/editable-form-wrapper.component.scss +269 -25
  15. package/src/lib/field-placeholder/field-placeholder.component.scss +4 -5
  16. package/src/lib/input/input.component.scss +2 -0
  17. package/src/lib/loader/loader.component.html +5 -5
  18. package/src/lib/loader/loader.component.scss +36 -13
  19. package/src/lib/newresumeheader/newresumeheader.component.html +2 -2
  20. package/src/lib/newresumeheader/newresumeheader.component.scss +6 -1
  21. package/src/lib/resume-entries/resume-entries.component.html +4 -1
  22. package/src/lib/resume-entries/resume-entries.component.scss +19 -11
  23. package/src/lib/tabs/tabs.component.html +1 -1
  24. package/src/lib/tabs/tabs.component.scss +7 -0
  25. package/src/lib/test-styling/test-styling.component.html +159 -1
  26. package/src/lib/toggle-buttons/toggle-buttons.component.html +4 -2
  27. package/src/lib/toggle-buttons/toggle-buttons.component.scss +16 -0
@@ -40,6 +40,11 @@ export declare class EditableFormWrapperComponent implements AfterViewInit, OnDe
40
40
  * If not provided, defaults to window scrolling.
41
41
  */
42
42
  scrollContainer: string | HTMLElement | null;
43
+ /**
44
+ * Padding for button clamp boundaries.
45
+ * @default 36
46
+ */
47
+ clampPadding: number;
43
48
  /**
44
49
  * Emitted when the left (edit) button is clicked.
45
50
  */
@@ -75,5 +80,5 @@ export declare class EditableFormWrapperComponent implements AfterViewInit, OnDe
75
80
  ngOnDestroy(): void;
76
81
  private setupScrollBehavior;
77
82
  static ɵfac: i0.ɵɵFactoryDeclaration<EditableFormWrapperComponent, never>;
78
- static ɵcmp: i0.ɵɵComponentDeclaration<EditableFormWrapperComponent, "al-form", never, { "testId": { "alias": "testId"; "required": false; }; "showLeftButton": { "alias": "showLeftButton"; "required": false; }; "showSaveButton": { "alias": "showSaveButton"; "required": false; }; "showDeleteButton": { "alias": "showDeleteButton"; "required": false; }; "leftContainerClass": { "alias": "leftContainerClass"; "required": false; }; "leftContainerStyle": { "alias": "leftContainerStyle"; "required": false; }; "scrollContainer": { "alias": "scrollContainer"; "required": false; }; }, { "leftButtonClick": "leftButtonClick"; "saveButtonClick": "saveButtonClick"; "deleteButtonClick": "deleteButtonClick"; }, never, ["[leftButtonContent]", "*"], true, never>;
83
+ static ɵcmp: i0.ɵɵComponentDeclaration<EditableFormWrapperComponent, "al-form", never, { "testId": { "alias": "testId"; "required": false; }; "showLeftButton": { "alias": "showLeftButton"; "required": false; }; "showSaveButton": { "alias": "showSaveButton"; "required": false; }; "showDeleteButton": { "alias": "showDeleteButton"; "required": false; }; "leftContainerClass": { "alias": "leftContainerClass"; "required": false; }; "leftContainerStyle": { "alias": "leftContainerStyle"; "required": false; }; "scrollContainer": { "alias": "scrollContainer"; "required": false; }; "clampPadding": { "alias": "clampPadding"; "required": false; }; }, { "leftButtonClick": "leftButtonClick"; "saveButtonClick": "saveButtonClick"; "deleteButtonClick": "deleteButtonClick"; }, never, ["[leftButtonContent]", "*"], true, never>;
79
84
  }
@@ -1,4 +1,4 @@
1
- import { OnInit, OnDestroy } from '@angular/core';
1
+ import { OnInit, OnDestroy, EventEmitter } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export type LoaderStatus = 'analyzing' | 'gathering' | 'processing' | 'applying' | 'done';
4
4
  export declare class LoaderComponent implements OnInit, OnDestroy {
@@ -43,6 +43,11 @@ export declare class LoaderComponent implements OnInit, OnDestroy {
43
43
  * @default false
44
44
  */
45
45
  completeOnDone: boolean;
46
+ /**
47
+ * Event emitted when the loader completes a full cycle (reaches 'done' status).
48
+ * Only emits when completeOnDone is true.
49
+ */
50
+ completed: EventEmitter<void>;
46
51
  private loopInterval?;
47
52
  private currentLoopIndex;
48
53
  private readonly statusOrder;
@@ -78,5 +83,5 @@ export declare class LoaderComponent implements OnInit, OnDestroy {
78
83
  */
79
84
  reset(): void;
80
85
  static ɵfac: i0.ɵɵFactoryDeclaration<LoaderComponent, never>;
81
- static ɵcmp: i0.ɵɵComponentDeclaration<LoaderComponent, "al-loader", never, { "dataTestId": { "alias": "dataTestId"; "required": false; }; "status": { "alias": "status"; "required": false; }; "customText": { "alias": "customText"; "required": false; }; "showText": { "alias": "showText"; "required": false; }; "size": { "alias": "size"; "required": false; }; "autoLoop": { "alias": "autoLoop"; "required": false; }; "loopDuration": { "alias": "loopDuration"; "required": false; }; "customTexts": { "alias": "customTexts"; "required": false; }; "completeOnDone": { "alias": "completeOnDone"; "required": false; }; }, {}, never, never, true, never>;
86
+ static ɵcmp: i0.ɵɵComponentDeclaration<LoaderComponent, "al-loader", never, { "dataTestId": { "alias": "dataTestId"; "required": false; }; "status": { "alias": "status"; "required": false; }; "customText": { "alias": "customText"; "required": false; }; "showText": { "alias": "showText"; "required": false; }; "size": { "alias": "size"; "required": false; }; "autoLoop": { "alias": "autoLoop"; "required": false; }; "loopDuration": { "alias": "loopDuration"; "required": false; }; "customTexts": { "alias": "customTexts"; "required": false; }; "completeOnDone": { "alias": "completeOnDone"; "required": false; }; }, { "completed": "completed"; }, never, never, true, never>;
82
87
  }
@@ -10,6 +10,8 @@ export declare class NewResumeHeaderComponent implements OnInit, OnDestroy, Afte
10
10
  title: string;
11
11
  showHeaderCheckbox: boolean;
12
12
  showEyeIcon: boolean;
13
+ showMenuTrigger: boolean;
14
+ showHeaderButtons: boolean;
13
15
  headerCheckboxChecked: boolean;
14
16
  configEyeToggle: EyeIconConfig[];
15
17
  hiddenSection: {
@@ -163,5 +165,5 @@ export declare class NewResumeHeaderComponent implements OnInit, OnDestroy, Afte
163
165
  ngAfterViewInit(): void;
164
166
  ngOnDestroy(): void;
165
167
  static ɵfac: i0.ɵɵFactoryDeclaration<NewResumeHeaderComponent, never>;
166
- static ɵcmp: i0.ɵɵComponentDeclaration<NewResumeHeaderComponent, "al-newresumeheader", never, { "title": { "alias": "title"; "required": false; }; "showHeaderCheckbox": { "alias": "showHeaderCheckbox"; "required": false; }; "showEyeIcon": { "alias": "showEyeIcon"; "required": false; }; "headerCheckboxChecked": { "alias": "headerCheckboxChecked"; "required": false; }; "configEyeToggle": { "alias": "configEyeToggle"; "required": false; }; "hiddenSection": { "alias": "hiddenSection"; "required": false; }; "buttonConfig": { "alias": "buttonConfig"; "required": false; }; "isLargeScreen": { "alias": "isLargeScreen"; "required": false; }; "popOutButtonLabel": { "alias": "popOutButtonLabel"; "required": false; }; "popOutButtonIcon": { "alias": "popOutButtonIcon"; "required": false; }; "popOutButtonTooltip": { "alias": "popOutButtonTooltip"; "required": false; }; "popOutButtonTooltipPosition": { "alias": "popOutButtonTooltipPosition"; "required": false; }; "showPopOutPanel": { "alias": "showPopOutPanel"; "required": false; }; "popOutMessage": { "alias": "popOutMessage"; "required": false; }; "dataTestId": { "alias": "dataTestId"; "required": false; }; "fieldVisibility": { "alias": "fieldVisibility"; "required": false; }; "index": { "alias": "index"; "required": false; }; "showBottomBorder": { "alias": "showBottomBorder"; "required": false; }; "borderColor": { "alias": "borderColor"; "required": false; }; }, { "titleChange": "titleChange"; "sectionToggled": "sectionToggled"; "headerCheckboxChange": "headerCheckboxChange"; "showHideToggleSection": "showHideToggleSection"; "buttonClicked": "buttonClicked"; "popOutButtonClick": "popOutButtonClick"; }, never, ["[header-left]", "[header-center-left]", "[header-center-center]", "[header-center-right]", "[header-right]", "[header-left]", "[header-center-right]", "[header-right]", "*"], true, never>;
168
+ static ɵcmp: i0.ɵɵComponentDeclaration<NewResumeHeaderComponent, "al-newresumeheader", never, { "title": { "alias": "title"; "required": false; }; "showHeaderCheckbox": { "alias": "showHeaderCheckbox"; "required": false; }; "showEyeIcon": { "alias": "showEyeIcon"; "required": false; }; "showMenuTrigger": { "alias": "showMenuTrigger"; "required": false; }; "showHeaderButtons": { "alias": "showHeaderButtons"; "required": false; }; "headerCheckboxChecked": { "alias": "headerCheckboxChecked"; "required": false; }; "configEyeToggle": { "alias": "configEyeToggle"; "required": false; }; "hiddenSection": { "alias": "hiddenSection"; "required": false; }; "buttonConfig": { "alias": "buttonConfig"; "required": false; }; "isLargeScreen": { "alias": "isLargeScreen"; "required": false; }; "popOutButtonLabel": { "alias": "popOutButtonLabel"; "required": false; }; "popOutButtonIcon": { "alias": "popOutButtonIcon"; "required": false; }; "popOutButtonTooltip": { "alias": "popOutButtonTooltip"; "required": false; }; "popOutButtonTooltipPosition": { "alias": "popOutButtonTooltipPosition"; "required": false; }; "showPopOutPanel": { "alias": "showPopOutPanel"; "required": false; }; "popOutMessage": { "alias": "popOutMessage"; "required": false; }; "dataTestId": { "alias": "dataTestId"; "required": false; }; "fieldVisibility": { "alias": "fieldVisibility"; "required": false; }; "index": { "alias": "index"; "required": false; }; "showBottomBorder": { "alias": "showBottomBorder"; "required": false; }; "borderColor": { "alias": "borderColor"; "required": false; }; }, { "titleChange": "titleChange"; "sectionToggled": "sectionToggled"; "headerCheckboxChange": "headerCheckboxChange"; "showHideToggleSection": "showHideToggleSection"; "buttonClicked": "buttonClicked"; "popOutButtonClick": "popOutButtonClick"; }, never, ["[header-left]", "[header-center-left]", "[header-center-center]", "[header-center-right]", "[header-right]", "[header-left]", "[header-center-right]", "[header-right]", "*"], true, never>;
167
169
  }
@@ -33,6 +33,7 @@ export declare class ResponsiveLayoutComponent {
33
33
  /** Minimum columns (e.g. 2) so this row never collapses to 1 column on small viewports. Use for "Date Type + Current Role/Study" row in certification/experience. */
34
34
  minColumns?: number;
35
35
  get hasMinCols2(): boolean;
36
+ get hasMinCols3(): boolean;
36
37
  get cssGap(): string;
37
38
  get cssCountMobile(): number;
38
39
  get cssCountMobileSm(): number;
@@ -4,7 +4,9 @@ export interface ToggleButton {
4
4
  id: string;
5
5
  label?: string;
6
6
  icon?: string;
7
+ fontSet?: string;
7
8
  disabled?: boolean;
9
+ tooltip?: string;
8
10
  dataTestId?: string;
9
11
  }
10
12
  export declare class ToggleButtonsComponent {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allsorter/ui-components",
3
- "version": "0.0.408",
3
+ "version": "0.0.412",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^18.0.0",
6
6
  "@angular/core": "^18.0.0",
@@ -458,6 +458,7 @@ mat-icon.mat-icon {
458
458
  align-items: center !important;
459
459
  justify-content: center !important;
460
460
  flex-shrink: 0;
461
+ cursor: pointer;
461
462
  }
462
463
 
463
464
  /* Ensure SVG icons inherit button text color for proper visibility */
@@ -4,28 +4,28 @@
4
4
  <div class="container" data-test-id="candidate-section-name-container"
5
5
  [style.opacity]="candidate_name ? '1' : '0.3'"><lib-field-placeholder icon="candidate_name"
6
6
  [value]="candidateDetails?.firstName && candidateDetails?.lastName ? candidateDetails?.firstName + ' ' + candidateDetails?.lastName : candidateDetails?.firstName || candidateDetails?.lastName"
7
- [placeholder]="'Name'" [tooltip]="candidateDetails?.firstName + ' ' + candidateDetails?.lastName"
8
- tooltipPosition="right" [testId]="'candidate-section-name'" [valueClass]="'typo-description'"
7
+ [placeholder]="'Name'"
8
+ [testId]="'candidate-section-name'" [valueClass]="'typo-description'"
9
9
  [compact]="true"></lib-field-placeholder></div>
10
10
  <div class="container" data-test-id="candidate-section-gender-container"
11
11
  [style.opacity]="candidate_gender ? '1' : '0.3'"><lib-field-placeholder icon="candidate_gender"
12
12
  [value]="candidateDetails?.userAssignedGender" [placeholder]="'Gender'"
13
- [tooltip]="candidateDetails?.userAssignedGender" tooltipPosition="right" [testId]="'candidate-section-gender'"
13
+ [testId]="'candidate-section-gender'"
14
14
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
15
15
  <div class="container" data-test-id="candidate-section-phone-container"
16
16
  [style.opacity]="candidate_phonenumber ? '1' : '0.3'"><lib-field-placeholder
17
17
  icon="candidate_phonenumber" [value]="candidateDetails?.phoneNumber" [placeholder]="'Phone Number'"
18
- [tooltip]="candidateDetails?.phoneNumber" tooltipPosition="right" [testId]="'candidate-section-phone'"
18
+ [testId]="'candidate-section-phone'"
19
19
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
20
20
  <div class="container" data-test-id="candidate-section-email-container"
21
21
  [style.opacity]="candidate_email ? '1' : '0.3'"><lib-field-placeholder icon="candidate_email"
22
22
  [value]="candidateDetails?.emailAddress" [placeholder]="'Email Address'"
23
- [tooltip]="candidateDetails?.emailAddress" tooltipPosition="right" [testId]="'candidate-section-email'"
23
+ [testId]="'candidate-section-email'"
24
24
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
25
25
  <div class="container" data-test-id="candidate-section-linkedin-container"
26
26
  [style.opacity]="candidate_linkedin ? '1' : '0.3'"><lib-field-placeholder
27
27
  icon="candidate_linkedin" iconAlt="LinkedIn" [value]="candidateDetails?.linkedin" [placeholder]="'LinkedIn'"
28
- [tooltip]="candidateDetails?.linkedin" tooltipPosition="right" [testId]="'candidate-section-linkedin'"
28
+ [testId]="'candidate-section-linkedin'"
29
29
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
30
30
  </div>
31
31
  <div class="column second-column">
@@ -33,28 +33,26 @@
33
33
  [style.opacity]="candidate_address ? '1' : '0.3'">
34
34
  <div [style.opacity]="addressStreet ? '1' : '0.3'"><lib-field-placeholder
35
35
  icon="candidate_address" [value]="candidateDetails?.street" [placeholder]="'Street'"
36
- [tooltip]="candidateDetails?.street" tooltipPosition="right" [testId]="'candidate-section-address-street'"
36
+ [testId]="'candidate-section-address-street'"
37
37
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
38
38
  <div [style.opacity]="addressCity ? '1' : '0.3'"><lib-field-placeholder icon="no-icon"
39
- [value]="candidateDetails?.city" [placeholder]="'City'" [tooltip]="candidateDetails?.city"
40
- tooltipPosition="right" [testId]="'candidate-section-address-city'" [valueClass]="'typo-description'"
39
+ [value]="candidateDetails?.city" [placeholder]="'City'"
40
+ [testId]="'candidate-section-address-city'" [valueClass]="'typo-description'"
41
41
  [compact]="true"></lib-field-placeholder></div>
42
42
  <div [style.opacity]="addressRegion ? '1' : '0.3'"><lib-field-placeholder
43
43
  icon="no-icon" [value]="candidateDetails?.region" [placeholder]="'Region'"
44
- [tooltip]="candidateDetails?.region" tooltipPosition="right" [testId]="'candidate-section-address-region'"
44
+ [testId]="'candidate-section-address-region'"
45
45
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
46
46
  <div [style.opacity]="addressRegionCode ? '1' : '0.3'"><lib-field-placeholder
47
47
  [value]="candidateDetails?.regionCode" [placeholder]="'Region Code'" icon="no-icon"
48
- [tooltip]="candidateDetails?.regionCode" tooltipPosition="right"
49
48
  [testId]="'candidate-section-address-region-code'" [valueClass]="'typo-description'"
50
49
  [compact]="true"></lib-field-placeholder></div>
51
50
  <div [style.opacity]="addressCountry ? '1' : '0.3'"><lib-field-placeholder
52
51
  icon="no-icon" [value]="candidateDetails?.country" [placeholder]="'Country'"
53
- [tooltip]="candidateDetails?.country" tooltipPosition="right" [testId]="'candidate-section-address-country'"
52
+ [testId]="'candidate-section-address-country'"
54
53
  [valueClass]="'typo-description'" [compact]="true"></lib-field-placeholder></div>
55
54
  <div [style.opacity]="addressPostCode ? '1' : '0.3'"><lib-field-placeholder
56
55
  icon="no-icon" [value]="candidateDetails?.postCode" [placeholder]="'Post Code'"
57
- [tooltip]="candidateDetails?.postCode" tooltipPosition="right"
58
56
  [testId]="'candidate-section-address-post-code'" [valueClass]="'typo-description'"
59
57
  [compact]="true"></lib-field-placeholder></div>
60
58
  </div>
@@ -66,8 +64,7 @@
66
64
  <lib-field-placeholder icon="candidate_most_recent"
67
65
  [value]="(getCurrentJob() || getCurrentEmployer()) ? 'Most Recently : <span class=\'most-recent-inline\'>' + (getCurrentJob() ? '<span class=\'total-exp-value\'>' + getCurrentJob() + '</span>' : '') + (getCurrentEmployer() ? (getCurrentJob() ? ' at <span class=\'total-exp-value\'>' + getCurrentEmployer() + '</span>' : '<span class=\'total-exp-value\'>' + getCurrentEmployer() + '</span>') : '') + '</span>' : ''"
68
66
  [placeholder]="'Current Job'"
69
- [tooltip]="(getCurrentJob() || getCurrentEmployer()) ? 'Most Recently : ' + getCurrentJob() + (getCurrentEmployer() ? ' at ' + getCurrentEmployer() : '') : 'Current Job'"
70
- tooltipPosition="right" [testId]="'candidate-section-current-job'" [valueClass]="'typo-description'"
67
+ [testId]="'candidate-section-current-job'" [valueClass]="'typo-description'"
71
68
  [compact]="true"></lib-field-placeholder>
72
69
  <div class="most-recent-details">
73
70
  <div class="current-job-title" *ngIf="getCurrentJob()">{{getCurrentJob()}}</div>
@@ -80,8 +77,7 @@
80
77
  icon="candidate_experience"
81
78
  [value]="getTotalExpYears() ? 'Total Exp - <span class=\'total-exp-value\'>' + getTotalExpYears() + '</span> yrs' : ''"
82
79
  [placeholder]="'Total Exp'"
83
- [tooltip]="getTotalExpYears() ? 'Total Exp - ' + getTotalExpYears() + ' yrs' : 'Total Exp'"
84
- tooltipPosition="right" [testId]="'candidate-section-total-exp-value'" [valueClass]="'typo-description'"
80
+ [testId]="'candidate-section-total-exp-value'" [valueClass]="'typo-description'"
85
81
  [compact]="true"></lib-field-placeholder></div>
86
82
  </div>
87
83
  </div>
@@ -4,6 +4,7 @@
4
4
  display: flex;
5
5
  flex-direction: row;
6
6
  gap: 16px;
7
+ cursor: pointer;
7
8
  }
8
9
 
9
10
  .columns-wrapper {
@@ -382,7 +382,7 @@
382
382
  }
383
383
 
384
384
  p {
385
- margin: 0 0 12px 0;
385
+ margin: 0 0 0px 0;
386
386
 
387
387
  &:last-child {
388
388
  margin-bottom: 0;
@@ -1,12 +1,5 @@
1
1
  <div class="al-form-wrapper" #wrapper [attr.data-test-id]="testId">
2
2
  <div *ngIf="showLeftButton" #leftButton class="fab left">
3
- <!-- <al-button [buttonType]="'icon-circle'" [iconOnly]="true"
4
- [leftIcon]="isLeftButtonActive ? 'close' : 'auto_fix_high'"
5
- [arialabel]="isLeftButtonActive ? 'Close' : 'Edit'"
6
- [size]="'base'"
7
- [color]="isLeftButtonActive ? 'grey' : 'gradient'"
8
- (onClick)="handleLeftButtonClick($event)">
9
- </al-button> -->
10
3
  <div
11
4
  class="left-button-container"
12
5
  [ngClass]="leftContainerClass"
@@ -54,6 +54,8 @@
54
54
  /* Enable container queries for responsive layout based on container size */
55
55
  container-type: inline-size;
56
56
  container-name: form-wrapper;
57
+ /* Isolate layout calculations to prevent FABs from causing parent reflow */
58
+ contain: layout style;
57
59
  }
58
60
 
59
61
  /* Subtle outer rounded border (like a frame) */
@@ -88,6 +90,20 @@
88
90
  box-sizing: border-box;
89
91
  z-index: 0;
90
92
 
93
+ /* Ensure content doesn't overflow the form */
94
+ overflow: hidden;
95
+ }
96
+
97
+ /* Ensure all form inputs don't overflow their containers */
98
+ :host ::ng-deep .al-form-wrapper>.inner > * {
99
+ max-width: 100%;
100
+ box-sizing: border-box;
101
+ }
102
+
103
+ /* Ensure app-flex-grid doesn't overflow */
104
+ :host ::ng-deep .al-form-wrapper>.inner app-flex-grid {
105
+ max-width: 100%;
106
+ box-sizing: border-box;
91
107
  }
92
108
 
93
109
  /* Trim accidental extra spacing from first/last child margins inside content */
@@ -195,19 +211,28 @@ select.al-form__control {
195
211
  position: absolute;
196
212
  left: -27px;
197
213
  /* intended design: slightly outside the inner frame */
198
- top: 0;
199
- /* Changed from top: 50% to top: 0, transform will be handled by JS */
214
+ top: 36px;
215
+ /* Start at clampPadding position to minimize jump */
200
216
  z-index: 10;
201
217
  background-color: #fff;
202
218
  border-radius: 50%;
203
219
  will-change: transform;
204
220
  /* Optimize for smooth scrolling */
205
221
  transition: transform 0.1s ease-out;
222
+ opacity: 0;
223
+ /* Start hidden, shown after positioning */
224
+ /* Match height with right button group (2 buttons + 8px gap = ~88px) */
225
+ height: 88px;
226
+ display: flex;
227
+ align-items: center;
228
+ /* Center the inner button container */
206
229
 
207
230
  .left-button-container {
208
231
  position: absolute;
209
232
  left: 56px;
210
- top: 0;
233
+ /* Vertically centered by flexbox on parent */
234
+ top: 50%;
235
+ transform: translateY(-50%);
211
236
  z-index: 1;
212
237
  pointer-events: auto;
213
238
  }
@@ -217,8 +242,8 @@ select.al-form__control {
217
242
  position: absolute;
218
243
  right: -16px;
219
244
  /* slightly outside the inner frame */
220
- top: 0;
221
- /* Changed from top: 50% to top: 0, transform will be handled by JS */
245
+ top: 36px;
246
+ /* Start at clampPadding position to minimize jump */
222
247
  display: flex;
223
248
  flex-direction: column;
224
249
  border-radius: 50%;
@@ -228,6 +253,16 @@ select.al-form__control {
228
253
  will-change: transform;
229
254
  /* Optimize for smooth scrolling */
230
255
  transition: transform 0.1s ease-out;
256
+ opacity: 0;
257
+ /* Start hidden, shown after positioning */
258
+ /* Fixed height to match left button (2 buttons + 8px gap) */
259
+ height: 82px;
260
+ }
261
+
262
+ /* When buttons are positioned, show them */
263
+ .fab.left.positioned,
264
+ .fab-group.right.positioned {
265
+ opacity: 1;
231
266
  }
232
267
 
233
268
  /* Add gap between form rows (app-flex-grid elements) */
@@ -246,10 +281,11 @@ select.al-form__control {
246
281
  justify-content: center;
247
282
  }
248
283
 
249
- /* AL Form only: force 2 columns for the first row (Date Type + Current Study) when viewport or form is narrow.
284
+ /* AL Form only: force 2 columns for the first row when viewport or form is narrow.
250
285
  Without this, app-flex-grid would collapse to 1 column; we keep 2 cols for this row inside al-form.
251
286
 
252
- WITHOUT Date Type (3 children): use 1 column so each field is on its own row */
287
+ WITH Date Type (Date Type, Current Study, ...): 2-1 layout (Date Type|Current Study in row 1, End Date in row 2)
288
+ WITHOUT Date Type (Current Study, Start Date, End Date): 1-1-1 layout (each field on its own row) */
253
289
  @media (max-width: 767.98px) {
254
290
  :host ::ng-deep app-flex-grid.row.min-cols-2,
255
291
  :host ::ng-deep app-flex-grid.col.min-cols-2 {
@@ -257,8 +293,24 @@ select.al-form__control {
257
293
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
258
294
  }
259
295
 
260
- /* Without Date Type: force 1 column so Current Study, Start Date, End Date each on own row */
261
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) {
296
+ /* Ensure checkbox and input don't span full width - fit in their grid cells */
297
+ :host ::ng-deep app-flex-grid.row.min-cols-2 al-checkbox,
298
+ :host ::ng-deep app-flex-grid.row.min-cols-2 al-input,
299
+ :host ::ng-deep app-flex-grid.col.min-cols-2 al-checkbox,
300
+ :host ::ng-deep app-flex-grid.col.min-cols-2 al-input {
301
+ grid-column: auto !important;
302
+ width: 100% !important;
303
+ max-width: 100% !important;
304
+ }
305
+
306
+ /* WITH Date Type (Date Type, Current Study, End Date): ensure inputs don't span full width */
307
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-input) {
308
+ grid-column: auto !important;
309
+ }
310
+
311
+ /* WITHOUT Date Type (first child is checkbox): force 1 column so Current Study, Start Date, End Date each on own row */
312
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox),
313
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox) ~ * {
262
314
  grid-column: 1 / -1 !important;
263
315
  }
264
316
  }
@@ -270,28 +322,220 @@ select.al-form__control {
270
322
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
271
323
  }
272
324
 
273
- /* Without Date Type: force 1 column so Current Study, Start Date, End Date each on own row */
274
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) {
325
+ /* Ensure checkbox and input don't span full width - fit in their grid cells */
326
+ :host ::ng-deep app-flex-grid.row.min-cols-2 al-checkbox,
327
+ :host ::ng-deep app-flex-grid.row.min-cols-2 al-input,
328
+ :host ::ng-deep app-flex-grid.col.min-cols-2 al-checkbox,
329
+ :host ::ng-deep app-flex-grid.col.min-cols-2 al-input {
330
+ grid-column: auto !important;
331
+ width: 100% !important;
332
+ max-width: 100% !important;
333
+ }
334
+
335
+ /* WITH Date Type (Date Type, Current Study, End Date): ensure inputs don't span full width */
336
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-input) {
337
+ grid-column: auto !important;
338
+ }
339
+
340
+ /* WITHOUT Date Type (first child is checkbox): force 1 column so Current Study, Start Date, End Date each on own row */
341
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox),
342
+ :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox) ~ * {
343
+ grid-column: 1 / -1 !important;
344
+ }
345
+ }
346
+
347
+ /* When form wrapper is wide enough (600px+): maintain responsive order with CSS.
348
+ Container query so order follows form width.
349
+
350
+ ORDER REQUIREMENTS:
351
+ - 4 fields: Date Type | Start Date | End Date | Current Study
352
+ - 3 fields (no Start Date): Date Type | End Date | Current Study
353
+ - 3 fields (no Date Type): Start Date | End Date | Current Study
354
+ - 2 fields (no Date Type, no Start Date): End Date | Current Study */
355
+ @container form-wrapper (min-width: 600px) {
356
+ /* === 4 CHILDREN: Date Type, Current Study, Start Date, End Date === */
357
+ /* Result: Date Type | Start Date | End Date | Current Study */
358
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(1) { order: 1; } /* Date Type → 1st */
359
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(2) { order: 4; } /* Current Study → 4th */
360
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(3) { order: 2; } /* Start Date → 2nd */
361
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(4) { order: 3; } /* End Date → 3rd */
362
+
363
+ /* === 3 CHILDREN: Date Type, Current Study, End Date (NO Start Date) === */
364
+ /* DOM order: Date Type(1), Current Study(2), End Date(3) */
365
+ /* Result: Date Type | End Date | Current Study */
366
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) {
367
+ order: 1;
368
+ grid-column: 1 / 2 !important;
369
+ }
370
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) ~ *:nth-child(2) {
371
+ order: 3;
372
+ grid-column: 4 / 5 !important;
373
+ }
374
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) ~ *:nth-child(3) {
375
+ order: 2;
376
+ grid-column: 2 / 4 !important;
377
+ }
378
+
379
+ /* === 3 CHILDREN: Current Study, Start Date, End Date (NO Date Type) === */
380
+ /* DOM order: Current Study(1), Start Date(2), End Date(3) */
381
+ /* Result: Start Date | End Date | Current Study */
382
+ /* Override: checkbox (1st child) moves to 3rd position */
383
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox) {
384
+ order: 3;
385
+ grid-column: 4 / 5 !important;
386
+ }
387
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(2) {
388
+ order: 1;
389
+ grid-column: 1 / 2 !important;
390
+ }
391
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(3) {
392
+ order: 2;
393
+ grid-column: 2 / 4 !important;
394
+ }
395
+
396
+ /* === 2 CHILDREN: Current Study, End Date (NO Date Type, NO Start Date) === */
397
+ /* DOM order: Current Study(1), End Date(2) */
398
+ /* Result: End Date | Current Study */
399
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(2) {
400
+ order: 2;
401
+ grid-column: 2 / 3 !important;
402
+ }
403
+ ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(2):last-child {
404
+ order: 1;
405
+ grid-column: 1 / 2 !important;
406
+ }
407
+ }
408
+
409
+ /* ============================================
410
+ 3-COLUMN LAYOUT RULES
411
+ Scenario: Start Date, End Date, Checkbox (no Date Type)
412
+
413
+ Desktop (600px+): Start Date | End Date | Checkbox (equal 1fr each)
414
+ Mobile (< 600px): Checkbox (full width, first), then Start Date | End Date
415
+
416
+ DOM order in actual project: Checkbox(1), Start Date(2), End Date(3)
417
+ ============================================ */
418
+
419
+ /* Mobile layout: 2 columns, checkbox first (full width), dates in row 2 */
420
+ @media (max-width: 767.98px) {
421
+ /* Target 3-column grids using min-cols-3 class or style attribute */
422
+ :host ::ng-deep app-flex-grid.row.min-cols-3,
423
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] {
424
+ --current-count: 2 !important;
425
+ grid-template-columns: repeat(2, 1fr) !important;
426
+ }
427
+
428
+ /* Move checkbox to first position, full width */
429
+ :host ::ng-deep app-flex-grid.row.min-cols-3 al-checkbox,
430
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] al-checkbox {
431
+ order: -1 !important;
275
432
  grid-column: 1 / -1 !important;
276
433
  }
434
+
435
+ /* Extra small screens (400.98px or less): all fields in separate rows (1 column) */
436
+ @media (max-width: 400.98px) {
437
+ :host ::ng-deep app-flex-grid.row.min-cols-3,
438
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] {
439
+ --current-count: 1 !important;
440
+ grid-template-columns: 1fr !important;
441
+ }
442
+
443
+ /* Reset all to natural DOM order: Current Study, Start Date, End Date */
444
+ :host ::ng-deep app-flex-grid.row.min-cols-3 > *,
445
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > * {
446
+ order: 0 !important;
447
+ grid-column: auto !important;
448
+ }
449
+ }
277
450
  }
278
451
 
279
- /* When form wrapper is wide enough (600px+): show initial order (Date Type, Start Date, End Date, Current Study).
280
- DOM order is Date Type, Current Study, Start Date, End Date; reorder with CSS.
281
- Container query so order follows form width (works in test-styling and narrow viewports).
452
+ /* Container query for mobile */
453
+ @container form-wrapper (max-width: 600px) {
454
+ :host ::ng-deep app-flex-grid.row.min-cols-3,
455
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] {
456
+ --current-count: 2 !important;
457
+ grid-template-columns: repeat(2, 1fr) !important;
458
+ }
459
+
460
+ /* Move checkbox to first position, full width */
461
+ :host ::ng-deep app-flex-grid.row.min-cols-3 al-checkbox,
462
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] al-checkbox {
463
+ order: -1 !important;
464
+ grid-column: 1 / -1 !important;
465
+ }
466
+ }
467
+
468
+ /* Extra small container (400px or less): all fields in separate rows (1 column) */
469
+ @container form-wrapper (max-width: 400px) {
470
+ :host ::ng-deep app-flex-grid.row.min-cols-3,
471
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] {
472
+ --current-count: 1 !important;
473
+ grid-template-columns: 1fr !important;
474
+ }
282
475
 
283
- WITHOUT Date Type (3 children): Start Date, End Date on row 1, Current Study on row 2 (as column) */
476
+ /* Reset all to natural DOM order: Current Study, Start Date, End Date */
477
+ :host ::ng-deep app-flex-grid.row.min-cols-3 > *,
478
+ :host ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > * {
479
+ order: 0 !important;
480
+ grid-column: auto !important;
481
+ }
482
+ }
483
+
484
+ /* Desktop layout: 3 equal columns, reorder to Start Date | End Date | Checkbox */
284
485
  @container form-wrapper (min-width: 600px) {
285
- /* With Date Type present (4 children): Date Type, Start Date, End Date, Current Study */
286
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(1) { order: 1; }
287
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(2) { order: 4; }
288
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(3) { order: 2; }
289
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(4) { order: 3; }
290
-
291
- /* Without Date Type (3 children): Start Date, End Date, Current Study all in ONE row */
292
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:first-child:nth-last-child(3) { order: 3; } /* Current Study last */
293
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(2):nth-last-child(2) { order: 1; } /* Start Date first */
294
- :host ::ng-deep app-flex-grid.row.min-cols-2 > *:nth-child(3):last-child { order: 2; } /* End Date middle */
486
+ /* Force 3 equal columns */
487
+ ::ng-deep app-flex-grid.row.min-cols-3,
488
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] {
489
+ grid-template-columns: repeat(3, 1fr) !important;
490
+ }
491
+
492
+ /* === 3 CHILDREN: Checkbox(1), Start Date(2), End Date(3) === */
493
+ /* Reorder to: Start Date | End Date | Checkbox */
494
+ ::ng-deep app-flex-grid.row.min-cols-3 > *:first-child:nth-last-child(3):is(al-checkbox),
495
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > *:first-child:nth-last-child(3):is(al-checkbox) {
496
+ order: 3 !important;
497
+ grid-column: auto !important;
498
+ }
499
+ ::ng-deep app-flex-grid.row.min-cols-3 > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(2),
500
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(2) {
501
+ order: 1 !important;
502
+ grid-column: auto !important;
503
+ }
504
+ ::ng-deep app-flex-grid.row.min-cols-3 > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(3),
505
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > *:first-child:nth-last-child(3):is(al-checkbox) ~ *:nth-child(3) {
506
+ order: 2 !important;
507
+ grid-column: auto !important;
508
+ }
509
+
510
+ /* === 2 CHILDREN: Checkbox(1), Start Date OR End Date(2) === */
511
+ /* Checkbox stays in position 2, date in position 1 */
512
+ ::ng-deep app-flex-grid.row.min-cols-3 > *:first-child:nth-last-child(2):is(al-checkbox),
513
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > *:first-child:nth-last-child(2):is(al-checkbox) {
514
+ order: 2 !important;
515
+ grid-column: 3 / 4 !important;
516
+ }
517
+ ::ng-deep app-flex-grid.row.min-cols-3 > *:first-child:nth-last-child(2):is(al-checkbox) ~ *:nth-child(2),
518
+ ::ng-deep app-flex-grid.row[style*="--count-desktop: 3"] > *:first-child:nth-last-child(2):is(al-checkbox) ~ *:nth-child(2) {
519
+ order: 1 !important;
520
+ grid-column: 1 / 3 !important;
521
+ }
522
+ }
523
+
524
+ /* Fade-in animation for FABs on initial render */
525
+ @keyframes fadeIn {
526
+ from {
527
+ opacity: 0;
528
+ }
529
+ to {
530
+ opacity: 1;
531
+ }
532
+ }
533
+
534
+ /* Apply fade-in animation to left and right FABs */
535
+ .fab.left,
536
+ .fab-group.right {
537
+ opacity: 0;
538
+ animation: fadeIn 1s ease-out forwards;
295
539
  }
296
540
 
297
541
  /* Remove special outline/background styles so buttons render as-is */
@@ -80,10 +80,9 @@
80
80
  }
81
81
 
82
82
 
83
- .value-text {
84
- color: $color-grey-600 !important;
85
- }
86
-
83
+ // .value-text {
84
+ // color: $color-grey-600 !important;
85
+ // }
87
86
  // Apply collapsed styles when .collapsed is anywhere in parent hierarchy
88
87
  .collapsed .value-text {
89
88
  display: -webkit-box !important;
@@ -93,4 +92,4 @@
93
92
  overflow: hidden !important;
94
93
  text-overflow: ellipsis !important;
95
94
  white-space: normal !important;
96
- }
95
+ }
@@ -420,6 +420,7 @@
420
420
  display: flex !important;
421
421
  align-items: center !important;
422
422
  justify-content: center !important;
423
+ cursor: pointer;
423
424
  }
424
425
 
425
426
  /* Icon sizing by size category */
@@ -498,6 +499,7 @@ mat-icon[matSuffix] {
498
499
  display: flex;
499
500
  align-items: center;
500
501
  justify-content: center;
502
+ cursor: pointer;
501
503
  }
502
504
 
503
505
  /* ===== FLOATING LABEL POSITIONING ===== */