diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html index 223538f..e9edd3e 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html @@ -40,19 +40,19 @@
Behov av tolk:
{{avropInformation.tolkbehov || 'Inget tolkbehov'}} - +

Tolk är en typ av språkstöd som kan behöva anlitas vid behov. Ibland står Arbetsförmedlingen för tolkkostnaden och ibland står leverantören för tolkkostnaden. Det finns skillnader mellan vilket språkstöd som ingår i upphandlingen av olika tjänster och utbildningar. Du hittar mer information om språkstöd och tolk i förfrågningsunderlaget för specifik upphandling.

-
+
Behov av språkstöd:
{{avropInformation.sprakstod || 'Inget språkstöd'}} - +

Det finns flera olika typer av språkstöd. Till exempel användande av flerspråkig personal, tillgång till material på lätt svenska eller olika språk, anlitande av tolk med mera. Dessa kan erbjudas och kombineras @@ -60,7 +60,7 @@ tjänster och utbildningar. Du hittar mer information om språkstöd i förfrågningsunderlaget för specifik upphandling.

-
+
@@ -108,12 +108,12 @@ class="deltagare-tab-personal-information__info" > {{ avropInformation.genomforandeReferens }} - +

Genomförandereferens är det referensnummer du ska använda dig av i kontakten med Arbetsförmedlingen. Du kan också använda genomförandereferensen till att leta fram en order i leverantörsportalen.

-
+ diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.scss b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.scss index 440a8de..a2cc661 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.scss +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.scss @@ -22,13 +22,4 @@ display: flex; align-items: center; } - - &__popover { - display: inline-block; - margin-left: var(--digi--layout--gutter--s); - - ::ng-deep .digi-ng-popover__container { - z-index: $msfa__z-index-popover; - } - } } diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts index 5c280ab..ca49ba6 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts @@ -9,6 +9,7 @@ import { distinctUntilChanged, filter, map, startWith, switchMap } from 'rxjs/op import { DeltagareCardService } from '../../deltagare-card.service'; import { UiIconType } from '@ui/icon/icon-type.enum'; import { UiIconSize } from '@ui/icon/icon-size.enum'; +import { UiPopoverPosition } from '@ui/popover/ui-popover.component'; @Component({ selector: 'msfa-deltagare-tab-personal-information', @@ -21,6 +22,7 @@ export class DeltagareTabPersonalInformationComponent { @Input() handledarePickerVisible: boolean; IconType = UiIconType; IconSize = UiIconSize; + UiPopoverPosition = UiPopoverPosition; avropInformation$: Observable = this.deltagareCardService.avropInformation$; contactInformation$: Observable = this.deltagareCardService.contactInformation$; diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.html b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.html index 1863464..0c931a3 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.html +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.html @@ -6,12 +6,9 @@
Funktionsnedsättning {{index + 1}}
- {{ disability.title }} - {{ disability.description }}{{ disability.description }}
diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.scss b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.scss index bbc0ca0..bdad79e 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.scss +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component.scss @@ -15,9 +15,5 @@ &__popover { display: inline-block; margin-left: var(--digi--layout--gutter--s); - - ::ng-deep .digi-ng-popover__container { - z-index: $msfa__z-index-popover; - } } } diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/deltagare-card.module.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/deltagare-card.module.ts index dd33552..2cb86ee 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/deltagare-card.module.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-details/pages/deltagare-card/deltagare-card.module.ts @@ -19,6 +19,7 @@ import { DeltagareTabReportsComponent } from './components/deltagare-tab-reports import { DeltagareTabSensitiveInformationComponent } from './components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component'; import { DeltagareCardComponent } from './deltagare-card.component'; import { DeltagareCardService } from './deltagare-card.service'; +import { UiPopoverModule } from '@ui/popover/ui-popover.module'; @NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -41,6 +42,7 @@ import { DeltagareCardService } from './deltagare-card.service'; HandledarePickerFormModule, DigiNgLayoutExpansionPanelModule, DigiNgPopoverModule, + UiPopoverModule, UiSkeletonModule, UiIconModule, UiLinkButtonModule, diff --git a/libs/ui/src/icon/icon-type.enum.ts b/libs/ui/src/icon/icon-type.enum.ts index 9033a25..78c31f0 100644 --- a/libs/ui/src/icon/icon-type.enum.ts +++ b/libs/ui/src/icon/icon-type.enum.ts @@ -21,6 +21,8 @@ export enum UiIconType { ARROW_RIGHT = 'arrow-right', EYE = 'eye', EYESLASH = 'eyeslash', + INFO_CIRCLE_SOLID = 'info-circle-solid', + INFO_CIRCLE_OUTLINE = 'info-circle-outline', ARCHIVE = 'archive', - PAPERCLIP = 'paperclip' + PAPERCLIP = 'paperclip', } diff --git a/libs/ui/src/icon/icon.component.html b/libs/ui/src/icon/icon.component.html index e48594e..65bd6cd 100644 --- a/libs/ui/src/icon/icon.component.html +++ b/libs/ui/src/icon/icon.component.html @@ -100,5 +100,13 @@ + + diff --git a/libs/ui/src/multiselect/multiselect.component.ts b/libs/ui/src/multiselect/multiselect.component.ts index 037e8c5..7d01574 100644 --- a/libs/ui/src/multiselect/multiselect.component.ts +++ b/libs/ui/src/multiselect/multiselect.component.ts @@ -38,7 +38,7 @@ interface PropagateTouchedFn { ], }) export class MultiselectComponent implements AfterViewInit, ControlValueAccessor { - @ViewChild(OverlayTriggerForDirective) dropdownRef: OverlayTriggerForDirective; + @ViewChild(OverlayTriggerForDirective) overlayRef: OverlayTriggerForDirective; panelId = `panel-${uuid()}`; @Input() buttonElementId: string = uuid(); @Input() isInvalid = false; @@ -88,7 +88,7 @@ export class MultiselectComponent implements AfterViewInit, ControlValueAccessor // Allows Angular to disable the input. setDisabledState?(isDisabled: boolean): void { this.renderer.setProperty(this.multiselectButton.nativeElement, 'disabled', isDisabled); - this.dropdownRef.closeDropdown(); + this.overlayRef.closeOverlay(); } emitSelectedOptions(selectedOptions: MultiselectFilterOption[]): void { @@ -100,14 +100,14 @@ export class MultiselectComponent implements AfterViewInit, ControlValueAccessor this.selectedOptionsChange.emit(selectedOptions); } - this.dropdownRef.closeDropdown(); + this.overlayRef.closeOverlay(); } ngAfterViewInit(): void { - if (!this.dropdownRef) { + if (!this.overlayRef) { return; } - this.dropdownRef.onOpen(() => { + this.overlayRef.onOpen(() => { // force refresh of selected options if it's reopened this.selectedOptions = [...(this.selectedOptions || [])]; }); diff --git a/libs/ui/src/overlay/overlay-trigger-for.directive.ts b/libs/ui/src/overlay/overlay-trigger-for.directive.ts index de0b79d..f16db37 100644 --- a/libs/ui/src/overlay/overlay-trigger-for.directive.ts +++ b/libs/ui/src/overlay/overlay-trigger-for.directive.ts @@ -1,6 +1,15 @@ -import { ConnectedPosition, Overlay, OverlayRef } from '@angular/cdk/overlay'; +import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { TemplatePortal } from '@angular/cdk/portal'; -import { Directive, ElementRef, HostListener, Input, OnDestroy, ViewContainerRef } from '@angular/core'; +import { + Directive, + ElementRef, + EventEmitter, + HostListener, + Input, + OnDestroy, + Output, + ViewContainerRef, +} from '@angular/core'; import { merge, Observable, Subscription } from 'rxjs'; import { OverlayPanel } from './overlay.model'; @@ -9,6 +18,7 @@ import { OverlayPanel } from './overlay.model'; }) export class OverlayTriggerForDirective implements OnDestroy { @Input() public uiOverlayTriggerFor: OverlayPanel; + @Input() public uiOverlayPositions: ConnectedPosition[] = [ { originX: 'start', @@ -18,6 +28,13 @@ export class OverlayTriggerForDirective implements OnDestroy { offsetY: 3, }, ]; + + /* + * uiOverlayConfig will override uiOverlayPreferredPositions + * */ + @Input() public uiOverlayConfig: OverlayConfig; + + @Output() public uiOverlayRealPositions = new EventEmitter(); private isOverlayOpen = false; public overlayRef: OverlayRef; private overlayClosingActionsSub = Subscription.EMPTY; @@ -30,32 +47,36 @@ export class OverlayTriggerForDirective implements OnDestroy { }; @HostListener('click') onClick(): void { - return this.toggleDropdown(); + return this.toggleOverlay(); } @HostListener('document:keyup.escape', ['$event']) onKeydownHandler(): void { - this.closeDropdown(); + this.closeOverlay(); } constructor( private overlay: Overlay, - private elementRef: ElementRef, + private triggerRef: ElementRef, private viewContainerRef: ViewContainerRef ) {} - toggleDropdown(): void { - this.isOverlayOpen ? this.closeDropdown() : this.openOverlay(); + toggleOverlay(): void { + this.isOverlayOpen ? this.closeOverlay() : this.openOverlay(); } openOverlay(): void { this.isOverlayOpen = true; + + const positionStrategy = this.overlay + .position() + .flexibleConnectedTo(this.triggerRef) + .withPositions(this.uiOverlayPositions); + this.overlayRef = this.overlay.create({ hasBackdrop: true, backdropClass: 'cdk-overlay-transparent-backdrop', scrollStrategy: this.overlay.scrollStrategies.close(), - positionStrategy: this.overlay - .position() - .flexibleConnectedTo(this.elementRef) - .withPositions(this.uiOverlayPositions), + positionStrategy, + ...(this.uiOverlayConfig ?? {}), }); const templatePortal = new TemplatePortal(this.uiOverlayTriggerFor.templateRef, this.viewContainerRef); @@ -63,7 +84,7 @@ export class OverlayTriggerForDirective implements OnDestroy { this.overlayRef.attach(templatePortal); this.onOpenCallback(); - this.overlayClosingActionsSub = this.dropdownClosingActions().subscribe(() => this.closeDropdown()); + this.overlayClosingActionsSub = this.dropdownClosingActions().subscribe(() => this.closeOverlay()); } private dropdownClosingActions(): Observable { @@ -74,7 +95,7 @@ export class OverlayTriggerForDirective implements OnDestroy { return merge(backdropClick$, detachment$, overlayClosed); } - closeDropdown(): void { + closeOverlay(): void { if (!this.overlayRef || !this.isOverlayOpen) { return; } diff --git a/libs/ui/src/popover/ui-popover.component.html b/libs/ui/src/popover/ui-popover.component.html new file mode 100644 index 0000000..16c48a6 --- /dev/null +++ b/libs/ui/src/popover/ui-popover.component.html @@ -0,0 +1,27 @@ +
+ +
+ + +
+ + + +
+ +
+
diff --git a/libs/ui/src/popover/ui-popover.component.scss b/libs/ui/src/popover/ui-popover.component.scss new file mode 100644 index 0000000..400f8b4 --- /dev/null +++ b/libs/ui/src/popover/ui-popover.component.scss @@ -0,0 +1,70 @@ +@import 'libs/styles/src/variables/colors'; +@import 'libs/styles/src/mixins/list'; +@import 'libs/styles/src/variables/gutters'; +@import 'libs/styles/src/variables/shadows'; +@import 'libs/styles/src/variables/z-index'; + +.popover { + margin-left: var(--digi--layout--gutter); + vertical-align: middle; + display: inline-block; + + &__button { + background-color: transparent; + color: var(--digi--typography--color--link); + font-size: var(--digi--typography--font-size--desktop); + border-width: 0; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + color: var(--digi--typography--color--link--active); + } + } + &__button-text { + margin-left: var(--digi--layout--gutter--s); + } + + &__overlay-content { + max-width: var(--digi--typography--text--max-width); + padding: var(--digi--layout--padding--50) var(--digi--layout--padding--20) var(--digi--layout--padding--30); + } + + &__close-button { + position: absolute; + top: var(--digi--layout--gutter); + right: var(--digi--layout--gutter--s); + background: transparent; + border: none; + display: flex; + justify-content: center; + align-items: center; + } + + &__close-button-text { + font-size: var(--digi--typography--font-size--s); + } + + &__container-arrow { + width: u(6); + height: u(6); + position: absolute; + bottom: 100%; + right: 50%; + z-index: $msfa__z-index-popover; + overflow: hidden; + &:after { + content: ''; + position: absolute; + background: #fff; + border-width: u(3); + border-style: solid; + border-color: transparent #fff #fff; + right: 50%; + overflow: hidden; + transform: rotate(45deg); + box-shadow: 0 0 u(0.7) u(0.7) rgb(0 0 0 / 30%); + } + } +} diff --git a/libs/ui/src/popover/ui-popover.component.spec.ts b/libs/ui/src/popover/ui-popover.component.spec.ts new file mode 100644 index 0000000..4c2f5ad --- /dev/null +++ b/libs/ui/src/popover/ui-popover.component.spec.ts @@ -0,0 +1,27 @@ +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { UiPopoverComponent } from './ui-popover.component'; +import { DropdownModule } from '@ui/dropdown/dropdown.module'; + +describe('popoverComponent', () => { + let component: UiPopoverComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DropdownModule], + declarations: [UiPopoverComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UiPopoverComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/ui/src/popover/ui-popover.component.ts b/libs/ui/src/popover/ui-popover.component.ts new file mode 100644 index 0000000..0b265a3 --- /dev/null +++ b/libs/ui/src/popover/ui-popover.component.ts @@ -0,0 +1,96 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + Renderer2, + ViewChild, +} from '@angular/core'; +import { uuid } from '@utils/uuid.util'; +import { OverlayTriggerForDirective } from '@ui/overlay/overlay-trigger-for.directive'; +import { ConnectedPosition } from '@angular/cdk/overlay'; +import { UiIconType } from '@ui/icon/icon-type.enum'; +import { UiIconSize } from '@ui/icon/icon-size.enum'; + +export enum UiPopoverPosition { + Top, + Bottom, +} + +@Component({ + selector: 'ui-popover', + templateUrl: './ui-popover.component.html', + styleUrls: ['./ui-popover.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class UiPopoverComponent implements AfterViewInit { + UiIconType = UiIconType; + UiIconSize = UiIconSize; + @ViewChild(OverlayTriggerForDirective) overlayRef: OverlayTriggerForDirective; + panelId = `panel-${uuid()}`; + @Input() uiAriaLabel: string; + @Input() uiButtonText?: string = 'Info'; + @Input() buttonElementId: string = uuid(); + @Input() uiPopoverPosition: UiPopoverPosition = UiPopoverPosition.Top; + @ViewChild('triggerButton') triggerButton: ElementRef; + @ViewChild('content') content: ElementRef; + @ViewChild('arrow') arrow: ElementRef; + readonly offsetPixels = -30; + + @ViewChild('popoverButton') popoverButton: ElementRef; + + get overlayPositions(): ConnectedPosition[] { + switch (this.uiPopoverPosition) { + case UiPopoverPosition.Top: + return [ + { + originX: 'center', + originY: 'top', + overlayX: 'center', + overlayY: 'bottom', + offsetY: this.offsetPixels, + }, + ]; + case UiPopoverPosition.Bottom: + return [ + { + originX: 'center', + originY: 'bottom', + overlayX: 'center', + overlayY: 'top', + offsetY: -this.offsetPixels, + }, + ]; + } + } + + constructor(private renderer: Renderer2) {} + + closePopover(): void { + this.overlayRef.closeOverlay(); + } + + ngAfterViewInit(): void { + switch (this.uiPopoverPosition) { + case UiPopoverPosition.Top: + this.moveArrowBottom(); + break; + case UiPopoverPosition.Bottom: + this.moveArrowTop(); + break; + default: + throw new Error('uiPopoverPosition is mandatory'); + } + } + + moveArrowBottom() { + this.renderer.setStyle(this.arrow.nativeElement, 'transform', 'rotate(90deg)'); + this.renderer.setStyle(this.arrow.nativeElement, 'bottom', `${this.offsetPixels + 6}px `); + } + + moveArrowTop() { + this.renderer.setStyle(this.arrow.nativeElement, 'transform', 'rotate(-90deg)'); + this.renderer.setStyle(this.arrow.nativeElement, 'top', `${this.offsetPixels + 7}px `); + } +} diff --git a/libs/ui/src/popover/ui-popover.module.ts b/libs/ui/src/popover/ui-popover.module.ts new file mode 100644 index 0000000..2e62f3f --- /dev/null +++ b/libs/ui/src/popover/ui-popover.module.ts @@ -0,0 +1,16 @@ +import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox'; +import { A11yModule } from '@angular/cdk/a11y'; +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { UiOverlayModule } from '@ui/overlay/overlay.module'; +import { UiPopoverComponent } from '@ui/popover/ui-popover.component'; +import { UiIconModule } from '@ui/icon/icon.module'; + +@NgModule({ + declarations: [UiPopoverComponent], + imports: [CommonModule, A11yModule, DigiNgFormCheckboxModule, FormsModule, UiOverlayModule, UiIconModule], + exports: [UiPopoverComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], +}) +export class UiPopoverModule {}