@sonny-ui/core 0.1.0-alpha.2 → 0.1.0-alpha.20
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/README.md +187 -40
- package/fesm2022/sonny-ui-core.mjs +6642 -268
- package/fesm2022/sonny-ui-core.mjs.map +1 -1
- package/package.json +8 -5
- package/schematics/ng-add/index.js +27 -0
- package/schematics/ng-add/schema.json +1 -1
- package/schematics/ng-generate/component/index.js +182 -1
- package/schematics/ng-generate/component/schema.json +2 -2
- package/src/lib/accordion/accordion.directives.spec.ts +173 -0
- package/src/lib/accordion/accordion.directives.ts +143 -0
- package/src/lib/accordion/index.ts +8 -0
- package/src/lib/alert/alert.directives.spec.ts +154 -0
- package/src/lib/alert/alert.directives.ts +67 -0
- package/src/lib/alert/alert.variants.ts +25 -0
- package/src/lib/alert/index.ts +6 -0
- package/src/lib/avatar/avatar.component.spec.ts +75 -0
- package/src/lib/avatar/avatar.component.ts +43 -0
- package/src/lib/avatar/avatar.variants.ts +26 -0
- package/src/lib/avatar/index.ts +2 -0
- package/src/lib/avatar-group/avatar-group.component.spec.ts +74 -0
- package/src/lib/avatar-group/avatar-group.component.ts +88 -0
- package/src/lib/avatar-group/index.ts +1 -0
- package/src/lib/badge/badge.directive.spec.ts +74 -0
- package/src/lib/badge/badge.directive.ts +17 -0
- package/src/lib/badge/badge.variants.ts +29 -0
- package/src/lib/badge/index.ts +2 -0
- package/src/lib/breadcrumb/breadcrumb.directives.spec.ts +80 -0
- package/src/lib/breadcrumb/breadcrumb.directives.ts +78 -0
- package/src/lib/breadcrumb/index.ts +8 -0
- package/src/lib/button/button.directive.spec.ts +92 -0
- package/src/lib/button/button.directive.ts +28 -0
- package/src/lib/button/button.variants.ts +30 -0
- package/src/lib/button/index.ts +2 -0
- package/src/lib/button-group/button-group.directive.spec.ts +46 -0
- package/src/lib/button-group/button-group.directive.ts +19 -0
- package/src/lib/button-group/button-group.variants.ts +18 -0
- package/src/lib/button-group/index.ts +2 -0
- package/src/lib/calendar/calendar.component.spec.ts +192 -0
- package/src/lib/calendar/calendar.component.ts +342 -0
- package/src/lib/calendar/calendar.types.ts +24 -0
- package/src/lib/calendar/index.ts +7 -0
- package/src/lib/card/card.directives.spec.ts +104 -0
- package/src/lib/card/card.directives.ts +72 -0
- package/src/lib/card/card.variants.ts +28 -0
- package/src/lib/card/index.ts +9 -0
- package/src/lib/carousel/carousel.directives.spec.ts +85 -0
- package/src/lib/carousel/carousel.directives.ts +159 -0
- package/src/lib/carousel/index.ts +8 -0
- package/src/lib/chat-bubble/chat-bubble.directives.spec.ts +52 -0
- package/src/lib/chat-bubble/chat-bubble.directives.ts +96 -0
- package/src/lib/chat-bubble/index.ts +11 -0
- package/src/lib/checkbox/checkbox.directive.spec.ts +57 -0
- package/src/lib/checkbox/checkbox.directive.ts +16 -0
- package/src/lib/checkbox/checkbox.variants.ts +19 -0
- package/src/lib/checkbox/index.ts +2 -0
- package/src/lib/color-picker/color-picker.component.spec.ts +328 -0
- package/src/lib/color-picker/color-picker.component.ts +537 -0
- package/src/lib/color-picker/color-picker.types.ts +24 -0
- package/src/lib/color-picker/color-picker.utils.ts +183 -0
- package/src/lib/color-picker/color-picker.variants.ts +17 -0
- package/src/lib/color-picker/index.ts +20 -0
- package/src/lib/combobox/combobox.component.spec.ts +151 -0
- package/src/lib/combobox/combobox.component.ts +264 -0
- package/src/lib/combobox/combobox.variants.ts +19 -0
- package/src/lib/combobox/index.ts +2 -0
- package/src/lib/command-palette/command-palette.component.spec.ts +178 -0
- package/src/lib/command-palette/command-palette.component.ts +194 -0
- package/src/lib/command-palette/command-palette.service.ts +36 -0
- package/src/lib/command-palette/command-palette.types.ts +23 -0
- package/src/lib/command-palette/index.ts +7 -0
- package/src/lib/data-table/data-table.component.spec.ts +443 -0
- package/src/lib/data-table/data-table.component.ts +602 -0
- package/src/lib/data-table/data-table.directives.ts +31 -0
- package/src/lib/data-table/data-table.types.ts +20 -0
- package/src/lib/data-table/index.ts +13 -0
- package/src/lib/date-picker/date-picker.component.spec.ts +131 -0
- package/src/lib/date-picker/date-picker.component.ts +220 -0
- package/src/lib/date-picker/date-picker.variants.ts +17 -0
- package/src/lib/date-picker/index.ts +2 -0
- package/src/lib/date-range-picker/date-range-picker.component.spec.ts +151 -0
- package/src/lib/date-range-picker/date-range-picker.component.ts +340 -0
- package/src/lib/date-range-picker/index.ts +1 -0
- package/src/lib/diff/diff.component.spec.ts +47 -0
- package/src/lib/diff/diff.component.ts +82 -0
- package/src/lib/diff/index.ts +1 -0
- package/src/lib/divider/divider.component.spec.ts +48 -0
- package/src/lib/divider/divider.component.ts +51 -0
- package/src/lib/divider/divider.variants.ts +22 -0
- package/src/lib/divider/index.ts +2 -0
- package/src/lib/dock/dock.directives.spec.ts +85 -0
- package/src/lib/dock/dock.directives.ts +81 -0
- package/src/lib/dock/index.ts +1 -0
- package/src/lib/drawer/drawer.directives.spec.ts +62 -0
- package/src/lib/drawer/drawer.directives.ts +80 -0
- package/src/lib/drawer/index.ts +8 -0
- package/src/lib/dropdown/dropdown.directives.spec.ts +106 -0
- package/src/lib/dropdown/dropdown.directives.ts +136 -0
- package/src/lib/dropdown/dropdown.variants.ts +27 -0
- package/src/lib/dropdown/index.ts +15 -0
- package/src/lib/fab/fab.directives.spec.ts +60 -0
- package/src/lib/fab/fab.directives.ts +77 -0
- package/src/lib/fab/index.ts +8 -0
- package/src/lib/fieldset/fieldset.directives.spec.ts +74 -0
- package/src/lib/fieldset/fieldset.directives.ts +49 -0
- package/src/lib/fieldset/fieldset.variants.ts +15 -0
- package/src/lib/fieldset/index.ts +6 -0
- package/src/lib/file-input/file-input.component.spec.ts +114 -0
- package/src/lib/file-input/file-input.component.ts +155 -0
- package/src/lib/file-input/file-input.variants.ts +25 -0
- package/src/lib/file-input/index.ts +6 -0
- package/src/lib/indicator/index.ts +6 -0
- package/src/lib/indicator/indicator.directives.spec.ts +64 -0
- package/src/lib/indicator/indicator.directives.ts +59 -0
- package/src/lib/input/index.ts +3 -0
- package/src/lib/input/input.directive.spec.ts +103 -0
- package/src/lib/input/input.directive.ts +25 -0
- package/src/lib/input/input.variants.ts +42 -0
- package/src/lib/input/label.directive.ts +16 -0
- package/src/lib/kbd/index.ts +2 -0
- package/src/lib/kbd/kbd.directive.spec.ts +42 -0
- package/src/lib/kbd/kbd.directive.ts +18 -0
- package/src/lib/kbd/kbd.variants.ts +19 -0
- package/src/lib/link/index.ts +2 -0
- package/src/lib/link/link.directive.spec.ts +41 -0
- package/src/lib/link/link.directive.ts +18 -0
- package/src/lib/link/link.variants.ts +20 -0
- package/src/lib/list/index.ts +8 -0
- package/src/lib/list/list.directives.spec.ts +65 -0
- package/src/lib/list/list.directives.ts +81 -0
- package/src/lib/loader/index.ts +2 -0
- package/src/lib/loader/loader.component.spec.ts +58 -0
- package/src/lib/loader/loader.component.ts +47 -0
- package/src/lib/loader/loader.variants.ts +21 -0
- package/src/lib/modal/dialog-ref.ts +19 -0
- package/src/lib/modal/dialog.directives.ts +84 -0
- package/src/lib/modal/dialog.service.spec.ts +52 -0
- package/src/lib/modal/dialog.service.ts +61 -0
- package/src/lib/modal/dialog.types.ts +16 -0
- package/src/lib/modal/index.ts +11 -0
- package/src/lib/navbar/index.ts +7 -0
- package/src/lib/navbar/navbar.directives.spec.ts +59 -0
- package/src/lib/navbar/navbar.directives.ts +57 -0
- package/src/lib/number-input/index.ts +2 -0
- package/src/lib/number-input/number-input.component.spec.ts +151 -0
- package/src/lib/number-input/number-input.component.ts +152 -0
- package/src/lib/number-input/number-input.variants.ts +17 -0
- package/src/lib/otp-input/index.ts +2 -0
- package/src/lib/otp-input/otp-input.component.spec.ts +252 -0
- package/src/lib/otp-input/otp-input.component.ts +274 -0
- package/src/lib/otp-input/otp-input.variants.ts +18 -0
- package/src/lib/pagination/index.ts +6 -0
- package/src/lib/pagination/pagination.component.spec.ts +59 -0
- package/src/lib/pagination/pagination.component.ts +143 -0
- package/src/lib/pagination/pagination.variants.ts +31 -0
- package/src/lib/popover/index.ts +6 -0
- package/src/lib/popover/popover.directives.spec.ts +147 -0
- package/src/lib/popover/popover.directives.ts +151 -0
- package/src/lib/progress/index.ts +7 -0
- package/src/lib/progress/progress.component.spec.ts +117 -0
- package/src/lib/progress/progress.component.ts +64 -0
- package/src/lib/progress/progress.variants.ts +43 -0
- package/src/lib/radial-progress/index.ts +5 -0
- package/src/lib/radial-progress/radial-progress.component.spec.ts +41 -0
- package/src/lib/radial-progress/radial-progress.component.ts +70 -0
- package/src/lib/radio/index.ts +2 -0
- package/src/lib/radio/radio.directive.spec.ts +46 -0
- package/src/lib/radio/radio.directive.ts +16 -0
- package/src/lib/radio/radio.variants.ts +19 -0
- package/src/lib/rating/index.ts +2 -0
- package/src/lib/rating/rating.component.spec.ts +157 -0
- package/src/lib/rating/rating.component.ts +163 -0
- package/src/lib/rating/rating.variants.ts +20 -0
- package/src/lib/select/index.ts +2 -0
- package/src/lib/select/select.component.spec.ts +112 -0
- package/src/lib/select/select.component.ts +235 -0
- package/src/lib/select/select.variants.ts +19 -0
- package/src/lib/sheet/index.ts +10 -0
- package/src/lib/sheet/sheet-ref.ts +18 -0
- package/src/lib/sheet/sheet.component.spec.ts +67 -0
- package/src/lib/sheet/sheet.directives.ts +70 -0
- package/src/lib/sheet/sheet.service.ts +100 -0
- package/src/lib/sheet/sheet.types.ts +23 -0
- package/src/lib/skeleton/index.ts +2 -0
- package/src/lib/skeleton/skeleton.directive.spec.ts +63 -0
- package/src/lib/skeleton/skeleton.directive.ts +21 -0
- package/src/lib/skeleton/skeleton.variants.ts +27 -0
- package/src/lib/slider/index.ts +2 -0
- package/src/lib/slider/slider.component.spec.ts +104 -0
- package/src/lib/slider/slider.component.ts +181 -0
- package/src/lib/slider/slider.variants.ts +25 -0
- package/src/lib/stat/index.ts +8 -0
- package/src/lib/stat/stat.directives.spec.ts +60 -0
- package/src/lib/stat/stat.directives.ts +79 -0
- package/src/lib/status/index.ts +2 -0
- package/src/lib/status/status.directive.spec.ts +43 -0
- package/src/lib/status/status.directive.ts +37 -0
- package/src/lib/status/status.variants.ts +26 -0
- package/src/lib/steps/index.ts +8 -0
- package/src/lib/steps/steps.directives.spec.ts +52 -0
- package/src/lib/steps/steps.directives.ts +78 -0
- package/src/lib/switch/index.ts +2 -0
- package/src/lib/switch/switch.component.spec.ts +98 -0
- package/src/lib/switch/switch.component.ts +76 -0
- package/src/lib/switch/switch.variants.ts +31 -0
- package/src/lib/table/index.ts +12 -0
- package/src/lib/table/table.directives.spec.ts +111 -0
- package/src/lib/table/table.directives.ts +126 -0
- package/src/lib/table/table.variants.ts +36 -0
- package/src/lib/tabs/index.ts +8 -0
- package/src/lib/tabs/tabs.directives.spec.ts +136 -0
- package/src/lib/tabs/tabs.directives.ts +126 -0
- package/src/lib/tabs/tabs.variants.ts +17 -0
- package/src/lib/tag-input/index.ts +2 -0
- package/src/lib/tag-input/tag-input.component.spec.ts +190 -0
- package/src/lib/tag-input/tag-input.component.ts +172 -0
- package/src/lib/tag-input/tag-input.variants.ts +31 -0
- package/src/lib/textarea/index.ts +7 -0
- package/src/lib/textarea/textarea.directive.spec.ts +84 -0
- package/src/lib/textarea/textarea.directive.ts +71 -0
- package/src/lib/textarea/textarea.variants.ts +34 -0
- package/src/lib/timeline/index.ts +11 -0
- package/src/lib/timeline/timeline.directives.spec.ts +55 -0
- package/src/lib/timeline/timeline.directives.ts +85 -0
- package/src/lib/toast/index.ts +3 -0
- package/src/lib/toast/toast.service.spec.ts +71 -0
- package/src/lib/toast/toast.service.ts +60 -0
- package/src/lib/toast/toast.variants.ts +38 -0
- package/src/lib/toast/toaster.component.spec.ts +38 -0
- package/src/lib/toast/toaster.component.ts +81 -0
- package/src/lib/toggle/index.ts +2 -0
- package/src/lib/toggle/toggle.directive.spec.ts +100 -0
- package/src/lib/toggle/toggle.directive.ts +61 -0
- package/src/lib/toggle/toggle.variants.ts +25 -0
- package/src/lib/tooltip/index.ts +2 -0
- package/src/lib/tooltip/tooltip.directive.spec.ts +113 -0
- package/src/lib/tooltip/tooltip.directive.ts +130 -0
- package/src/lib/tooltip/tooltip.variants.ts +20 -0
- package/src/lib/validator/index.ts +5 -0
- package/src/lib/validator/validator.directives.spec.ts +47 -0
- package/src/lib/validator/validator.directives.ts +50 -0
- package/src/styles/sonny-theme.css +33 -0
- package/types/sonny-ui-core.d.ts +1443 -13
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
TemplateRef,
|
|
5
|
+
computed,
|
|
6
|
+
contentChild,
|
|
7
|
+
contentChildren,
|
|
8
|
+
effect,
|
|
9
|
+
input,
|
|
10
|
+
model,
|
|
11
|
+
output,
|
|
12
|
+
signal,
|
|
13
|
+
untracked,
|
|
14
|
+
} from '@angular/core';
|
|
15
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
16
|
+
import {
|
|
17
|
+
SnyTableDirective,
|
|
18
|
+
SnyTableHeaderDirective,
|
|
19
|
+
SnyTableBodyDirective,
|
|
20
|
+
SnyTableRowDirective,
|
|
21
|
+
SnyTableHeadDirective,
|
|
22
|
+
SnyTableCellDirective,
|
|
23
|
+
} from '../table/table.directives';
|
|
24
|
+
import type { TableVariant, TableDensity } from '../table/table.variants';
|
|
25
|
+
import { SnyPaginationComponent } from '../pagination/pagination.component';
|
|
26
|
+
import { SnyCheckboxDirective } from '../checkbox/checkbox.directive';
|
|
27
|
+
import { SnyInputDirective } from '../input/input.directive';
|
|
28
|
+
import { SnyButtonDirective } from '../button/button.directive';
|
|
29
|
+
import { SnySelectComponent, type SelectOption } from '../select/select.component';
|
|
30
|
+
import { SnySkeletonDirective } from '../skeleton/skeleton.directive';
|
|
31
|
+
import {
|
|
32
|
+
SnyDropdownDirective,
|
|
33
|
+
SnyDropdownTriggerDirective,
|
|
34
|
+
SnyDropdownContentDirective,
|
|
35
|
+
SnyMenuItemDirective,
|
|
36
|
+
} from '../dropdown/dropdown.directives';
|
|
37
|
+
import {
|
|
38
|
+
SnyCellDefDirective,
|
|
39
|
+
SnyHeaderCellDefDirective,
|
|
40
|
+
SnyBulkActionsDefDirective,
|
|
41
|
+
SnyRowExpandDefDirective,
|
|
42
|
+
} from './data-table.directives';
|
|
43
|
+
import type {
|
|
44
|
+
DataTableColumn,
|
|
45
|
+
DataTablePaginationConfig,
|
|
46
|
+
SortState,
|
|
47
|
+
SortDirection,
|
|
48
|
+
} from './data-table.types';
|
|
49
|
+
|
|
50
|
+
const DEFAULT_PAGINATION: DataTablePaginationConfig = {
|
|
51
|
+
pageSize: 10,
|
|
52
|
+
pageSizeOptions: [5, 10, 25, 50],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
@Component({
|
|
56
|
+
selector: 'sny-data-table',
|
|
57
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
58
|
+
imports: [
|
|
59
|
+
NgTemplateOutlet,
|
|
60
|
+
SnyTableDirective,
|
|
61
|
+
SnyTableHeaderDirective,
|
|
62
|
+
SnyTableBodyDirective,
|
|
63
|
+
SnyTableRowDirective,
|
|
64
|
+
SnyTableHeadDirective,
|
|
65
|
+
SnyTableCellDirective,
|
|
66
|
+
SnyPaginationComponent,
|
|
67
|
+
SnyCheckboxDirective,
|
|
68
|
+
SnyInputDirective,
|
|
69
|
+
SnyButtonDirective,
|
|
70
|
+
SnySelectComponent,
|
|
71
|
+
SnySkeletonDirective,
|
|
72
|
+
SnyDropdownDirective,
|
|
73
|
+
SnyDropdownTriggerDirective,
|
|
74
|
+
SnyDropdownContentDirective,
|
|
75
|
+
SnyMenuItemDirective,
|
|
76
|
+
],
|
|
77
|
+
template: `
|
|
78
|
+
<!-- Toolbar -->
|
|
79
|
+
@if (filterable() || showExport() || showColumnToggle()) {
|
|
80
|
+
<div class="flex items-center justify-between gap-4 mb-4 flex-wrap">
|
|
81
|
+
@if (filterable()) {
|
|
82
|
+
<input
|
|
83
|
+
snyInput
|
|
84
|
+
[value]="filterText()"
|
|
85
|
+
(input)="onFilterInput($event)"
|
|
86
|
+
placeholder="Filter..."
|
|
87
|
+
class="w-full sm:max-w-sm"
|
|
88
|
+
/>
|
|
89
|
+
}
|
|
90
|
+
<div class="flex items-center gap-2">
|
|
91
|
+
@if (showExport()) {
|
|
92
|
+
<button snyBtn variant="outline" size="sm" (click)="onExport()">
|
|
93
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6"/><path d="M12 18v-6"/><path d="m9 15 3-3 3 3"/></svg>
|
|
94
|
+
<span class="hidden sm:inline">Export</span>
|
|
95
|
+
</button>
|
|
96
|
+
}
|
|
97
|
+
@if (showColumnToggle()) {
|
|
98
|
+
<div snyDropdown class="relative">
|
|
99
|
+
<button snyBtn variant="outline" size="sm" snyDropdownTrigger>
|
|
100
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/></svg>
|
|
101
|
+
<span class="hidden sm:inline">Columns</span>
|
|
102
|
+
</button>
|
|
103
|
+
<div snyDropdownContent class="w-48 right-0 left-auto">
|
|
104
|
+
@for (col of columns(); track col.key) {
|
|
105
|
+
<label snyMenuItem class="flex items-center gap-2 cursor-pointer">
|
|
106
|
+
<input
|
|
107
|
+
type="checkbox"
|
|
108
|
+
snyCheckbox
|
|
109
|
+
[checked]="!hiddenColumns().has(col.key)"
|
|
110
|
+
(change)="toggleColumnVisibility(col.key)"
|
|
111
|
+
(click)="$event.stopPropagation()"
|
|
112
|
+
/>
|
|
113
|
+
{{ col.label }}
|
|
114
|
+
</label>
|
|
115
|
+
}
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
}
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
<!-- Bulk Actions Bar -->
|
|
124
|
+
@if (showBulkActions()) {
|
|
125
|
+
@let selected = selectedRows();
|
|
126
|
+
<div class="flex items-center gap-2 mb-4 p-3 bg-muted/50 rounded-sm border border-border flex-wrap">
|
|
127
|
+
<span class="text-sm font-medium text-muted-foreground mr-2">
|
|
128
|
+
{{ selected.length }} selected
|
|
129
|
+
</span>
|
|
130
|
+
<ng-container
|
|
131
|
+
[ngTemplateOutlet]="bulkActionsDef()!.template"
|
|
132
|
+
[ngTemplateOutletContext]="{ $implicit: selected }"
|
|
133
|
+
/>
|
|
134
|
+
<button
|
|
135
|
+
snyBtn variant="ghost" size="sm" class="ml-auto"
|
|
136
|
+
(click)="selectedRows.set([])"
|
|
137
|
+
>
|
|
138
|
+
Clear
|
|
139
|
+
</button>
|
|
140
|
+
</div>
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
<!-- Table -->
|
|
144
|
+
<div class="overflow-auto border border-border rounded-sm">
|
|
145
|
+
<table
|
|
146
|
+
snyTable
|
|
147
|
+
[variant]="variant()"
|
|
148
|
+
[density]="density()"
|
|
149
|
+
[hoverable]="hoverable()"
|
|
150
|
+
[stickyHeader]="stickyHeader()"
|
|
151
|
+
>
|
|
152
|
+
<thead snyTableHeader>
|
|
153
|
+
<tr snyTableRow>
|
|
154
|
+
@if (selectable()) {
|
|
155
|
+
<th snyTableHead class="w-12">
|
|
156
|
+
<input
|
|
157
|
+
type="checkbox"
|
|
158
|
+
snyCheckbox
|
|
159
|
+
[checked]="allSelected()"
|
|
160
|
+
[indeterminate]="someSelected() && !allSelected()"
|
|
161
|
+
(change)="toggleSelectAll()"
|
|
162
|
+
/>
|
|
163
|
+
</th>
|
|
164
|
+
}
|
|
165
|
+
@if (expandable()) {
|
|
166
|
+
<th snyTableHead class="w-10"></th>
|
|
167
|
+
}
|
|
168
|
+
@let sort = sortState();
|
|
169
|
+
@let headerDefs = headerCellDefMap();
|
|
170
|
+
@for (col of visibleColumns(); track col.key) {
|
|
171
|
+
<th
|
|
172
|
+
snyTableHead
|
|
173
|
+
[style.width]="col.width ?? null"
|
|
174
|
+
[class]="col.sortable ? 'cursor-pointer select-none' : ''"
|
|
175
|
+
(click)="col.sortable ? toggleSort(col.key) : null"
|
|
176
|
+
>
|
|
177
|
+
@if (headerDefs.has(col.key)) {
|
|
178
|
+
<ng-container
|
|
179
|
+
[ngTemplateOutlet]="headerDefs.get(col.key)!"
|
|
180
|
+
[ngTemplateOutletContext]="{ $implicit: col }"
|
|
181
|
+
/>
|
|
182
|
+
} @else {
|
|
183
|
+
<div class="flex items-center gap-1">
|
|
184
|
+
<span>{{ col.label }}</span>
|
|
185
|
+
@if (col.sortable) {
|
|
186
|
+
@let isActive = sort.key === col.key;
|
|
187
|
+
@if (isActive && sort.direction === 'asc') {
|
|
188
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 7-7 7 7"/></svg>
|
|
189
|
+
} @else if (isActive && sort.direction === 'desc') {
|
|
190
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m19 12-7 7-7-7"/></svg>
|
|
191
|
+
} @else {
|
|
192
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-30"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
</div>
|
|
196
|
+
}
|
|
197
|
+
</th>
|
|
198
|
+
}
|
|
199
|
+
</tr>
|
|
200
|
+
</thead>
|
|
201
|
+
<tbody snyTableBody>
|
|
202
|
+
@if (loading()) {
|
|
203
|
+
@for (i of skeletonRows(); track i) {
|
|
204
|
+
<tr snyTableRow>
|
|
205
|
+
@if (selectable()) {
|
|
206
|
+
<td snyTableCell class="w-12"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
207
|
+
}
|
|
208
|
+
@if (expandable()) {
|
|
209
|
+
<td snyTableCell class="w-10"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
210
|
+
}
|
|
211
|
+
@for (col of visibleColumns(); track col.key) {
|
|
212
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
213
|
+
<div snySkeleton class="w-full h-4 rounded"></div>
|
|
214
|
+
</td>
|
|
215
|
+
}
|
|
216
|
+
</tr>
|
|
217
|
+
}
|
|
218
|
+
} @else if (paginatedData().length === 0) {
|
|
219
|
+
<tr snyTableRow>
|
|
220
|
+
<td
|
|
221
|
+
snyTableCell
|
|
222
|
+
[attr.colspan]="totalColSpan()"
|
|
223
|
+
class="text-center text-muted-foreground py-8"
|
|
224
|
+
>
|
|
225
|
+
{{ noDataText() }}
|
|
226
|
+
</td>
|
|
227
|
+
</tr>
|
|
228
|
+
} @else {
|
|
229
|
+
@let cellDefs = cellDefMap();
|
|
230
|
+
@let cols = visibleColumns();
|
|
231
|
+
@let expandTpl = rowExpandDef();
|
|
232
|
+
@for (row of paginatedData(); track trackByFn(row, $index)) {
|
|
233
|
+
<tr
|
|
234
|
+
snyTableRow
|
|
235
|
+
[attr.data-state]="isSelected(row) ? 'selected' : null"
|
|
236
|
+
(click)="onRowClick(row)"
|
|
237
|
+
class="cursor-pointer"
|
|
238
|
+
>
|
|
239
|
+
@if (selectable()) {
|
|
240
|
+
<td snyTableCell class="w-12">
|
|
241
|
+
<input
|
|
242
|
+
type="checkbox"
|
|
243
|
+
snyCheckbox
|
|
244
|
+
[checked]="isSelected(row)"
|
|
245
|
+
(change)="toggleRowSelection(row)"
|
|
246
|
+
(click)="$event.stopPropagation()"
|
|
247
|
+
/>
|
|
248
|
+
</td>
|
|
249
|
+
}
|
|
250
|
+
@if (expandable()) {
|
|
251
|
+
<td snyTableCell class="w-10">
|
|
252
|
+
<button
|
|
253
|
+
class="p-0.5 rounded hover:bg-accent transition-transform duration-150"
|
|
254
|
+
[class.rotate-90]="isExpanded(row)"
|
|
255
|
+
(click)="toggleRowExpansion(row); $event.stopPropagation()"
|
|
256
|
+
>
|
|
257
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
258
|
+
</button>
|
|
259
|
+
</td>
|
|
260
|
+
}
|
|
261
|
+
@for (col of cols; track col.key) {
|
|
262
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
263
|
+
@if (cellDefs.has(col.key)) {
|
|
264
|
+
<ng-container
|
|
265
|
+
[ngTemplateOutlet]="cellDefs.get(col.key)!"
|
|
266
|
+
[ngTemplateOutletContext]="{ $implicit: row[col.key], row: row }"
|
|
267
|
+
/>
|
|
268
|
+
} @else {
|
|
269
|
+
{{ row[col.key] }}
|
|
270
|
+
}
|
|
271
|
+
</td>
|
|
272
|
+
}
|
|
273
|
+
</tr>
|
|
274
|
+
@if (expandable() && isExpanded(row) && expandTpl) {
|
|
275
|
+
<tr snyTableRow>
|
|
276
|
+
<td snyTableCell [attr.colspan]="totalColSpan()" class="bg-muted/30">
|
|
277
|
+
<ng-container
|
|
278
|
+
[ngTemplateOutlet]="expandTpl.template"
|
|
279
|
+
[ngTemplateOutletContext]="{ $implicit: row }"
|
|
280
|
+
/>
|
|
281
|
+
</td>
|
|
282
|
+
</tr>
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
</tbody>
|
|
287
|
+
</table>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<!-- Footer -->
|
|
291
|
+
@if (paginated()) {
|
|
292
|
+
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-4 gap-3 sm:gap-4">
|
|
293
|
+
<span class="text-sm text-muted-foreground">
|
|
294
|
+
@if (selectable()) {
|
|
295
|
+
{{ selectedRows().length }} of {{ filteredData().length }} row(s) selected
|
|
296
|
+
} @else {
|
|
297
|
+
{{ filteredData().length }} row(s)
|
|
298
|
+
}
|
|
299
|
+
</span>
|
|
300
|
+
<div class="flex items-center gap-3 sm:gap-4 flex-wrap">
|
|
301
|
+
<div class="flex items-center gap-2">
|
|
302
|
+
<span class="hidden sm:inline text-sm text-muted-foreground whitespace-nowrap">Rows per page</span>
|
|
303
|
+
<sny-select
|
|
304
|
+
[options]="pageSizeOptions()"
|
|
305
|
+
[value]="pageSizeValue()"
|
|
306
|
+
(valueChange)="onPageSizeChange($event)"
|
|
307
|
+
size="sm"
|
|
308
|
+
class="w-20"
|
|
309
|
+
/>
|
|
310
|
+
</div>
|
|
311
|
+
<sny-pagination
|
|
312
|
+
[currentPage]="currentPage()"
|
|
313
|
+
(currentPageChange)="currentPage.set($event)"
|
|
314
|
+
[totalPages]="totalPages()"
|
|
315
|
+
/>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
}
|
|
319
|
+
`,
|
|
320
|
+
})
|
|
321
|
+
export class SnyDataTableComponent {
|
|
322
|
+
// Inputs
|
|
323
|
+
readonly columns = input.required<DataTableColumn[]>();
|
|
324
|
+
readonly data = input.required<Record<string, unknown>[]>();
|
|
325
|
+
readonly variant = input<TableVariant>('default');
|
|
326
|
+
readonly density = input<TableDensity>('normal');
|
|
327
|
+
readonly hoverable = input(true);
|
|
328
|
+
readonly stickyHeader = input(false);
|
|
329
|
+
readonly selectable = input(false);
|
|
330
|
+
readonly paginated = input(true);
|
|
331
|
+
readonly filterable = input(true);
|
|
332
|
+
readonly showExport = input(false);
|
|
333
|
+
readonly showColumnToggle = input(false);
|
|
334
|
+
readonly expandable = input(false);
|
|
335
|
+
readonly loading = input(false);
|
|
336
|
+
readonly loadingRows = input(5);
|
|
337
|
+
readonly paginationConfig = input<DataTablePaginationConfig>(DEFAULT_PAGINATION);
|
|
338
|
+
readonly trackBy = input('');
|
|
339
|
+
readonly noDataText = input('No data available');
|
|
340
|
+
|
|
341
|
+
// Model
|
|
342
|
+
readonly selectedRows = model<Record<string, unknown>[]>([]);
|
|
343
|
+
|
|
344
|
+
// Outputs
|
|
345
|
+
readonly sortChanged = output<SortState>();
|
|
346
|
+
readonly rowClicked = output<Record<string, unknown>>();
|
|
347
|
+
readonly dataExported = output<Record<string, unknown>[]>();
|
|
348
|
+
|
|
349
|
+
// Content queries
|
|
350
|
+
readonly cellDefs = contentChildren(SnyCellDefDirective);
|
|
351
|
+
readonly headerCellDefs = contentChildren(SnyHeaderCellDefDirective);
|
|
352
|
+
readonly bulkActionsDef = contentChild(SnyBulkActionsDefDirective);
|
|
353
|
+
readonly rowExpandDef = contentChild(SnyRowExpandDefDirective);
|
|
354
|
+
|
|
355
|
+
// Internal state
|
|
356
|
+
readonly sortState = signal<SortState>({ key: '', direction: null });
|
|
357
|
+
readonly filterText = signal('');
|
|
358
|
+
readonly currentPage = signal(1);
|
|
359
|
+
readonly pageSize = signal(10);
|
|
360
|
+
readonly hiddenColumns = signal<Set<string>>(new Set());
|
|
361
|
+
readonly expandedRows = signal<Set<unknown>>(new Set());
|
|
362
|
+
|
|
363
|
+
// Template def maps
|
|
364
|
+
readonly cellDefMap = computed(() => {
|
|
365
|
+
const map = new Map<string, TemplateRef<unknown>>();
|
|
366
|
+
for (const def of this.cellDefs()) {
|
|
367
|
+
map.set(def.snyCell(), def.template);
|
|
368
|
+
}
|
|
369
|
+
return map;
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
readonly headerCellDefMap = computed(() => {
|
|
373
|
+
const map = new Map<string, TemplateRef<unknown>>();
|
|
374
|
+
for (const def of this.headerCellDefs()) {
|
|
375
|
+
map.set(def.snyHeaderCell(), def.template);
|
|
376
|
+
}
|
|
377
|
+
return map;
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Visible columns
|
|
381
|
+
readonly visibleColumns = computed(() =>
|
|
382
|
+
this.columns().filter(
|
|
383
|
+
(col) => col.visible !== false && !this.hiddenColumns().has(col.key)
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
// Page size options
|
|
388
|
+
readonly pageSizeOptions = computed<SelectOption[]>(() =>
|
|
389
|
+
this.paginationConfig().pageSizeOptions.map((n) => ({
|
|
390
|
+
value: String(n),
|
|
391
|
+
label: String(n),
|
|
392
|
+
}))
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
readonly pageSizeValue = computed(() => String(this.pageSize()));
|
|
396
|
+
|
|
397
|
+
// Skeleton rows
|
|
398
|
+
readonly skeletonRows = computed(() =>
|
|
399
|
+
Array.from({ length: this.loadingRows() }, (_, i) => i)
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// Bulk actions visibility
|
|
403
|
+
readonly showBulkActions = computed(
|
|
404
|
+
() =>
|
|
405
|
+
this.selectable() &&
|
|
406
|
+
this.selectedRows().length > 0 &&
|
|
407
|
+
this.bulkActionsDef() != null
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
// Data pipeline (filter uses all columns, not just visible)
|
|
411
|
+
readonly filteredData = computed(() => {
|
|
412
|
+
const text = this.filterText().toLowerCase().trim();
|
|
413
|
+
const rows = this.data();
|
|
414
|
+
if (!text) return rows;
|
|
415
|
+
const cols = this.columns().filter((c) => c.filterable !== false);
|
|
416
|
+
return rows.filter((row) =>
|
|
417
|
+
cols.some((col) =>
|
|
418
|
+
String(row[col.key] ?? '').toLowerCase().includes(text)
|
|
419
|
+
)
|
|
420
|
+
);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
readonly sortedData = computed(() => {
|
|
424
|
+
const { key, direction } = this.sortState();
|
|
425
|
+
const rows = this.filteredData();
|
|
426
|
+
if (!key || !direction) return rows;
|
|
427
|
+
return [...rows].sort((a, b) => {
|
|
428
|
+
const aVal = a[key];
|
|
429
|
+
const bVal = b[key];
|
|
430
|
+
if (aVal == null && bVal == null) return 0;
|
|
431
|
+
if (aVal == null) return direction === 'asc' ? -1 : 1;
|
|
432
|
+
if (bVal == null) return direction === 'asc' ? 1 : -1;
|
|
433
|
+
if (typeof aVal === 'number' && typeof bVal === 'number') {
|
|
434
|
+
return direction === 'asc' ? aVal - bVal : bVal - aVal;
|
|
435
|
+
}
|
|
436
|
+
const cmp = String(aVal).localeCompare(String(bVal));
|
|
437
|
+
return direction === 'asc' ? cmp : -cmp;
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
readonly totalPages = computed(() =>
|
|
442
|
+
Math.max(1, Math.ceil(this.filteredData().length / this.pageSize()))
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
readonly paginatedData = computed(() => {
|
|
446
|
+
if (!this.paginated()) return this.sortedData();
|
|
447
|
+
const start = (this.currentPage() - 1) * this.pageSize();
|
|
448
|
+
return this.sortedData().slice(start, start + this.pageSize());
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
readonly totalColSpan = computed(
|
|
452
|
+
() =>
|
|
453
|
+
this.visibleColumns().length +
|
|
454
|
+
(this.selectable() ? 1 : 0) +
|
|
455
|
+
(this.expandable() ? 1 : 0)
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// Selection computed
|
|
459
|
+
readonly allSelected = computed(() => {
|
|
460
|
+
const page = this.paginatedData();
|
|
461
|
+
if (page.length === 0) return false;
|
|
462
|
+
const selected = this.selectedRows();
|
|
463
|
+
return page.every((row) => this.isRowInList(row, selected));
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
readonly someSelected = computed(() => {
|
|
467
|
+
const page = this.paginatedData();
|
|
468
|
+
const selected = this.selectedRows();
|
|
469
|
+
return page.some((row) => this.isRowInList(row, selected));
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
constructor() {
|
|
473
|
+
effect(() => {
|
|
474
|
+
const config = this.paginationConfig();
|
|
475
|
+
untracked(() => this.pageSize.set(config.pageSize));
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
effect(() => {
|
|
479
|
+
this.filterText();
|
|
480
|
+
this.pageSize();
|
|
481
|
+
this.data();
|
|
482
|
+
untracked(() => this.currentPage.set(1));
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Sort
|
|
487
|
+
toggleSort(key: string): void {
|
|
488
|
+
const current = this.sortState();
|
|
489
|
+
let direction: SortDirection;
|
|
490
|
+
if (current.key !== key) {
|
|
491
|
+
direction = 'asc';
|
|
492
|
+
} else if (current.direction === 'asc') {
|
|
493
|
+
direction = 'desc';
|
|
494
|
+
} else if (current.direction === 'desc') {
|
|
495
|
+
direction = null;
|
|
496
|
+
} else {
|
|
497
|
+
direction = 'asc';
|
|
498
|
+
}
|
|
499
|
+
const next: SortState = { key: direction ? key : '', direction };
|
|
500
|
+
this.sortState.set(next);
|
|
501
|
+
this.sortChanged.emit(next);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Filter
|
|
505
|
+
onFilterInput(event: Event): void {
|
|
506
|
+
this.filterText.set((event.target as HTMLInputElement).value);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Page size
|
|
510
|
+
onPageSizeChange(value: string): void {
|
|
511
|
+
this.pageSize.set(Number(value));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Selection
|
|
515
|
+
toggleSelectAll(): void {
|
|
516
|
+
if (this.allSelected()) {
|
|
517
|
+
const page = this.paginatedData();
|
|
518
|
+
this.selectedRows.update((sel) =>
|
|
519
|
+
sel.filter((r) => !page.some((p) => this.rowsEqual(r, p)))
|
|
520
|
+
);
|
|
521
|
+
} else {
|
|
522
|
+
const page = this.paginatedData();
|
|
523
|
+
this.selectedRows.update((sel) => {
|
|
524
|
+
const newSel = [...sel];
|
|
525
|
+
for (const row of page) {
|
|
526
|
+
if (!this.isRowInList(row, newSel)) newSel.push(row);
|
|
527
|
+
}
|
|
528
|
+
return newSel;
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
toggleRowSelection(row: Record<string, unknown>): void {
|
|
534
|
+
this.selectedRows.update((sel) =>
|
|
535
|
+
this.isRowInList(row, sel)
|
|
536
|
+
? sel.filter((r) => !this.rowsEqual(r, row))
|
|
537
|
+
: [...sel, row]
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Row click
|
|
542
|
+
onRowClick(row: Record<string, unknown>): void {
|
|
543
|
+
this.rowClicked.emit(row);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Export
|
|
547
|
+
onExport(): void {
|
|
548
|
+
this.dataExported.emit(this.filteredData());
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Column visibility
|
|
552
|
+
toggleColumnVisibility(key: string): void {
|
|
553
|
+
this.hiddenColumns.update((set) => {
|
|
554
|
+
const next = new Set(set);
|
|
555
|
+
if (next.has(key)) next.delete(key);
|
|
556
|
+
else next.add(key);
|
|
557
|
+
return next;
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Expansion
|
|
562
|
+
toggleRowExpansion(row: Record<string, unknown>): void {
|
|
563
|
+
const key = this.trackBy() ? row[this.trackBy()] : row;
|
|
564
|
+
this.expandedRows.update((set) => {
|
|
565
|
+
const next = new Set(set);
|
|
566
|
+
if (next.has(key)) next.delete(key);
|
|
567
|
+
else next.add(key);
|
|
568
|
+
return next;
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
isExpanded(row: Record<string, unknown>): boolean {
|
|
573
|
+
const key = this.trackBy() ? row[this.trackBy()] : row;
|
|
574
|
+
return this.expandedRows().has(key);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Helpers
|
|
578
|
+
isSelected(row: Record<string, unknown>): boolean {
|
|
579
|
+
return this.isRowInList(row, this.selectedRows());
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
trackByFn(row: Record<string, unknown>, index: number): unknown {
|
|
583
|
+
const key = this.trackBy();
|
|
584
|
+
return key ? row[key] : index;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private isRowInList(
|
|
588
|
+
row: Record<string, unknown>,
|
|
589
|
+
list: Record<string, unknown>[]
|
|
590
|
+
): boolean {
|
|
591
|
+
return list.some((r) => this.rowsEqual(r, row));
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private rowsEqual(
|
|
595
|
+
a: Record<string, unknown>,
|
|
596
|
+
b: Record<string, unknown>
|
|
597
|
+
): boolean {
|
|
598
|
+
const key = this.trackBy();
|
|
599
|
+
if (key) return a[key] === b[key];
|
|
600
|
+
return a === b;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Directive, TemplateRef, inject, input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[snyCell]',
|
|
5
|
+
})
|
|
6
|
+
export class SnyCellDefDirective {
|
|
7
|
+
readonly snyCell = input.required<string>();
|
|
8
|
+
readonly template = inject(TemplateRef);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Directive({
|
|
12
|
+
selector: '[snyHeaderCell]',
|
|
13
|
+
})
|
|
14
|
+
export class SnyHeaderCellDefDirective {
|
|
15
|
+
readonly snyHeaderCell = input.required<string>();
|
|
16
|
+
readonly template = inject(TemplateRef);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Directive({
|
|
20
|
+
selector: '[snyBulkActions]',
|
|
21
|
+
})
|
|
22
|
+
export class SnyBulkActionsDefDirective {
|
|
23
|
+
readonly template = inject(TemplateRef);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Directive({
|
|
27
|
+
selector: '[snyRowExpand]',
|
|
28
|
+
})
|
|
29
|
+
export class SnyRowExpandDefDirective {
|
|
30
|
+
readonly template = inject(TemplateRef);
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface DataTableColumn {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
sortable?: boolean;
|
|
5
|
+
filterable?: boolean;
|
|
6
|
+
width?: string;
|
|
7
|
+
visible?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type SortDirection = 'asc' | 'desc' | null;
|
|
11
|
+
|
|
12
|
+
export interface SortState {
|
|
13
|
+
key: string;
|
|
14
|
+
direction: SortDirection;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DataTablePaginationConfig {
|
|
18
|
+
pageSize: number;
|
|
19
|
+
pageSizeOptions: number[];
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { SnyDataTableComponent } from './data-table.component';
|
|
2
|
+
export {
|
|
3
|
+
SnyCellDefDirective,
|
|
4
|
+
SnyHeaderCellDefDirective,
|
|
5
|
+
SnyBulkActionsDefDirective,
|
|
6
|
+
SnyRowExpandDefDirective,
|
|
7
|
+
} from './data-table.directives';
|
|
8
|
+
export type {
|
|
9
|
+
DataTableColumn,
|
|
10
|
+
SortState,
|
|
11
|
+
SortDirection,
|
|
12
|
+
DataTablePaginationConfig,
|
|
13
|
+
} from './data-table.types';
|