feat: refactor dialog components to use light-bottomsheet for improved UX

- Replaced SharedDialogComponent with SharedLightBottomsheetComponent in customer-dialog, order-submitted-dialog, payment form-dialog, and pre-invoice-dialog components.
- Updated styles and properties for light-bottomsheet to enhance responsiveness and usability.
- Modified payload form components to use measure units instead of unit types for better clarity.
- Adjusted form controls to use consistent naming conventions for amounts and percentages.
- Enhanced support for overlay options in select components to manage z-index dynamically.
- Improved support for RTL layouts in input groups and other components.
This commit is contained in:
2026-05-13 13:44:33 +03:30
parent dba960c454
commit 42b8476b96
39 changed files with 396 additions and 143 deletions
@@ -24,8 +24,8 @@
[attr.name]="name"
[attr.placeholder]="placeholder"
[attr.autocomplete]="autocomplete"
[class]="` w-full hasSuffix text-left ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
dir="ltr"
[inputStyle]="{ direction: 'ltr' }"
[inputStyleClass]="` w-full hasSuffix text-left ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
[required]="required"
[invalid]="amountControl.invalid && (amountControl.touched || amountControl.dirty)"
(onInput)="onPriceInput($event)"
@@ -58,9 +58,10 @@
<p-select
[formControl]="selectedType"
[options]="typeSelectOptions"
tabindex="-1"
optionValue="value"
size="small"
class="border-0!"
class="border-none! shadow-none! w-full!"
/>
</p-inputgroup-addon>
</p-inputgroup>
@@ -180,11 +180,16 @@ export class AmountPercentageInputComponent {
const amountValue = Number(this.amountControl.value || 0);
const percentageValue = Number(this.percentageControl.value || 0);
const isPercentageType = percentageValue > 0 && amountValue <= 0;
console.log(amountValue, percentageValue, isPercentageType);
this.preparedLabel.set(this.prepareLabel(isPercentageType));
this.selectedType.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
this.preparedLabel.set(this.prepareLabel(value === 'percentage'));
});
this.selectedType.setValue(isPercentageType ? 'percentage' : 'amount');
}
ngOnChanges() {
@@ -1,6 +1,6 @@
<div class="flex flex-col gap-2">
<div class="flex items-center gap-3">
<p-checkBox [formControl]="control" [name]="name" [id]="name" binary class="shrink-0"> </p-checkBox>
<p-checkBox [formControl]="control" [name]="name" [inputId]="name" binary class="shrink-0"> </p-checkBox>
<uikit-label [name]="name"> {{ label }} </uikit-label>
</div>
@@ -1,20 +1,21 @@
<div class="light-bottomsheet-mask" (click)="onMaskClick()"></div>
<section
class="light-bottomsheet-panel"
role="dialog"
aria-modal="true"
[attr.aria-hidden]="!visible"
[ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }"
>
<section class="light-bottomsheet-panel" [ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }">
<div class="light-bottomsheet-content">
@if (header || closable) {
<header class="light-bottomsheet-header">
<h3 class="light-bottomsheet-title">{{ header }}</h3>
<span class="text-xl font-bold">{{ header }}</span>
@if (closable) {
<button type="button" class="light-bottomsheet-close" (click)="onVisibilityChange(false)" aria-label="Close">
×
</button>
<p-button
type="button"
icon="pi pi-times"
text
size="small"
class="light-bottomsheet-close"
(click)="onVisibilityChange(false)"
aria-label="Close"
>
</p-button>
}
</header>
}
@@ -1,27 +1,29 @@
import { NgStyle } from '@angular/common';
import { DOCUMENT } from '@angular/common';
import { DOCUMENT, NgStyle } from '@angular/common';
import {
Component,
ElementRef,
EventEmitter,
Inject,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
Renderer2,
SimpleChanges,
} from '@angular/core';
import { Button } from 'primeng/button';
@Component({
selector: 'shared-light-bottomsheet',
templateUrl: './light-bottomsheet.component.html',
imports: [NgStyle],
imports: [NgStyle, Button],
styles: [
`
:host {
position: fixed;
inset: 0;
z-index: 11020;
z-index: 1210;
}
.light-bottomsheet-mask {
@@ -66,8 +68,6 @@ import {
.light-bottomsheet-title {
margin: 0;
font-size: 0.95rem;
font-weight: 600;
}
.light-bottomsheet-close {
@@ -98,11 +98,17 @@ import {
`,
],
host: {
'[attr.role]': '"complementary"',
'[attr.aria-modal]': 'true',
'[attr.pfocustrap]': 'true',
'[attr.data-pc-name]': "'drawer'",
'[attr.data-pc-section]': "'root'",
'[attr.aria-hidden]': '!visible',
'[style.display]': 'visible ? "block" : "none"',
'[style.--sheet-transition]': 'transitionOptions',
},
})
export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnChanges {
@Input() header = '';
@Input() visible = false;
@Output() visibleChange = new EventEmitter<boolean>();
@@ -116,6 +122,7 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
@Output() onHide = new EventEmitter<any>();
private originalParent: Node | null = null;
private readonly defaultDrawerZIndex = 1102;
constructor(
private readonly elementRef: ElementRef<HTMLElement>,
@@ -127,9 +134,20 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
const host = this.elementRef.nativeElement;
this.originalParent = host.parentNode;
this.renderer.appendChild(this.document.body, host);
this.syncZIndex();
}
ngOnChanges(changes: SimpleChanges) {
if (changes['visible'] && this.visible) {
this.syncZIndex();
}
}
ngOnDestroy() {
this.removeDrawer();
}
private removeDrawer() {
const host = this.elementRef.nativeElement;
if (this.originalParent) {
this.renderer.appendChild(this.originalParent, host);
@@ -139,6 +157,9 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
onVisibilityChange(nextValue: boolean) {
this.visible = nextValue;
this.visibleChange.emit(nextValue);
if (nextValue) {
this.syncZIndex();
}
if (!nextValue) {
this.onHide.emit();
}
@@ -149,4 +170,19 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
this.onVisibilityChange(false);
}
}
private syncZIndex() {
const host = this.elementRef.nativeElement;
const siblingDrawers = Array.from(
this.document.body.querySelectorAll('.p-drawer'),
) as HTMLElement[];
const drawerZIndexes = siblingDrawers
.map((drawer) => Number.parseInt(drawer.style.zIndex || '0', 10))
.filter((zIndex) => Number.isFinite(zIndex) && zIndex > 0);
const maxDrawerZIndex = drawerZIndexes.length
? Math.max(...drawerZIndexes)
: this.defaultDrawerZIndex;
this.renderer.setStyle(host, 'z-index', `${maxDrawerZIndex + 1}`);
}
}