pdm-ui-kit 0.1.0
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.
- package/FIGMA_COMPONENT_AUDIT.md +154 -0
- package/README.md +72 -0
- package/ng-package.json +7 -0
- package/package.json +29 -0
- package/src/lib/components/accordion/accordion.component.html +34 -0
- package/src/lib/components/accordion/accordion.component.ts +38 -0
- package/src/lib/components/alert/alert.component.html +52 -0
- package/src/lib/components/alert/alert.component.ts +25 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.html +41 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.ts +45 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.html +11 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.ts +18 -0
- package/src/lib/components/avatar/avatar.component.html +21 -0
- package/src/lib/components/avatar/avatar.component.ts +32 -0
- package/src/lib/components/badge/badge.component.html +28 -0
- package/src/lib/components/badge/badge.component.ts +23 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.html +39 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.ts +26 -0
- package/src/lib/components/button/button.component.html +15 -0
- package/src/lib/components/button/button.component.ts +84 -0
- package/src/lib/components/button-group/button-group.component.html +39 -0
- package/src/lib/components/button-group/button-group.component.ts +15 -0
- package/src/lib/components/calendar/calendar.component.html +73 -0
- package/src/lib/components/calendar/calendar.component.ts +78 -0
- package/src/lib/components/card/card.component.html +77 -0
- package/src/lib/components/card/card.component.ts +39 -0
- package/src/lib/components/carousel/carousel.component.html +86 -0
- package/src/lib/components/carousel/carousel.component.ts +100 -0
- package/src/lib/components/chart/chart.component.html +143 -0
- package/src/lib/components/chart/chart.component.ts +147 -0
- package/src/lib/components/checkbox/checkbox.component.html +38 -0
- package/src/lib/components/checkbox/checkbox.component.ts +32 -0
- package/src/lib/components/collapsible/collapsible.component.html +26 -0
- package/src/lib/components/collapsible/collapsible.component.ts +29 -0
- package/src/lib/components/combobox/combobox.component.html +42 -0
- package/src/lib/components/combobox/combobox.component.ts +32 -0
- package/src/lib/components/command/command.component.html +55 -0
- package/src/lib/components/command/command.component.ts +67 -0
- package/src/lib/components/context-menu/context-menu.component.html +47 -0
- package/src/lib/components/context-menu/context-menu.component.ts +67 -0
- package/src/lib/components/data-table/data-table.component.html +63 -0
- package/src/lib/components/data-table/data-table.component.ts +78 -0
- package/src/lib/components/date-picker/date-picker.component.html +38 -0
- package/src/lib/components/date-picker/date-picker.component.ts +34 -0
- package/src/lib/components/dialog/dialog.component.html +78 -0
- package/src/lib/components/dialog/dialog.component.ts +55 -0
- package/src/lib/components/drawer/drawer.component.html +56 -0
- package/src/lib/components/drawer/drawer.component.ts +43 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.html +56 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.ts +126 -0
- package/src/lib/components/empty/empty.component.html +29 -0
- package/src/lib/components/empty/empty.component.ts +35 -0
- package/src/lib/components/field/field.component.html +22 -0
- package/src/lib/components/field/field.component.ts +28 -0
- package/src/lib/components/hover-card/hover-card.component.html +24 -0
- package/src/lib/components/hover-card/hover-card.component.ts +36 -0
- package/src/lib/components/icon/icon.component.html +286 -0
- package/src/lib/components/icon/icon.component.ts +133 -0
- package/src/lib/components/input/input.component.html +22 -0
- package/src/lib/components/input/input.component.ts +33 -0
- package/src/lib/components/input-group/input-group.component.html +31 -0
- package/src/lib/components/input-group/input-group.component.ts +26 -0
- package/src/lib/components/input-otp/input-otp.component.html +25 -0
- package/src/lib/components/input-otp/input-otp.component.ts +146 -0
- package/src/lib/components/input-password/input-password.component.html +64 -0
- package/src/lib/components/input-password/input-password.component.ts +46 -0
- package/src/lib/components/item/item.component.html +10 -0
- package/src/lib/components/item/item.component.ts +12 -0
- package/src/lib/components/kbd/kbd.component.html +3 -0
- package/src/lib/components/kbd/kbd.component.ts +10 -0
- package/src/lib/components/label/label.component.html +7 -0
- package/src/lib/components/label/label.component.ts +12 -0
- package/src/lib/components/menubar/menubar.component.html +16 -0
- package/src/lib/components/menubar/menubar.component.ts +29 -0
- package/src/lib/components/native-select/native-select.component.html +17 -0
- package/src/lib/components/native-select/native-select.component.ts +28 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.html +15 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.ts +17 -0
- package/src/lib/components/pagination/pagination.component.html +30 -0
- package/src/lib/components/pagination/pagination.component.ts +37 -0
- package/src/lib/components/popover/popover.component.html +6 -0
- package/src/lib/components/popover/popover.component.ts +40 -0
- package/src/lib/components/progress/progress.component.html +9 -0
- package/src/lib/components/progress/progress.component.ts +20 -0
- package/src/lib/components/radio-group/radio-group.component.html +25 -0
- package/src/lib/components/radio-group/radio-group.component.ts +30 -0
- package/src/lib/components/scroll-area/scroll-area.component.html +5 -0
- package/src/lib/components/scroll-area/scroll-area.component.ts +11 -0
- package/src/lib/components/select/select.component.html +14 -0
- package/src/lib/components/select/select.component.ts +27 -0
- package/src/lib/components/separator/separator.component.html +5 -0
- package/src/lib/components/separator/separator.component.ts +16 -0
- package/src/lib/components/sheet/sheet.component.html +10 -0
- package/src/lib/components/sheet/sheet.component.ts +28 -0
- package/src/lib/components/sidebar/sidebar.component.html +3 -0
- package/src/lib/components/sidebar/sidebar.component.ts +11 -0
- package/src/lib/components/skeleton/skeleton.component.html +1 -0
- package/src/lib/components/skeleton/skeleton.component.ts +10 -0
- package/src/lib/components/slider/slider.component.html +15 -0
- package/src/lib/components/slider/slider.component.ts +31 -0
- package/src/lib/components/sonner/sonner.component.html +10 -0
- package/src/lib/components/sonner/sonner.component.ts +25 -0
- package/src/lib/components/spinner/spinner.component.html +6 -0
- package/src/lib/components/spinner/spinner.component.ts +11 -0
- package/src/lib/components/switch/switch.component.html +14 -0
- package/src/lib/components/switch/switch.component.ts +20 -0
- package/src/lib/components/table/table.component.html +5 -0
- package/src/lib/components/table/table.component.ts +10 -0
- package/src/lib/components/tabs/tabs.component.html +21 -0
- package/src/lib/components/tabs/tabs.component.ts +26 -0
- package/src/lib/components/textarea/textarea.component.html +21 -0
- package/src/lib/components/textarea/textarea.component.ts +28 -0
- package/src/lib/components/toggle/toggle.component.html +16 -0
- package/src/lib/components/toggle/toggle.component.ts +29 -0
- package/src/lib/components/toggle-group/toggle-group.component.html +17 -0
- package/src/lib/components/toggle-group/toggle-group.component.ts +26 -0
- package/src/lib/components/tooltip/tooltip.component.html +6 -0
- package/src/lib/components/tooltip/tooltip.component.ts +20 -0
- package/src/lib/pdm-ui-kit.module.ts +126 -0
- package/src/public-api.ts +58 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<div class="relative inline-block" [ngClass]="className">
|
|
2
|
+
<button
|
|
3
|
+
type="button"
|
|
4
|
+
class="inline-flex h-9 items-center justify-center rounded-[10px] border border-[#e5e5e5] bg-white px-4 text-[14px] font-medium text-[#0a0a0a] shadow-[0_1px_2px_rgba(0,0,0,0.1)]"
|
|
5
|
+
[attr.aria-expanded]="open"
|
|
6
|
+
(click)="toggle()"
|
|
7
|
+
>
|
|
8
|
+
{{ triggerText }}
|
|
9
|
+
</button>
|
|
10
|
+
|
|
11
|
+
<div
|
|
12
|
+
*ngIf="open"
|
|
13
|
+
[ngClass]="[
|
|
14
|
+
'absolute left-0 top-full z-50 mt-2 min-w-[224px] overflow-hidden rounded-[8px] border border-[#e5e5e5] bg-white p-1 text-[#0a0a0a] shadow-[0_2px_4px_-2px_rgba(0,0,0,0.1),0_4px_6px_-1px_rgba(0,0,0,0.1)]',
|
|
15
|
+
panelClassName
|
|
16
|
+
]"
|
|
17
|
+
>
|
|
18
|
+
<ng-container *ngFor="let item of resolvedItems">
|
|
19
|
+
<div *ngIf="item.type === 'separator'" class="my-[5px] h-px bg-[#f1f5f9]"></div>
|
|
20
|
+
|
|
21
|
+
<div
|
|
22
|
+
*ngIf="item.type === 'label'"
|
|
23
|
+
[ngClass]="['px-2 py-1.5 text-[14px] font-semibold leading-5 text-[#0a0a0a]', item.inset ? 'pl-8' : '']"
|
|
24
|
+
>
|
|
25
|
+
{{ item.label }}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<button
|
|
29
|
+
*ngIf="!item.type || item.type === 'item'"
|
|
30
|
+
type="button"
|
|
31
|
+
[disabled]="item.disabled"
|
|
32
|
+
[ngClass]="[
|
|
33
|
+
'relative flex w-full items-center gap-2 rounded-[6px] px-2 py-1.5 text-left text-[14px] leading-5 text-[#0a0a0a] transition-colors hover:bg-[#f5f5f5] disabled:pointer-events-none disabled:opacity-50',
|
|
34
|
+
item.inset ? 'pl-8' : ''
|
|
35
|
+
]"
|
|
36
|
+
(click)="select(item)"
|
|
37
|
+
>
|
|
38
|
+
<span class="inline-flex h-4 w-4 shrink-0 items-center justify-center">
|
|
39
|
+
<svg
|
|
40
|
+
*ngIf="item.checked"
|
|
41
|
+
viewBox="0 0 24 24"
|
|
42
|
+
class="h-3.5 w-3.5 text-[#0a0a0a]"
|
|
43
|
+
fill="none"
|
|
44
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
45
|
+
>
|
|
46
|
+
<path d="M5 12.5L9.2 16.7L19 7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
47
|
+
</svg>
|
|
48
|
+
<span *ngIf="item.radioSelected" class="h-2 w-2 rounded-full bg-[#0a0a0a]"></span>
|
|
49
|
+
</span>
|
|
50
|
+
<span class="min-w-0 flex-1 truncate">{{ item.label }}</span>
|
|
51
|
+
<span *ngIf="item.shortcut" class="text-[12px] leading-5 text-[#64748b]">{{ item.shortcut }}</span>
|
|
52
|
+
<span *ngIf="item.showChevron" class="text-[16px] leading-none text-[#475569]">›</span>
|
|
53
|
+
</button>
|
|
54
|
+
</ng-container>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmDropdownMenuVariant = 'default' | 'checkboxes' | 'radio-group';
|
|
4
|
+
|
|
5
|
+
export interface PdmMenuItem {
|
|
6
|
+
type?: 'item' | 'label' | 'separator';
|
|
7
|
+
label?: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
inset?: boolean;
|
|
12
|
+
showChevron?: boolean;
|
|
13
|
+
checked?: boolean;
|
|
14
|
+
radioSelected?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@Component({
|
|
18
|
+
selector: 'pdm-dropdown-menu',
|
|
19
|
+
templateUrl: './dropdown-menu.component.html',
|
|
20
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
21
|
+
})
|
|
22
|
+
export class PdmDropdownMenuComponent {
|
|
23
|
+
@Input() triggerText = 'Open';
|
|
24
|
+
@Input() variant: PdmDropdownMenuVariant = 'default';
|
|
25
|
+
@Input() items: PdmMenuItem[] = [];
|
|
26
|
+
@Input() closeOnSelect = true;
|
|
27
|
+
@Input() panelClassName = '';
|
|
28
|
+
@Input() className = '';
|
|
29
|
+
|
|
30
|
+
@Output() itemSelect = new EventEmitter<string>();
|
|
31
|
+
@Output() itemsChange = new EventEmitter<PdmMenuItem[]>();
|
|
32
|
+
|
|
33
|
+
open = false;
|
|
34
|
+
|
|
35
|
+
constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
|
|
36
|
+
|
|
37
|
+
toggle(): void {
|
|
38
|
+
this.open = !this.open;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get resolvedItems(): PdmMenuItem[] {
|
|
42
|
+
if (this.items.length) {
|
|
43
|
+
return this.items;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (this.variant === 'checkboxes') {
|
|
47
|
+
return [
|
|
48
|
+
{ type: 'label', label: 'Appearance' },
|
|
49
|
+
{ type: 'separator' },
|
|
50
|
+
{ type: 'item', label: 'Status Bar', value: 'status-bar', checked: true },
|
|
51
|
+
{ type: 'item', label: 'Activity Bar', value: 'activity-bar', checked: false },
|
|
52
|
+
{ type: 'item', label: 'Panel', value: 'panel', checked: false }
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (this.variant === 'radio-group') {
|
|
57
|
+
return [
|
|
58
|
+
{ type: 'label', label: 'Panel Position' },
|
|
59
|
+
{ type: 'separator' },
|
|
60
|
+
{ type: 'item', label: 'Top', value: 'top', radioSelected: true },
|
|
61
|
+
{ type: 'item', label: 'Bottom', value: 'bottom', radioSelected: false },
|
|
62
|
+
{ type: 'item', label: 'Right', value: 'right', radioSelected: false }
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return [
|
|
67
|
+
{ type: 'label', label: 'My Account', inset: true },
|
|
68
|
+
{ type: 'separator' },
|
|
69
|
+
{ type: 'item', label: 'Profile', value: 'profile', shortcut: '⇧⌘P' },
|
|
70
|
+
{ type: 'item', label: 'Billing', value: 'billing', shortcut: '⌘B' },
|
|
71
|
+
{ type: 'item', label: 'Settings', value: 'settings', shortcut: '⌘S' },
|
|
72
|
+
{ type: 'item', label: 'Keyboard shortcuts', value: 'shortcuts', shortcut: '⌘K' },
|
|
73
|
+
{ type: 'separator' },
|
|
74
|
+
{ type: 'item', label: 'Team', value: 'team' },
|
|
75
|
+
{ type: 'item', label: 'Invite users', value: 'invite', showChevron: true },
|
|
76
|
+
{ type: 'item', label: 'New Team', value: 'new-team', shortcut: '⌘+T' },
|
|
77
|
+
{ type: 'separator' },
|
|
78
|
+
{ type: 'item', label: 'GitHub', value: 'github' },
|
|
79
|
+
{ type: 'item', label: 'Support', value: 'support' },
|
|
80
|
+
{ type: 'item', label: 'API', value: 'api', disabled: true },
|
|
81
|
+
{ type: 'separator' },
|
|
82
|
+
{ type: 'item', label: 'Log out', value: 'logout', shortcut: '⇧⌘Q' }
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
select(item: PdmMenuItem): void {
|
|
87
|
+
if (item.disabled || item.type === 'separator' || item.type === 'label' || !item.value) return;
|
|
88
|
+
|
|
89
|
+
if (this.variant === 'checkboxes') {
|
|
90
|
+
const updated = this.resolvedItems.map((entry) =>
|
|
91
|
+
entry.value === item.value ? { ...entry, checked: !entry.checked } : entry
|
|
92
|
+
);
|
|
93
|
+
this.itemsChange.emit(updated);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (this.variant === 'radio-group') {
|
|
97
|
+
const updated = this.resolvedItems.map((entry) =>
|
|
98
|
+
entry.type === 'item'
|
|
99
|
+
? { ...entry, radioSelected: entry.value === item.value }
|
|
100
|
+
: entry
|
|
101
|
+
);
|
|
102
|
+
this.itemsChange.emit(updated);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.itemSelect.emit(item.value);
|
|
106
|
+
|
|
107
|
+
const shouldClose = this.variant === 'default' ? this.closeOnSelect : false;
|
|
108
|
+
if (shouldClose) {
|
|
109
|
+
this.open = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@HostListener('document:keydown.escape')
|
|
114
|
+
onEsc(): void {
|
|
115
|
+
this.open = false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@HostListener('document:click', ['$event'])
|
|
119
|
+
onDocumentClick(event: MouseEvent): void {
|
|
120
|
+
if (!this.open) return;
|
|
121
|
+
const target = event.target as Node | null;
|
|
122
|
+
if (target && !this.elementRef.nativeElement.contains(target)) {
|
|
123
|
+
this.open = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<section [ngClass]="['flex flex-col items-center justify-center gap-4 px-6 py-10 text-center text-[hsl(var(--foreground))]', containerClass, className]">
|
|
2
|
+
<div class="flex h-10 w-10 items-center justify-center rounded-[10px] bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]">
|
|
3
|
+
<pdm-icon [name]="iconName" [size]="20"></pdm-icon>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="space-y-2">
|
|
7
|
+
<h3 class="text-2xl font-semibold leading-none tracking-tight">{{ title }}</h3>
|
|
8
|
+
<p class="mx-auto max-w-[420px] text-sm leading-relaxed text-[hsl(var(--muted-foreground))]">
|
|
9
|
+
{{ description }}
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div *ngIf="primaryActionLabel || secondaryActionLabel" class="mt-1 flex flex-wrap items-center justify-center gap-3">
|
|
14
|
+
<pdm-button *ngIf="primaryActionLabel" variant="default" (pressed)="primaryAction.emit()">{{ primaryActionLabel }}</pdm-button>
|
|
15
|
+
<pdm-button *ngIf="secondaryActionLabel" variant="outline" (pressed)="secondaryAction.emit()">{{ secondaryActionLabel }}</pdm-button>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<button
|
|
19
|
+
*ngIf="linkLabel"
|
|
20
|
+
type="button"
|
|
21
|
+
class="mt-1 inline-flex items-center gap-2 text-[15px] font-medium text-[hsl(var(--muted-foreground))] underline-offset-4 hover:underline"
|
|
22
|
+
(click)="linkAction.emit()"
|
|
23
|
+
>
|
|
24
|
+
<span>{{ linkLabel }}</span>
|
|
25
|
+
<pdm-icon name="arrow-up-right" [size]="16"></pdm-icon>
|
|
26
|
+
</button>
|
|
27
|
+
|
|
28
|
+
<ng-content></ng-content>
|
|
29
|
+
</section>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmEmptyVariant = 'default' | 'outline' | 'background';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-empty',
|
|
7
|
+
templateUrl: './empty.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmEmptyComponent {
|
|
11
|
+
@Input() variant: PdmEmptyVariant = 'default';
|
|
12
|
+
@Input() title = 'No Projects Yet';
|
|
13
|
+
@Input() description = "You haven't created any projects yet. Get started by creating your first project.";
|
|
14
|
+
@Input() iconName = 'folder';
|
|
15
|
+
@Input() primaryActionLabel = '';
|
|
16
|
+
@Input() secondaryActionLabel = '';
|
|
17
|
+
@Input() linkLabel = '';
|
|
18
|
+
@Input() className = '';
|
|
19
|
+
|
|
20
|
+
@Output() primaryAction = new EventEmitter<void>();
|
|
21
|
+
@Output() secondaryAction = new EventEmitter<void>();
|
|
22
|
+
@Output() linkAction = new EventEmitter<void>();
|
|
23
|
+
|
|
24
|
+
get containerClass(): string {
|
|
25
|
+
if (this.variant === 'outline') {
|
|
26
|
+
return 'border border-dashed border-[hsl(var(--border))] rounded-[12px]';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (this.variant === 'background') {
|
|
30
|
+
return 'rounded-[12px] bg-[hsl(var(--muted))]';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<div [ngClass]="[rootClass, className]">
|
|
2
|
+
<div class="grid gap-2">
|
|
3
|
+
<label
|
|
4
|
+
*ngIf="label"
|
|
5
|
+
[attr.for]="id"
|
|
6
|
+
[ngClass]="['text-sm font-medium leading-5 text-[hsl(var(--foreground))]', disabled ? 'opacity-70' : '', labelClassName]"
|
|
7
|
+
>
|
|
8
|
+
{{ label }}
|
|
9
|
+
<span *ngIf="required" class="text-[hsl(var(--destructive))]">*</span>
|
|
10
|
+
</label>
|
|
11
|
+
|
|
12
|
+
<p *ngIf="description && !invalid" class="text-sm leading-5 text-[hsl(var(--muted-foreground))]">{{ description }}</p>
|
|
13
|
+
<p *ngIf="invalid && error" class="text-sm leading-5 text-[hsl(var(--destructive))]">{{ error }}</p>
|
|
14
|
+
|
|
15
|
+
<ng-content select="[pdmFieldDescription]"></ng-content>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div [ngClass]="controlClassName">
|
|
19
|
+
<ng-content></ng-content>
|
|
20
|
+
<ng-content select="[pdmFieldControl]"></ng-content>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmFieldOrientation = 'vertical' | 'horizontal';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-field',
|
|
7
|
+
templateUrl: './field.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmFieldComponent {
|
|
11
|
+
@Input() id = '';
|
|
12
|
+
@Input() label = '';
|
|
13
|
+
@Input() description = '';
|
|
14
|
+
@Input() error = '';
|
|
15
|
+
@Input() required = false;
|
|
16
|
+
@Input() disabled = false;
|
|
17
|
+
@Input() invalid = false;
|
|
18
|
+
@Input() orientation: PdmFieldOrientation = 'vertical';
|
|
19
|
+
@Input() className = '';
|
|
20
|
+
@Input() labelClassName = '';
|
|
21
|
+
@Input() controlClassName = '';
|
|
22
|
+
|
|
23
|
+
get rootClass(): string {
|
|
24
|
+
return this.orientation === 'horizontal'
|
|
25
|
+
? 'grid items-start gap-3 sm:grid-cols-[200px_minmax(0,1fr)] sm:gap-4'
|
|
26
|
+
: 'grid w-full gap-3';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="relative inline-flex"
|
|
3
|
+
[ngClass]="className"
|
|
4
|
+
(mouseenter)="open = true"
|
|
5
|
+
(mouseleave)="open = false"
|
|
6
|
+
(focusin)="open = true"
|
|
7
|
+
(focusout)="open = false"
|
|
8
|
+
>
|
|
9
|
+
<div>
|
|
10
|
+
<ng-content select="[pdmHoverTrigger]"></ng-content>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<section
|
|
14
|
+
*ngIf="open"
|
|
15
|
+
[style.width.px]="panelWidth"
|
|
16
|
+
[ngClass]="[
|
|
17
|
+
'absolute z-30 rounded-[10px] border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-4 text-[hsl(var(--popover-foreground))] shadow-[0_10px_30px_rgba(15,23,42,0.15)]',
|
|
18
|
+
positionClass,
|
|
19
|
+
panelClassName
|
|
20
|
+
]"
|
|
21
|
+
>
|
|
22
|
+
<ng-content select="[pdmHoverContent]"></ng-content>
|
|
23
|
+
</section>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmHoverCardSide = 'top' | 'right' | 'bottom' | 'left';
|
|
4
|
+
export type PdmHoverCardAlign = 'start' | 'center' | 'end';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'pdm-hover-card',
|
|
8
|
+
templateUrl: './hover-card.component.html',
|
|
9
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
10
|
+
})
|
|
11
|
+
export class PdmHoverCardComponent {
|
|
12
|
+
@Input() className = '';
|
|
13
|
+
@Input() panelClassName = '';
|
|
14
|
+
@Input() side: PdmHoverCardSide = 'bottom';
|
|
15
|
+
@Input() align: PdmHoverCardAlign = 'start';
|
|
16
|
+
@Input() panelWidth = 304;
|
|
17
|
+
|
|
18
|
+
open = false;
|
|
19
|
+
|
|
20
|
+
get positionClass(): string {
|
|
21
|
+
const sideClassMap: Record<PdmHoverCardSide, string> = {
|
|
22
|
+
top: 'bottom-full mb-2',
|
|
23
|
+
right: 'left-full ml-2',
|
|
24
|
+
bottom: 'top-full mt-2',
|
|
25
|
+
left: 'right-full mr-2'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const alignClassMap: Record<PdmHoverCardAlign, string> = {
|
|
29
|
+
start: this.side === 'top' || this.side === 'bottom' ? 'left-0' : 'top-0',
|
|
30
|
+
center: this.side === 'top' || this.side === 'bottom' ? 'left-1/2 -translate-x-1/2' : 'top-1/2 -translate-y-1/2',
|
|
31
|
+
end: this.side === 'top' || this.side === 'bottom' ? 'right-0' : 'bottom-0'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return `${sideClassMap[this.side]} ${alignClassMap[this.align]}`;
|
|
35
|
+
}
|
|
36
|
+
}
|