cerxos-ui 0.0.3 → 0.0.5
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/fesm2022/cerxos-ui.mjs +1948 -239
- package/fesm2022/cerxos-ui.mjs.map +1 -1
- package/index.d.ts +454 -4
- package/package.json +1 -1
- package/styles/tailwind.css +3 -3
- package/tokens/theme-dark.css +16 -16
- package/tokens/theme-default.css +15 -15
package/fesm2022/cerxos-ui.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, HostListener,
|
|
2
|
+
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, Directive, ContentChildren, ViewChild, HostListener, ElementRef, ViewChildren } from '@angular/core';
|
|
3
3
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
|
-
import { NgIf } from '@angular/common';
|
|
4
|
+
import { NgTemplateOutlet, NgIf } from '@angular/common';
|
|
5
5
|
|
|
6
6
|
class CerxosUi {
|
|
7
7
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CerxosUi, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -20,9 +20,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
20
20
|
` }]
|
|
21
21
|
}] });
|
|
22
22
|
|
|
23
|
-
const BASE_CLASSES$
|
|
23
|
+
const BASE_CLASSES$a = 'relative flex w-full gap-3 rounded-[var(--cxs-radius-md)] border border-l-4 px-4 py-3 text-sm ' +
|
|
24
24
|
'text-[var(--cxs-color-on-surface)]';
|
|
25
|
-
const VARIANT_CLASSES$
|
|
25
|
+
const VARIANT_CLASSES$7 = {
|
|
26
26
|
info: 'border-[var(--cxs-color-primary)] border-l-[var(--cxs-color-primary)] ' +
|
|
27
27
|
'bg-[var(--cxs-color-primary-ghost)]',
|
|
28
28
|
neutral: 'border-[var(--cxs-color-border)] border-l-[var(--cxs-color-border)] ' +
|
|
@@ -36,7 +36,7 @@ const TITLE_VARIANT = {
|
|
|
36
36
|
neutral: 'text-[var(--cxs-color-on-surface)]',
|
|
37
37
|
danger: 'text-[var(--cxs-color-danger)]'
|
|
38
38
|
};
|
|
39
|
-
const CLOSE_BUTTON_CLASSES = 'ml-auto inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
39
|
+
const CLOSE_BUTTON_CLASSES$2 = 'ml-auto inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
40
40
|
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
41
41
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
42
42
|
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
@@ -47,24 +47,24 @@ class CxsAlertComponent {
|
|
|
47
47
|
closed = new EventEmitter();
|
|
48
48
|
isVisible = true;
|
|
49
49
|
get alertClass() {
|
|
50
|
-
return [BASE_CLASSES$
|
|
50
|
+
return [BASE_CLASSES$a, VARIANT_CLASSES$7[this.variant]].join(' ');
|
|
51
51
|
}
|
|
52
52
|
get titleClass() {
|
|
53
53
|
return [TITLE_BASE, TITLE_VARIANT[this.variant]].join(' ');
|
|
54
54
|
}
|
|
55
55
|
get closeButtonClass() {
|
|
56
|
-
return CLOSE_BUTTON_CLASSES;
|
|
56
|
+
return CLOSE_BUTTON_CLASSES$2;
|
|
57
57
|
}
|
|
58
58
|
onClose() {
|
|
59
59
|
this.isVisible = false;
|
|
60
60
|
this.closed.emit();
|
|
61
61
|
}
|
|
62
62
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
63
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAlertComponent, isStandalone: true, selector: "cxs-alert", inputs: { variant: "variant", title: "title", dismissible: "dismissible" }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isVisible) {\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\n <div class=\"flex flex-col gap-1\">\n @if (title) {\n <div [class]=\"titleClass\">{{ title }}</div>\n }\n <div class=\"text-[var(--cxs-color-on-surface)]\">\n <ng-content></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss alert\"\n (click)=\"onClose()\"\n >\n x\n </button>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
63
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAlertComponent, isStandalone: true, selector: "cxs-alert", inputs: { variant: "variant", title: "title", dismissible: "dismissible" }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isVisible) {\r\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\r\n <div class=\"flex flex-col gap-1\">\r\n @if (title) {\r\n <div [class]=\"titleClass\">{{ title }}</div>\r\n }\r\n <div class=\"text-[var(--cxs-color-on-surface)]\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n @if (dismissible) {\r\n <button\r\n type=\"button\"\r\n [class]=\"closeButtonClass\"\r\n aria-label=\"Dismiss alert\"\r\n (click)=\"onClose()\"\r\n >\r\n x\r\n </button>\r\n }\r\n </div>\r\n}\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
64
64
|
}
|
|
65
65
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAlertComponent, decorators: [{
|
|
66
66
|
type: Component,
|
|
67
|
-
args: [{ selector: 'cxs-alert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isVisible) {\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\n <div class=\"flex flex-col gap-1\">\n @if (title) {\n <div [class]=\"titleClass\">{{ title }}</div>\n }\n <div class=\"text-[var(--cxs-color-on-surface)]\">\n <ng-content></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss alert\"\n (click)=\"onClose()\"\n >\n x\n </button>\n }\n </div>\n}\n" }]
|
|
67
|
+
args: [{ selector: 'cxs-alert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isVisible) {\r\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\r\n <div class=\"flex flex-col gap-1\">\r\n @if (title) {\r\n <div [class]=\"titleClass\">{{ title }}</div>\r\n }\r\n <div class=\"text-[var(--cxs-color-on-surface)]\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n @if (dismissible) {\r\n <button\r\n type=\"button\"\r\n [class]=\"closeButtonClass\"\r\n aria-label=\"Dismiss alert\"\r\n (click)=\"onClose()\"\r\n >\r\n x\r\n </button>\r\n }\r\n </div>\r\n}\r\n" }]
|
|
68
68
|
}], propDecorators: { variant: [{
|
|
69
69
|
type: Input
|
|
70
70
|
}], title: [{
|
|
@@ -75,9 +75,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
75
75
|
type: Output
|
|
76
76
|
}] } });
|
|
77
77
|
|
|
78
|
-
const BASE_CLASSES$
|
|
78
|
+
const BASE_CLASSES$9 = 'grid';
|
|
79
|
+
const SPACING_CLASSES = {
|
|
80
|
+
sm: 'gap-2',
|
|
81
|
+
md: 'gap-3',
|
|
82
|
+
lg: 'gap-4'
|
|
83
|
+
};
|
|
84
|
+
class CxsAccordionComponent {
|
|
85
|
+
spacing = 'md';
|
|
86
|
+
get accordionClass() {
|
|
87
|
+
return [BASE_CLASSES$9, SPACING_CLASSES[this.spacing]].join(' ');
|
|
88
|
+
}
|
|
89
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
90
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsAccordionComponent, isStandalone: true, selector: "cxs-accordion", inputs: { spacing: "spacing" }, ngImport: i0, template: "<div [class]=\"accordionClass\">\n <ng-content></ng-content>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionComponent, decorators: [{
|
|
93
|
+
type: Component,
|
|
94
|
+
args: [{ selector: 'cxs-accordion', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"accordionClass\">\n <ng-content></ng-content>\n</div>\n" }]
|
|
95
|
+
}], propDecorators: { spacing: [{
|
|
96
|
+
type: Input
|
|
97
|
+
}] } });
|
|
98
|
+
|
|
99
|
+
const ITEM_BASE = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
100
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
|
|
101
|
+
const ITEM_DISABLED = 'opacity-60';
|
|
102
|
+
const HEADER_BASE = 'flex w-full items-center justify-between gap-3 text-left font-medium transition-colors ' +
|
|
103
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
104
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
105
|
+
const HEADER_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
|
|
106
|
+
const HEADER_DISABLED = 'cursor-not-allowed';
|
|
107
|
+
const CONTENT_BASE = 'text-(--cxs-color-on-surface-muted)';
|
|
108
|
+
const SIZE_HEADER_CLASSES = {
|
|
109
|
+
sm: 'px-3 py-2 text-sm',
|
|
110
|
+
md: 'px-4 py-3 text-sm',
|
|
111
|
+
lg: 'px-5 py-4 text-base'
|
|
112
|
+
};
|
|
113
|
+
const SIZE_CONTENT_CLASSES = {
|
|
114
|
+
sm: 'px-3 pb-3 text-sm',
|
|
115
|
+
md: 'px-4 pb-4 text-sm',
|
|
116
|
+
lg: 'px-5 pb-5 text-base'
|
|
117
|
+
};
|
|
118
|
+
class CxsAccordionItemComponent {
|
|
119
|
+
static nextId = 0;
|
|
120
|
+
title;
|
|
121
|
+
expanded = false;
|
|
122
|
+
disabled = false;
|
|
123
|
+
size = 'md';
|
|
124
|
+
expandedChange = new EventEmitter();
|
|
125
|
+
buttonId = `cxs-accordion-button-${++CxsAccordionItemComponent.nextId}`;
|
|
126
|
+
contentId = `cxs-accordion-panel-${CxsAccordionItemComponent.nextId}`;
|
|
127
|
+
get itemClass() {
|
|
128
|
+
return [ITEM_BASE, this.disabled ? ITEM_DISABLED : ''].filter(Boolean).join(' ');
|
|
129
|
+
}
|
|
130
|
+
get headerClass() {
|
|
131
|
+
return [
|
|
132
|
+
HEADER_BASE,
|
|
133
|
+
SIZE_HEADER_CLASSES[this.size],
|
|
134
|
+
this.disabled ? HEADER_DISABLED : HEADER_HOVER
|
|
135
|
+
]
|
|
136
|
+
.filter(Boolean)
|
|
137
|
+
.join(' ');
|
|
138
|
+
}
|
|
139
|
+
get contentClass() {
|
|
140
|
+
return [CONTENT_BASE, SIZE_CONTENT_CLASSES[this.size]].join(' ');
|
|
141
|
+
}
|
|
142
|
+
get iconClass() {
|
|
143
|
+
return [
|
|
144
|
+
'h-4 w-4 shrink-0 text-(--cxs-color-on-surface-muted) transition-transform',
|
|
145
|
+
this.expanded ? 'rotate-180' : ''
|
|
146
|
+
]
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
.join(' ');
|
|
149
|
+
}
|
|
150
|
+
toggle() {
|
|
151
|
+
if (this.disabled) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.expanded = !this.expanded;
|
|
155
|
+
this.expandedChange.emit(this.expanded);
|
|
156
|
+
}
|
|
157
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
158
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAccordionItemComponent, isStandalone: true, selector: "cxs-accordion-item", inputs: { title: "title", expanded: "expanded", disabled: "disabled", size: "size" }, outputs: { expandedChange: "expandedChange" }, ngImport: i0, template: "<div [class]=\"itemClass\">\n <button\n type=\"button\"\n [class]=\"headerClass\"\n [id]=\"buttonId\"\n [disabled]=\"disabled\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"contentId\"\n (click)=\"toggle()\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n <ng-content select=\"[cxsAccordionTitle]\"></ng-content>\n @if (title) {\n <span class=\"truncate\">{{ title }}</span>\n }\n </span>\n <svg aria-hidden=\"true\" [class]=\"iconClass\" viewBox=\"0 0 20 20\">\n <path\n d=\"M5 7l5 5 5-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n ></path>\n </svg>\n </button>\n\n <div\n [id]=\"contentId\"\n role=\"region\"\n [attr.aria-labelledby]=\"buttonId\"\n [class]=\"contentClass\"\n [hidden]=\"!expanded\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
159
|
+
}
|
|
160
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionItemComponent, decorators: [{
|
|
161
|
+
type: Component,
|
|
162
|
+
args: [{ selector: 'cxs-accordion-item', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"itemClass\">\n <button\n type=\"button\"\n [class]=\"headerClass\"\n [id]=\"buttonId\"\n [disabled]=\"disabled\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"contentId\"\n (click)=\"toggle()\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n <ng-content select=\"[cxsAccordionTitle]\"></ng-content>\n @if (title) {\n <span class=\"truncate\">{{ title }}</span>\n }\n </span>\n <svg aria-hidden=\"true\" [class]=\"iconClass\" viewBox=\"0 0 20 20\">\n <path\n d=\"M5 7l5 5 5-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n ></path>\n </svg>\n </button>\n\n <div\n [id]=\"contentId\"\n role=\"region\"\n [attr.aria-labelledby]=\"buttonId\"\n [class]=\"contentClass\"\n [hidden]=\"!expanded\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n" }]
|
|
163
|
+
}], propDecorators: { title: [{
|
|
164
|
+
type: Input
|
|
165
|
+
}], expanded: [{
|
|
166
|
+
type: Input
|
|
167
|
+
}], disabled: [{
|
|
168
|
+
type: Input
|
|
169
|
+
}], size: [{
|
|
170
|
+
type: Input
|
|
171
|
+
}], expandedChange: [{
|
|
172
|
+
type: Output
|
|
173
|
+
}] } });
|
|
174
|
+
|
|
175
|
+
const BASE_CLASSES$8 = 'inline-flex items-center gap-1 rounded-[var(--cxs-radius-md)] border px-2.5 py-0.5 text-xs font-medium ' +
|
|
79
176
|
'leading-none';
|
|
80
|
-
const VARIANT_CLASSES$
|
|
177
|
+
const VARIANT_CLASSES$6 = {
|
|
81
178
|
primary: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
|
|
82
179
|
'text-[var(--cxs-color-primary)]',
|
|
83
180
|
neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
@@ -85,7 +182,7 @@ const VARIANT_CLASSES$5 = {
|
|
|
85
182
|
danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
|
|
86
183
|
'text-[var(--cxs-color-danger)]'
|
|
87
184
|
};
|
|
88
|
-
const SIZE_CLASSES$
|
|
185
|
+
const SIZE_CLASSES$7 = {
|
|
89
186
|
sm: 'text-[11px]',
|
|
90
187
|
md: 'text-xs'
|
|
91
188
|
};
|
|
@@ -93,21 +190,124 @@ class CxsBadgeComponent {
|
|
|
93
190
|
variant = 'primary';
|
|
94
191
|
size = 'md';
|
|
95
192
|
get badgeClass() {
|
|
96
|
-
return [BASE_CLASSES$
|
|
193
|
+
return [BASE_CLASSES$8, VARIANT_CLASSES$6[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
|
|
97
194
|
}
|
|
98
195
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
99
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\n <ng-content></ng-content>\n</span>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
196
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\r\n <ng-content></ng-content>\r\n</span>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
100
197
|
}
|
|
101
198
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, decorators: [{
|
|
102
199
|
type: Component,
|
|
103
|
-
args: [{ selector: 'cxs-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<span [class]=\"badgeClass\">\n <ng-content></ng-content>\n</span>\n" }]
|
|
200
|
+
args: [{ selector: 'cxs-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<span [class]=\"badgeClass\">\r\n <ng-content></ng-content>\r\n</span>\r\n" }]
|
|
104
201
|
}], propDecorators: { variant: [{
|
|
105
202
|
type: Input
|
|
106
203
|
}], size: [{
|
|
107
204
|
type: Input
|
|
108
205
|
}] } });
|
|
109
206
|
|
|
110
|
-
const BASE_CLASSES$
|
|
207
|
+
const BASE_CLASSES$7 = 'inline-flex items-center justify-center overflow-hidden border border-[var(--cxs-color-border)] ' +
|
|
208
|
+
'bg-[var(--cxs-color-primary-ghost)] text-[var(--cxs-color-primary)] font-semibold uppercase ' +
|
|
209
|
+
'select-none';
|
|
210
|
+
const SIZE_CLASSES$6 = {
|
|
211
|
+
sm: 'h-8 w-8 text-[11px]',
|
|
212
|
+
md: 'h-10 w-10 text-xs',
|
|
213
|
+
lg: 'h-14 w-14 text-sm'
|
|
214
|
+
};
|
|
215
|
+
const SHAPE_CLASSES = {
|
|
216
|
+
circle: 'rounded-full',
|
|
217
|
+
square: 'rounded-[var(--cxs-radius-md)]'
|
|
218
|
+
};
|
|
219
|
+
const FALLBACK_CLASSES = 'leading-none';
|
|
220
|
+
class CxsAvatarComponent {
|
|
221
|
+
hostClass;
|
|
222
|
+
_src;
|
|
223
|
+
set src(value) {
|
|
224
|
+
if (value !== this._src) {
|
|
225
|
+
this._src = value;
|
|
226
|
+
this.imageError = false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
get src() {
|
|
230
|
+
return this._src;
|
|
231
|
+
}
|
|
232
|
+
name;
|
|
233
|
+
alt;
|
|
234
|
+
size = 'md';
|
|
235
|
+
shape = 'circle';
|
|
236
|
+
imageError = false;
|
|
237
|
+
constructor(hostClass) {
|
|
238
|
+
this.hostClass = hostClass;
|
|
239
|
+
}
|
|
240
|
+
get avatarClass() {
|
|
241
|
+
return [BASE_CLASSES$7, SIZE_CLASSES$6[this.size], SHAPE_CLASSES[this.shape], this.hostClass]
|
|
242
|
+
.filter(Boolean)
|
|
243
|
+
.join(' ');
|
|
244
|
+
}
|
|
245
|
+
get fallbackClass() {
|
|
246
|
+
return FALLBACK_CLASSES;
|
|
247
|
+
}
|
|
248
|
+
get altText() {
|
|
249
|
+
if (this.alt !== undefined) {
|
|
250
|
+
return this.alt;
|
|
251
|
+
}
|
|
252
|
+
if (this.name) {
|
|
253
|
+
return this.name;
|
|
254
|
+
}
|
|
255
|
+
return 'Avatar';
|
|
256
|
+
}
|
|
257
|
+
get fallbackLabel() {
|
|
258
|
+
if (this.name) {
|
|
259
|
+
return this.name;
|
|
260
|
+
}
|
|
261
|
+
if (this.alt && this.alt.trim().length > 0) {
|
|
262
|
+
return this.alt;
|
|
263
|
+
}
|
|
264
|
+
return 'Avatar';
|
|
265
|
+
}
|
|
266
|
+
get fallbackText() {
|
|
267
|
+
if (!this.name) {
|
|
268
|
+
return '?';
|
|
269
|
+
}
|
|
270
|
+
return this.getInitials(this.name);
|
|
271
|
+
}
|
|
272
|
+
get showImage() {
|
|
273
|
+
return !!this.src && !this.imageError;
|
|
274
|
+
}
|
|
275
|
+
onImageError() {
|
|
276
|
+
this.imageError = true;
|
|
277
|
+
}
|
|
278
|
+
getInitials(value) {
|
|
279
|
+
const parts = value
|
|
280
|
+
.trim()
|
|
281
|
+
.split(/\s+/)
|
|
282
|
+
.filter(Boolean);
|
|
283
|
+
if (parts.length >= 2) {
|
|
284
|
+
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
285
|
+
}
|
|
286
|
+
const word = parts[0] ?? '';
|
|
287
|
+
return word.slice(0, 2).toUpperCase() || '?';
|
|
288
|
+
}
|
|
289
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAvatarComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
290
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAvatarComponent, isStandalone: true, selector: "cxs-avatar", inputs: { src: "src", name: "name", alt: "alt", size: "size", shape: "shape" }, ngImport: i0, template: "<div\n [class]=\"avatarClass\"\n [attr.role]=\"showImage ? null : 'img'\"\n [attr.aria-label]=\"showImage ? null : fallbackLabel\"\n>\n @if (showImage) {\n <img\n [attr.src]=\"src\"\n [attr.alt]=\"altText\"\n class=\"h-full w-full object-cover\"\n (error)=\"onImageError()\"\n />\n } @else {\n <span [class]=\"fallbackClass\" aria-hidden=\"true\">{{ fallbackText }}</span>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
291
|
+
}
|
|
292
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAvatarComponent, decorators: [{
|
|
293
|
+
type: Component,
|
|
294
|
+
args: [{ selector: 'cxs-avatar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [class]=\"avatarClass\"\n [attr.role]=\"showImage ? null : 'img'\"\n [attr.aria-label]=\"showImage ? null : fallbackLabel\"\n>\n @if (showImage) {\n <img\n [attr.src]=\"src\"\n [attr.alt]=\"altText\"\n class=\"h-full w-full object-cover\"\n (error)=\"onImageError()\"\n />\n } @else {\n <span [class]=\"fallbackClass\" aria-hidden=\"true\">{{ fallbackText }}</span>\n }\n</div>\n" }]
|
|
295
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
296
|
+
type: Attribute,
|
|
297
|
+
args: ['class']
|
|
298
|
+
}] }], propDecorators: { src: [{
|
|
299
|
+
type: Input
|
|
300
|
+
}], name: [{
|
|
301
|
+
type: Input
|
|
302
|
+
}], alt: [{
|
|
303
|
+
type: Input
|
|
304
|
+
}], size: [{
|
|
305
|
+
type: Input
|
|
306
|
+
}], shape: [{
|
|
307
|
+
type: Input
|
|
308
|
+
}] } });
|
|
309
|
+
|
|
310
|
+
const BASE_CLASSES$6 = 'flex flex-wrap items-center gap-x-1 gap-y-1';
|
|
111
311
|
const ITEM_CLASSES = 'flex items-center gap-1';
|
|
112
312
|
const LINK_BASE_CLASSES = 'rounded-[var(--cxs-radius-md)] transition-colors focus-visible:outline focus-visible:outline-2 ' +
|
|
113
313
|
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
@@ -135,7 +335,7 @@ class CxsBreadcrumbComponent {
|
|
|
135
335
|
variant = 'default';
|
|
136
336
|
disabled = false;
|
|
137
337
|
get listClass() {
|
|
138
|
-
return [BASE_CLASSES$
|
|
338
|
+
return [BASE_CLASSES$6, SIZE_CLASSES$5[this.size], this.disabled ? 'opacity-60' : '']
|
|
139
339
|
.filter(Boolean)
|
|
140
340
|
.join(' ');
|
|
141
341
|
}
|
|
@@ -177,11 +377,11 @@ class CxsBreadcrumbComponent {
|
|
|
177
377
|
return item.rel ?? null;
|
|
178
378
|
}
|
|
179
379
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
180
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsBreadcrumbComponent, isStandalone: true, selector: "cxs-breadcrumb", inputs: { items: "items", separator: "separator", ariaLabel: "ariaLabel", size: "size", variant: "variant", disabled: "disabled" }, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ol [class]=\"listClass\">\n @for (item of items; track item; let last = $last) {\n <li [class]=\"itemClass\">\n @if (isLink(item, last)) {\n <a\n [class]=\"getLinkClass(item)\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n [class]=\"getLabelClass(item, last)\"\n [attr.aria-current]=\"last ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n @if (!last && separator) {\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
380
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsBreadcrumbComponent, isStandalone: true, selector: "cxs-breadcrumb", inputs: { items: "items", separator: "separator", ariaLabel: "ariaLabel", size: "size", variant: "variant", disabled: "disabled" }, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel\">\r\n <ol [class]=\"listClass\">\r\n @for (item of items; track item; let last = $last) {\r\n <li [class]=\"itemClass\">\r\n @if (isLink(item, last)) {\r\n <a\r\n [class]=\"getLinkClass(item)\"\r\n [attr.href]=\"item.href\"\r\n [attr.target]=\"item.target ?? null\"\r\n [attr.rel]=\"getItemRel(item)\"\r\n [attr.aria-label]=\"item.ariaLabel ?? null\"\r\n >\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n [class]=\"getLabelClass(item, last)\"\r\n [attr.aria-current]=\"last ? 'page' : null\"\r\n >\r\n {{ item.label }}\r\n </span>\r\n }\r\n @if (!last && separator) {\r\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
181
381
|
}
|
|
182
382
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, decorators: [{
|
|
183
383
|
type: Component,
|
|
184
|
-
args: [{ selector: 'cxs-breadcrumb', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ol [class]=\"listClass\">\n @for (item of items; track item; let last = $last) {\n <li [class]=\"itemClass\">\n @if (isLink(item, last)) {\n <a\n [class]=\"getLinkClass(item)\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n [class]=\"getLabelClass(item, last)\"\n [attr.aria-current]=\"last ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n @if (!last && separator) {\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n" }]
|
|
384
|
+
args: [{ selector: 'cxs-breadcrumb', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [attr.aria-label]=\"ariaLabel\">\r\n <ol [class]=\"listClass\">\r\n @for (item of items; track item; let last = $last) {\r\n <li [class]=\"itemClass\">\r\n @if (isLink(item, last)) {\r\n <a\r\n [class]=\"getLinkClass(item)\"\r\n [attr.href]=\"item.href\"\r\n [attr.target]=\"item.target ?? null\"\r\n [attr.rel]=\"getItemRel(item)\"\r\n [attr.aria-label]=\"item.ariaLabel ?? null\"\r\n >\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n [class]=\"getLabelClass(item, last)\"\r\n [attr.aria-current]=\"last ? 'page' : null\"\r\n >\r\n {{ item.label }}\r\n </span>\r\n }\r\n @if (!last && separator) {\r\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n" }]
|
|
185
385
|
}], propDecorators: { items: [{
|
|
186
386
|
type: Input
|
|
187
387
|
}], separator: [{
|
|
@@ -196,10 +396,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
196
396
|
type: Input
|
|
197
397
|
}] } });
|
|
198
398
|
|
|
199
|
-
const BASE_CLASSES$
|
|
399
|
+
const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
|
|
200
400
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
201
401
|
'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-50';
|
|
202
|
-
const VARIANT_CLASSES$
|
|
402
|
+
const VARIANT_CLASSES$5 = {
|
|
203
403
|
primary: 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)] ' +
|
|
204
404
|
'hover:bg-[var(--cxs-color-primary-hover)] shadow-[var(--cxs-shadow-sm)]',
|
|
205
405
|
secondary: 'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
@@ -225,16 +425,16 @@ class CxsButtonComponent {
|
|
|
225
425
|
return this.disabled || this.loading;
|
|
226
426
|
}
|
|
227
427
|
get buttonClass() {
|
|
228
|
-
return [BASE_CLASSES$
|
|
428
|
+
return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$5[this.variant], this.hostClass]
|
|
229
429
|
.filter(Boolean)
|
|
230
430
|
.join(' ');
|
|
231
431
|
}
|
|
232
432
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
233
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type" }, ngImport: i0, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
433
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type" }, ngImport: i0, template: "<button\r\n [class]=\"buttonClass\"\r\n [attr.type]=\"type\"\r\n [disabled]=\"isDisabled\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n>\r\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
234
434
|
}
|
|
235
435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, decorators: [{
|
|
236
436
|
type: Component,
|
|
237
|
-
args: [{ selector: 'cxs-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n" }]
|
|
437
|
+
args: [{ selector: 'cxs-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\r\n [class]=\"buttonClass\"\r\n [attr.type]=\"type\"\r\n [disabled]=\"isDisabled\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n>\r\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n" }]
|
|
238
438
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
239
439
|
type: Attribute,
|
|
240
440
|
args: ['class']
|
|
@@ -250,9 +450,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
250
450
|
type: Input
|
|
251
451
|
}] } });
|
|
252
452
|
|
|
253
|
-
const BASE_CLASSES$
|
|
453
|
+
const BASE_CLASSES$4 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
254
454
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
|
|
255
|
-
const VARIANT_CLASSES$
|
|
455
|
+
const VARIANT_CLASSES$4 = {
|
|
256
456
|
surface: 'bg-[var(--cxs-color-surface)]',
|
|
257
457
|
muted: 'bg-[var(--cxs-color-surface-hover)]',
|
|
258
458
|
outline: 'bg-transparent'
|
|
@@ -270,8 +470,8 @@ class CxsCardComponent {
|
|
|
270
470
|
ariaLabelledby;
|
|
271
471
|
get cardClass() {
|
|
272
472
|
return [
|
|
273
|
-
BASE_CLASSES$
|
|
274
|
-
VARIANT_CLASSES$
|
|
473
|
+
BASE_CLASSES$4,
|
|
474
|
+
VARIANT_CLASSES$4[this.variant],
|
|
275
475
|
SIZE_CLASSES$3[this.size],
|
|
276
476
|
this.elevated ? 'shadow-[var(--cxs-shadow-sm)]' : ''
|
|
277
477
|
]
|
|
@@ -279,11 +479,11 @@ class CxsCardComponent {
|
|
|
279
479
|
.join(' ');
|
|
280
480
|
}
|
|
281
481
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
282
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsCardComponent, isStandalone: true, selector: "cxs-card", inputs: { variant: "variant", size: "size", elevated: "elevated", ariaLabel: "ariaLabel", ariaLabelledby: "ariaLabelledby" }, ngImport: i0, template: "<section\n [class]=\"cardClass\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n>\n <ng-content></ng-content>\n</section>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
482
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsCardComponent, isStandalone: true, selector: "cxs-card", inputs: { variant: "variant", size: "size", elevated: "elevated", ariaLabel: "ariaLabel", ariaLabelledby: "ariaLabelledby" }, ngImport: i0, template: "<section\r\n [class]=\"cardClass\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-labelledby]=\"ariaLabelledby\"\r\n>\r\n <ng-content></ng-content>\r\n</section>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
283
483
|
}
|
|
284
484
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, decorators: [{
|
|
285
485
|
type: Component,
|
|
286
|
-
args: [{ selector: 'cxs-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n [class]=\"cardClass\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n>\n <ng-content></ng-content>\n</section>\n" }]
|
|
486
|
+
args: [{ selector: 'cxs-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\r\n [class]=\"cardClass\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-labelledby]=\"ariaLabelledby\"\r\n>\r\n <ng-content></ng-content>\r\n</section>\r\n" }]
|
|
287
487
|
}], propDecorators: { variant: [{
|
|
288
488
|
type: Input
|
|
289
489
|
}], size: [{
|
|
@@ -401,7 +601,7 @@ class CxsCheckboxComponent {
|
|
|
401
601
|
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
402
602
|
multi: true
|
|
403
603
|
}
|
|
404
|
-
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-checked]=\"ariaChecked\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"checked\"\n [indeterminate]=\"indeterminate\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onCheckboxChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n @if (label) {\n <span [class]=\"labelClass\">{{ label }}</span>\n } @else {\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n }\n</label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
604
|
+
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"checkbox\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-checked]=\"ariaChecked\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"checked\"\r\n [indeterminate]=\"indeterminate\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onCheckboxChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n @if (label) {\r\n <span [class]=\"labelClass\">{{ label }}</span>\r\n } @else {\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n</label>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
405
605
|
}
|
|
406
606
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCheckboxComponent, decorators: [{
|
|
407
607
|
type: Component,
|
|
@@ -411,7 +611,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
411
611
|
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
412
612
|
multi: true
|
|
413
613
|
}
|
|
414
|
-
], template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-checked]=\"ariaChecked\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"checked\"\n [indeterminate]=\"indeterminate\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onCheckboxChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n @if (label) {\n <span [class]=\"labelClass\">{{ label }}</span>\n } @else {\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n }\n</label>\n" }]
|
|
614
|
+
], template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"checkbox\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-checked]=\"ariaChecked\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"checked\"\r\n [indeterminate]=\"indeterminate\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onCheckboxChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n @if (label) {\r\n <span [class]=\"labelClass\">{{ label }}</span>\r\n } @else {\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n</label>\r\n" }]
|
|
415
615
|
}], propDecorators: { checked: [{
|
|
416
616
|
type: Input
|
|
417
617
|
}], indeterminate: [{
|
|
@@ -438,175 +638,1103 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
438
638
|
type: Output
|
|
439
639
|
}] } });
|
|
440
640
|
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
outline: 'bg-[var(--cxs-color-surface)]',
|
|
449
|
-
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
450
|
-
};
|
|
451
|
-
const SIZE_CLASSES$2 = {
|
|
452
|
-
sm: 'h-8 px-3 text-sm',
|
|
453
|
-
md: 'h-10 px-3 text-sm',
|
|
454
|
-
lg: 'h-12 px-4 text-base'
|
|
455
|
-
};
|
|
456
|
-
const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
|
|
457
|
-
'focus-visible:outline-[var(--cxs-color-danger)]';
|
|
458
|
-
const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
|
|
459
|
-
'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
|
|
460
|
-
const NAV_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
461
|
-
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
641
|
+
const WRAPPER_BASE_CLASSES$2 = 'relative overflow-hidden rounded-[var(--cxs-radius-md)]';
|
|
642
|
+
const TRACK_CLASSES = 'flex transition-transform duration-500 ease-out';
|
|
643
|
+
const SLIDE_BASE_CLASSES = 'w-full flex-shrink-0';
|
|
644
|
+
const IMAGE_CLASSES = 'h-56 w-full object-cover';
|
|
645
|
+
const CONTENT_CLASSES = 'absolute inset-x-0 bottom-0 bg-[rgba(15,23,42,0.6)] px-4 py-3 text-sm text-white';
|
|
646
|
+
const CONTROL_CLASSES = 'absolute top-1/2 -translate-y-1/2 inline-flex h-9 w-9 items-center justify-center rounded-full ' +
|
|
647
|
+
'bg-[rgba(15,23,42,0.7)] text-white transition hover:bg-[rgba(15,23,42,0.85)] ' +
|
|
462
648
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
463
649
|
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
id;
|
|
482
|
-
name;
|
|
483
|
-
min;
|
|
484
|
-
max;
|
|
485
|
-
placeholder;
|
|
486
|
-
ariaLabel;
|
|
487
|
-
ariaDescribedby;
|
|
488
|
-
valueChange = new EventEmitter();
|
|
489
|
-
static nextId = 0;
|
|
490
|
-
fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
|
|
491
|
-
disabledFromControl = false;
|
|
492
|
-
onChange = () => { };
|
|
493
|
-
onTouched = () => { };
|
|
494
|
-
isOpen = false;
|
|
495
|
-
displayMonth = new Date();
|
|
496
|
-
calendarDays = [];
|
|
497
|
-
weekDayLabels = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
498
|
-
get isDisabled() {
|
|
499
|
-
return this.disabled || this.disabledFromControl;
|
|
500
|
-
}
|
|
501
|
-
get panelId() {
|
|
502
|
-
return this.id ? `${this.id}-panel` : this.fallbackId;
|
|
503
|
-
}
|
|
504
|
-
get inputClass() {
|
|
505
|
-
return [
|
|
506
|
-
BASE_CLASSES$2,
|
|
507
|
-
SIZE_CLASSES$2[this.size],
|
|
508
|
-
VARIANT_CLASSES$2[this.variant],
|
|
509
|
-
this.invalid ? INVALID_CLASSES$3 : ''
|
|
510
|
-
]
|
|
511
|
-
.filter(Boolean)
|
|
512
|
-
.join(' ');
|
|
650
|
+
const INDICATOR_CONTAINER_CLASSES = 'absolute bottom-3 left-1/2 flex -translate-x-1/2 items-center gap-2';
|
|
651
|
+
const INDICATOR_BASE_CLASSES = 'h-2 w-2 rounded-full bg-white/50 transition-colors';
|
|
652
|
+
const INDICATOR_ACTIVE_CLASSES = 'bg-white';
|
|
653
|
+
class CxsCarouselComponent {
|
|
654
|
+
hostClass;
|
|
655
|
+
items = [];
|
|
656
|
+
activeIndex = 0;
|
|
657
|
+
autoplay = false;
|
|
658
|
+
interval = 4000;
|
|
659
|
+
loop = true;
|
|
660
|
+
showControls = true;
|
|
661
|
+
showIndicators = true;
|
|
662
|
+
ariaLabel = 'Carousel';
|
|
663
|
+
activeIndexChange = new EventEmitter();
|
|
664
|
+
timerId = null;
|
|
665
|
+
constructor(hostClass) {
|
|
666
|
+
this.hostClass = hostClass;
|
|
513
667
|
}
|
|
514
|
-
|
|
515
|
-
|
|
668
|
+
ngOnChanges(changes) {
|
|
669
|
+
if (changes['items'] || changes['autoplay'] || changes['interval']) {
|
|
670
|
+
this.resetAutoplay();
|
|
671
|
+
}
|
|
672
|
+
if (changes['activeIndex']) {
|
|
673
|
+
this.activeIndex = this.clampIndex(this.activeIndex);
|
|
674
|
+
}
|
|
516
675
|
}
|
|
517
|
-
|
|
518
|
-
|
|
676
|
+
ngAfterViewInit() {
|
|
677
|
+
this.resetAutoplay();
|
|
519
678
|
}
|
|
520
|
-
|
|
521
|
-
|
|
679
|
+
ngOnDestroy() {
|
|
680
|
+
this.clearAutoplay();
|
|
522
681
|
}
|
|
523
|
-
|
|
524
|
-
this.
|
|
525
|
-
this.syncDisplayMonthWithValue();
|
|
682
|
+
get wrapperClass() {
|
|
683
|
+
return [WRAPPER_BASE_CLASSES$2, this.hostClass].filter(Boolean).join(' ');
|
|
526
684
|
}
|
|
527
|
-
|
|
528
|
-
this.
|
|
685
|
+
get trackStyle() {
|
|
686
|
+
return `translateX(-${this.activeIndex * 100}%)`;
|
|
529
687
|
}
|
|
530
|
-
|
|
531
|
-
|
|
688
|
+
get trackClass() {
|
|
689
|
+
return TRACK_CLASSES;
|
|
532
690
|
}
|
|
533
|
-
|
|
534
|
-
|
|
691
|
+
get slideClass() {
|
|
692
|
+
return SLIDE_BASE_CLASSES;
|
|
535
693
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const nextValue = target.value;
|
|
539
|
-
this.value = nextValue;
|
|
540
|
-
this.onChange(nextValue);
|
|
541
|
-
this.valueChange.emit(nextValue);
|
|
694
|
+
get imageClass() {
|
|
695
|
+
return IMAGE_CLASSES;
|
|
542
696
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const nextValue = this.formatDate(day.date);
|
|
548
|
-
this.value = nextValue;
|
|
549
|
-
this.onChange(nextValue);
|
|
550
|
-
this.valueChange.emit(nextValue);
|
|
551
|
-
this.isOpen = false;
|
|
697
|
+
get contentClass() {
|
|
698
|
+
return CONTENT_CLASSES;
|
|
552
699
|
}
|
|
553
|
-
|
|
554
|
-
|
|
700
|
+
get controlClass() {
|
|
701
|
+
return CONTROL_CLASSES;
|
|
555
702
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
this.isOpen = true;
|
|
561
|
-
this.syncDisplayMonthWithValue();
|
|
703
|
+
get indicatorContainerClass() {
|
|
704
|
+
return INDICATOR_CONTAINER_CLASSES;
|
|
562
705
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
this.open();
|
|
706
|
+
indicatorClass(isActive) {
|
|
707
|
+
return [INDICATOR_BASE_CLASSES, isActive ? INDICATOR_ACTIVE_CLASSES : '']
|
|
708
|
+
.filter(Boolean)
|
|
709
|
+
.join(' ');
|
|
569
710
|
}
|
|
570
|
-
|
|
571
|
-
this.
|
|
572
|
-
this.updateCalendar();
|
|
711
|
+
previous() {
|
|
712
|
+
this.goTo(this.activeIndex - 1);
|
|
573
713
|
}
|
|
574
|
-
|
|
575
|
-
this.
|
|
576
|
-
this.updateCalendar();
|
|
714
|
+
next() {
|
|
715
|
+
this.goTo(this.activeIndex + 1);
|
|
577
716
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
day.isToday ? DAY_TODAY : '',
|
|
583
|
-
this.isSelected(day.date) ? DAY_SELECTED : DAY_HOVER
|
|
584
|
-
]
|
|
585
|
-
.filter(Boolean)
|
|
586
|
-
.join(' ');
|
|
717
|
+
goTo(index) {
|
|
718
|
+
const nextIndex = this.normalizeIndex(index);
|
|
719
|
+
this.activeIndex = nextIndex;
|
|
720
|
+
this.activeIndexChange.emit(nextIndex);
|
|
587
721
|
}
|
|
588
|
-
|
|
589
|
-
if (
|
|
590
|
-
return;
|
|
722
|
+
normalizeIndex(index) {
|
|
723
|
+
if (!this.items.length) {
|
|
724
|
+
return 0;
|
|
591
725
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
726
|
+
if (this.loop) {
|
|
727
|
+
const total = this.items.length;
|
|
728
|
+
return (index + total) % total;
|
|
595
729
|
}
|
|
730
|
+
return this.clampIndex(index);
|
|
596
731
|
}
|
|
597
|
-
|
|
598
|
-
if (
|
|
599
|
-
return;
|
|
732
|
+
clampIndex(index) {
|
|
733
|
+
if (!this.items.length) {
|
|
734
|
+
return 0;
|
|
600
735
|
}
|
|
601
|
-
this.
|
|
736
|
+
return Math.min(Math.max(0, index), this.items.length - 1);
|
|
602
737
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
this.
|
|
606
|
-
|
|
738
|
+
resetAutoplay() {
|
|
739
|
+
this.clearAutoplay();
|
|
740
|
+
if (!this.autoplay || this.items.length <= 1) {
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
const intervalMs = Math.max(1000, this.interval);
|
|
744
|
+
this.timerId = setInterval(() => {
|
|
745
|
+
this.next();
|
|
746
|
+
}, intervalMs);
|
|
747
|
+
}
|
|
748
|
+
clearAutoplay() {
|
|
749
|
+
if (this.timerId) {
|
|
750
|
+
clearInterval(this.timerId);
|
|
751
|
+
this.timerId = null;
|
|
752
|
+
}
|
|
607
753
|
}
|
|
608
|
-
|
|
609
|
-
|
|
754
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCarouselComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
755
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsCarouselComponent, isStandalone: true, selector: "cxs-carousel", inputs: { items: "items", activeIndex: "activeIndex", autoplay: "autoplay", interval: "interval", loop: "loop", showControls: "showControls", showIndicators: "showIndicators", ariaLabel: "ariaLabel" }, outputs: { activeIndexChange: "activeIndexChange" }, usesOnChanges: true, ngImport: i0, template: "<div [class]=\"wrapperClass\" [attr.aria-label]=\"ariaLabel\">\n <div [class]=\"trackClass\" [style.transform]=\"trackStyle\">\n @for (item of items; track item) {\n <div [class]=\"slideClass\">\n @if (item.image) {\n <img\n [class]=\"imageClass\"\n [attr.src]=\"item.image\"\n [attr.alt]=\"item.alt ?? item.title ?? 'Carousel image'\"\n />\n }\n @if (item.title || item.description) {\n <div [class]=\"contentClass\">\n @if (item.title) {\n <div class=\"text-base font-semibold\">{{ item.title }}</div>\n }\n @if (item.description) {\n <div class=\"text-sm text-white/80\">{{ item.description }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (showControls && items.length > 1) {\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"left: 12px\"\n aria-label=\"Previous slide\"\n (click)=\"previous()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"right: 12px\"\n aria-label=\"Next slide\"\n (click)=\"next()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n\n </button>\n }\n\n @if (showIndicators && items.length > 1) {\n <div [class]=\"indicatorContainerClass\">\n @for (item of items; track item; let index = $index) {\n <button\n type=\"button\"\n [class]=\"indicatorClass(index === activeIndex)\"\n [attr.aria-label]=\"'Go to slide ' + (index + 1)\"\n (click)=\"goTo(index)\"\n ></button>\n }\n </div>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
756
|
+
}
|
|
757
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCarouselComponent, decorators: [{
|
|
758
|
+
type: Component,
|
|
759
|
+
args: [{ selector: 'cxs-carousel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\" [attr.aria-label]=\"ariaLabel\">\n <div [class]=\"trackClass\" [style.transform]=\"trackStyle\">\n @for (item of items; track item) {\n <div [class]=\"slideClass\">\n @if (item.image) {\n <img\n [class]=\"imageClass\"\n [attr.src]=\"item.image\"\n [attr.alt]=\"item.alt ?? item.title ?? 'Carousel image'\"\n />\n }\n @if (item.title || item.description) {\n <div [class]=\"contentClass\">\n @if (item.title) {\n <div class=\"text-base font-semibold\">{{ item.title }}</div>\n }\n @if (item.description) {\n <div class=\"text-sm text-white/80\">{{ item.description }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (showControls && items.length > 1) {\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"left: 12px\"\n aria-label=\"Previous slide\"\n (click)=\"previous()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"right: 12px\"\n aria-label=\"Next slide\"\n (click)=\"next()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n\n </button>\n }\n\n @if (showIndicators && items.length > 1) {\n <div [class]=\"indicatorContainerClass\">\n @for (item of items; track item; let index = $index) {\n <button\n type=\"button\"\n [class]=\"indicatorClass(index === activeIndex)\"\n [attr.aria-label]=\"'Go to slide ' + (index + 1)\"\n (click)=\"goTo(index)\"\n ></button>\n }\n </div>\n }\n</div>\n" }]
|
|
760
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
761
|
+
type: Attribute,
|
|
762
|
+
args: ['class']
|
|
763
|
+
}] }], propDecorators: { items: [{
|
|
764
|
+
type: Input
|
|
765
|
+
}], activeIndex: [{
|
|
766
|
+
type: Input
|
|
767
|
+
}], autoplay: [{
|
|
768
|
+
type: Input
|
|
769
|
+
}], interval: [{
|
|
770
|
+
type: Input
|
|
771
|
+
}], loop: [{
|
|
772
|
+
type: Input
|
|
773
|
+
}], showControls: [{
|
|
774
|
+
type: Input
|
|
775
|
+
}], showIndicators: [{
|
|
776
|
+
type: Input
|
|
777
|
+
}], ariaLabel: [{
|
|
778
|
+
type: Input
|
|
779
|
+
}], activeIndexChange: [{
|
|
780
|
+
type: Output
|
|
781
|
+
}] } });
|
|
782
|
+
|
|
783
|
+
class CxsDataTableCellDirective {
|
|
784
|
+
template;
|
|
785
|
+
columnKey = '';
|
|
786
|
+
constructor(template) {
|
|
787
|
+
this.template = template;
|
|
788
|
+
}
|
|
789
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
790
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: CxsDataTableCellDirective, isStandalone: true, selector: "[cxsDataTableCell]", inputs: { columnKey: ["cxsDataTableCell", "columnKey"] }, ngImport: i0 });
|
|
791
|
+
}
|
|
792
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableCellDirective, decorators: [{
|
|
793
|
+
type: Directive,
|
|
794
|
+
args: [{
|
|
795
|
+
selector: '[cxsDataTableCell]',
|
|
796
|
+
standalone: true
|
|
797
|
+
}]
|
|
798
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { columnKey: [{
|
|
799
|
+
type: Input,
|
|
800
|
+
args: ['cxsDataTableCell']
|
|
801
|
+
}] } });
|
|
802
|
+
|
|
803
|
+
const WRAPPER_BASE_CLASSES$1 = 'w-full overflow-hidden';
|
|
804
|
+
const WRAPPER_BORDERED_CLASSES$1 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
|
|
805
|
+
const TABLE_BASE_CLASSES$1 = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
|
|
806
|
+
const TABLE_COMPACT_CLASSES$1 = 'text-xs';
|
|
807
|
+
const HEADER_ROW_CLASSES$1 = 'border-b border-[var(--cxs-color-border)] text-xs font-semibold ' +
|
|
808
|
+
'text-[var(--cxs-color-on-surface-muted)]';
|
|
809
|
+
const HEADER_CELL_BASE_CLASSES$1 = 'px-3 py-2 text-left';
|
|
810
|
+
const HEADER_BUTTON_CLASSES = 'inline-flex items-center gap-2 rounded-[var(--cxs-radius-md)] px-2 py-1 ' +
|
|
811
|
+
'transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
812
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
813
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
814
|
+
const HEADER_FILTER_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
815
|
+
'bg-[var(--cxs-color-surface)] px-2 py-1 text-xs text-[var(--cxs-color-on-surface)] ' +
|
|
816
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
|
|
817
|
+
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
818
|
+
const BODY_ROW_BASE_CLASSES$1 = 'border-b border-[var(--cxs-color-border)] last:border-b-0';
|
|
819
|
+
const BODY_ROW_STRIPED_CLASSES$1 = 'odd:bg-[var(--cxs-color-surface)] even:bg-[var(--cxs-color-surface-hover)]';
|
|
820
|
+
const BODY_CELL_BASE_CLASSES$1 = 'px-3 py-2 align-top';
|
|
821
|
+
const BODY_CELL_COMPACT_CLASSES$1 = 'px-2 py-1.5';
|
|
822
|
+
const ALIGN_CLASSES$1 = {
|
|
823
|
+
left: 'text-left',
|
|
824
|
+
center: 'text-center',
|
|
825
|
+
right: 'text-right'
|
|
826
|
+
};
|
|
827
|
+
const EMPTY_ROW_CLASSES$1 = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
828
|
+
const PAGINATION_CLASSES = 'mt-4 flex flex-wrap items-center justify-between gap-3 text-sm text-[var(--cxs-color-on-surface)]';
|
|
829
|
+
const PAGE_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
830
|
+
'px-3 py-1.5 text-sm transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
831
|
+
'disabled:cursor-not-allowed disabled:opacity-60';
|
|
832
|
+
const PAGE_SELECT_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
833
|
+
'px-2 py-1 text-sm';
|
|
834
|
+
const TOOLBAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 text-sm text-[var(--cxs-color-on-surface)]';
|
|
835
|
+
const TOOLBAR_GROUP_CLASSES = 'flex flex-wrap items-center gap-2';
|
|
836
|
+
const TOOLBAR_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
837
|
+
'bg-[var(--cxs-color-surface)] px-3 py-2 text-sm text-[var(--cxs-color-on-surface)] ' +
|
|
838
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
|
|
839
|
+
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
840
|
+
const TOOLBAR_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
841
|
+
'px-3 py-2 text-sm transition-colors hover:bg-[var(--cxs-color-surface-hover)]';
|
|
842
|
+
const BULK_BAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 rounded-[var(--cxs-radius-md)] ' +
|
|
843
|
+
'border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] px-3 py-2 text-sm';
|
|
844
|
+
const RESIZE_HANDLE_CLASSES = 'absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none';
|
|
845
|
+
class CxsDataTableComponent {
|
|
846
|
+
hostClass;
|
|
847
|
+
columns = [];
|
|
848
|
+
data = [];
|
|
849
|
+
caption;
|
|
850
|
+
ariaLabel = 'Data table';
|
|
851
|
+
striped = false;
|
|
852
|
+
bordered = false;
|
|
853
|
+
compact = false;
|
|
854
|
+
loading = false;
|
|
855
|
+
emptyMessage = 'No data available';
|
|
856
|
+
emptyCell = '—';
|
|
857
|
+
pageSize = 10;
|
|
858
|
+
pageIndex = 1;
|
|
859
|
+
pageSizeOptions = [10, 20, 50];
|
|
860
|
+
showPagination = true;
|
|
861
|
+
showPageSize = true;
|
|
862
|
+
manualPagination = false;
|
|
863
|
+
total;
|
|
864
|
+
sortKey;
|
|
865
|
+
sortDirection = 'asc';
|
|
866
|
+
manualSort = false;
|
|
867
|
+
showToolbar = true;
|
|
868
|
+
showFilters = true;
|
|
869
|
+
showColumnVisibility = true;
|
|
870
|
+
showGlobalSearch = true;
|
|
871
|
+
manualFilter = false;
|
|
872
|
+
selectable = false;
|
|
873
|
+
rowKey = 'id';
|
|
874
|
+
selectedKeys = [];
|
|
875
|
+
bulkActions = [];
|
|
876
|
+
pageChange = new EventEmitter();
|
|
877
|
+
pageSizeChange = new EventEmitter();
|
|
878
|
+
sortChange = new EventEmitter();
|
|
879
|
+
filterChange = new EventEmitter();
|
|
880
|
+
selectionChange = new EventEmitter();
|
|
881
|
+
bulkAction = new EventEmitter();
|
|
882
|
+
cellTemplates;
|
|
883
|
+
currentPage = 1;
|
|
884
|
+
currentPageSize = 10;
|
|
885
|
+
globalFilter = '';
|
|
886
|
+
columnFilters = {};
|
|
887
|
+
columnVisibility = {};
|
|
888
|
+
columnWidths = {};
|
|
889
|
+
isResizing = false;
|
|
890
|
+
resizingColumn;
|
|
891
|
+
pinnedOffsetsLeft = {};
|
|
892
|
+
pinnedOffsetsRight = {};
|
|
893
|
+
filtersOpen = true;
|
|
894
|
+
resizeStartX = 0;
|
|
895
|
+
resizeStartWidth = 0;
|
|
896
|
+
constructor(hostClass) {
|
|
897
|
+
this.hostClass = hostClass;
|
|
898
|
+
}
|
|
899
|
+
ngOnChanges(changes) {
|
|
900
|
+
if (changes['pageIndex']) {
|
|
901
|
+
this.currentPage = Math.max(1, this.pageIndex);
|
|
902
|
+
}
|
|
903
|
+
if (changes['pageSize']) {
|
|
904
|
+
this.currentPageSize = Math.max(1, this.pageSize);
|
|
905
|
+
}
|
|
906
|
+
if (changes['columns']) {
|
|
907
|
+
this.initializeVisibility();
|
|
908
|
+
this.initializeWidths();
|
|
909
|
+
this.updatePinnedOffsets();
|
|
910
|
+
}
|
|
911
|
+
if (changes['showFilters']) {
|
|
912
|
+
this.filtersOpen = this.showFilters;
|
|
913
|
+
}
|
|
914
|
+
if (changes['selectedKeys']) {
|
|
915
|
+
this.selectedKeys = [...this.selectedKeys];
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
get wrapperClass() {
|
|
919
|
+
return [
|
|
920
|
+
WRAPPER_BASE_CLASSES$1,
|
|
921
|
+
this.bordered ? WRAPPER_BORDERED_CLASSES$1 : '',
|
|
922
|
+
this.hostClass
|
|
923
|
+
]
|
|
924
|
+
.filter(Boolean)
|
|
925
|
+
.join(' ');
|
|
926
|
+
}
|
|
927
|
+
get tableClass() {
|
|
928
|
+
return [TABLE_BASE_CLASSES$1, this.compact ? TABLE_COMPACT_CLASSES$1 : '']
|
|
929
|
+
.filter(Boolean)
|
|
930
|
+
.join(' ');
|
|
931
|
+
}
|
|
932
|
+
get headerRowClass() {
|
|
933
|
+
return HEADER_ROW_CLASSES$1;
|
|
934
|
+
}
|
|
935
|
+
get bodyRowClass() {
|
|
936
|
+
return [
|
|
937
|
+
BODY_ROW_BASE_CLASSES$1,
|
|
938
|
+
this.striped ? BODY_ROW_STRIPED_CLASSES$1 : ''
|
|
939
|
+
]
|
|
940
|
+
.filter(Boolean)
|
|
941
|
+
.join(' ');
|
|
942
|
+
}
|
|
943
|
+
get emptyRowClass() {
|
|
944
|
+
return EMPTY_ROW_CLASSES$1;
|
|
945
|
+
}
|
|
946
|
+
get paginationClass() {
|
|
947
|
+
return PAGINATION_CLASSES;
|
|
948
|
+
}
|
|
949
|
+
get pageButtonClass() {
|
|
950
|
+
return PAGE_BUTTON_CLASSES;
|
|
951
|
+
}
|
|
952
|
+
get pageSelectClass() {
|
|
953
|
+
return PAGE_SELECT_CLASSES;
|
|
954
|
+
}
|
|
955
|
+
get toolbarClass() {
|
|
956
|
+
return TOOLBAR_CLASSES;
|
|
957
|
+
}
|
|
958
|
+
get toolbarGroupClass() {
|
|
959
|
+
return TOOLBAR_GROUP_CLASSES;
|
|
960
|
+
}
|
|
961
|
+
get toolbarInputClass() {
|
|
962
|
+
return TOOLBAR_INPUT_CLASSES;
|
|
963
|
+
}
|
|
964
|
+
get toolbarButtonClass() {
|
|
965
|
+
return TOOLBAR_BUTTON_CLASSES;
|
|
966
|
+
}
|
|
967
|
+
get bulkBarClass() {
|
|
968
|
+
return BULK_BAR_CLASSES;
|
|
969
|
+
}
|
|
970
|
+
get resizeHandleClass() {
|
|
971
|
+
return RESIZE_HANDLE_CLASSES;
|
|
972
|
+
}
|
|
973
|
+
get colSpan() {
|
|
974
|
+
return Math.max(this.visibleColumns.length + (this.selectable ? 1 : 0), 1);
|
|
975
|
+
}
|
|
976
|
+
get totalItems() {
|
|
977
|
+
if (this.manualPagination && this.total !== undefined) {
|
|
978
|
+
return this.total;
|
|
979
|
+
}
|
|
980
|
+
return this.data.length;
|
|
981
|
+
}
|
|
982
|
+
get totalPages() {
|
|
983
|
+
return Math.max(1, Math.ceil(this.totalItems / this.currentPageSize));
|
|
984
|
+
}
|
|
985
|
+
get pageLabel() {
|
|
986
|
+
return `Page ${this.currentPage} of ${this.totalPages}`;
|
|
987
|
+
}
|
|
988
|
+
get displayRows() {
|
|
989
|
+
const filtered = this.manualFilter ? this.data : this.getFilteredData(this.data);
|
|
990
|
+
const sorted = this.manualSort ? filtered : this.getSortedData(filtered);
|
|
991
|
+
if (this.manualPagination) {
|
|
992
|
+
return sorted;
|
|
993
|
+
}
|
|
994
|
+
const start = (this.currentPage - 1) * this.currentPageSize;
|
|
995
|
+
return sorted.slice(start, start + this.currentPageSize);
|
|
996
|
+
}
|
|
997
|
+
get visibleColumns() {
|
|
998
|
+
return this.columns.filter((column) => this.columnVisibility[column.key] !== false);
|
|
999
|
+
}
|
|
1000
|
+
get selectedCount() {
|
|
1001
|
+
return this.selectedKeys.length;
|
|
1002
|
+
}
|
|
1003
|
+
get allVisibleSelected() {
|
|
1004
|
+
if (!this.displayRows.length) {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
return this.displayRows.every((row) => this.isSelected(row));
|
|
1008
|
+
}
|
|
1009
|
+
get someVisibleSelected() {
|
|
1010
|
+
return this.displayRows.some((row) => this.isSelected(row)) && !this.allVisibleSelected;
|
|
1011
|
+
}
|
|
1012
|
+
headerCellClass(column) {
|
|
1013
|
+
return [
|
|
1014
|
+
HEADER_CELL_BASE_CLASSES$1,
|
|
1015
|
+
ALIGN_CLASSES$1[column.align ?? 'left'],
|
|
1016
|
+
column.headerClass ?? ''
|
|
1017
|
+
]
|
|
1018
|
+
.filter(Boolean)
|
|
1019
|
+
.join(' ');
|
|
1020
|
+
}
|
|
1021
|
+
headerButtonClass() {
|
|
1022
|
+
return HEADER_BUTTON_CLASSES;
|
|
1023
|
+
}
|
|
1024
|
+
headerFilterInputClass() {
|
|
1025
|
+
return HEADER_FILTER_INPUT_CLASSES;
|
|
1026
|
+
}
|
|
1027
|
+
bodyCellClass(column) {
|
|
1028
|
+
return [
|
|
1029
|
+
BODY_CELL_BASE_CLASSES$1,
|
|
1030
|
+
this.compact ? BODY_CELL_COMPACT_CLASSES$1 : '',
|
|
1031
|
+
ALIGN_CLASSES$1[column.align ?? 'left'],
|
|
1032
|
+
column.cellClass ?? ''
|
|
1033
|
+
]
|
|
1034
|
+
.filter(Boolean)
|
|
1035
|
+
.join(' ');
|
|
1036
|
+
}
|
|
1037
|
+
cellTemplate(columnKey) {
|
|
1038
|
+
if (!this.cellTemplates) {
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1041
|
+
return this.cellTemplates.find((template) => template.columnKey === columnKey)?.template ?? null;
|
|
1042
|
+
}
|
|
1043
|
+
cellValue(row, column) {
|
|
1044
|
+
const value = row[column.key];
|
|
1045
|
+
if (column.formatter) {
|
|
1046
|
+
return column.formatter(value, row);
|
|
1047
|
+
}
|
|
1048
|
+
if (value === null || value === undefined || value === '') {
|
|
1049
|
+
return this.emptyCell;
|
|
1050
|
+
}
|
|
1051
|
+
return String(value);
|
|
1052
|
+
}
|
|
1053
|
+
columnWidth(column) {
|
|
1054
|
+
return this.columnWidths[column.key] ?? column.width ?? null;
|
|
1055
|
+
}
|
|
1056
|
+
columnMinWidth(column) {
|
|
1057
|
+
if (column.minWidth) {
|
|
1058
|
+
return `${column.minWidth}px`;
|
|
1059
|
+
}
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
pinnedStyle(column) {
|
|
1063
|
+
if (!column.pinned) {
|
|
1064
|
+
return null;
|
|
1065
|
+
}
|
|
1066
|
+
if (column.pinned === 'left') {
|
|
1067
|
+
return { left: `${this.pinnedOffsetsLeft[column.key] ?? 0}px` };
|
|
1068
|
+
}
|
|
1069
|
+
return { right: `${this.pinnedOffsetsRight[column.key] ?? 0}px` };
|
|
1070
|
+
}
|
|
1071
|
+
pinnedLeft(column) {
|
|
1072
|
+
const style = this.pinnedStyle(column);
|
|
1073
|
+
return style ? style['left'] ?? null : null;
|
|
1074
|
+
}
|
|
1075
|
+
pinnedRight(column) {
|
|
1076
|
+
const style = this.pinnedStyle(column);
|
|
1077
|
+
return style ? style['right'] ?? null : null;
|
|
1078
|
+
}
|
|
1079
|
+
pinnedClass(column) {
|
|
1080
|
+
if (!column.pinned) {
|
|
1081
|
+
return '';
|
|
1082
|
+
}
|
|
1083
|
+
return 'sticky z-10';
|
|
1084
|
+
}
|
|
1085
|
+
ariaSort(column) {
|
|
1086
|
+
if (!column.sortable) {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
if (this.sortKey !== column.key) {
|
|
1090
|
+
return 'none';
|
|
1091
|
+
}
|
|
1092
|
+
return this.sortDirection === 'asc' ? 'ascending' : 'descending';
|
|
1093
|
+
}
|
|
1094
|
+
onSort(column) {
|
|
1095
|
+
if (!column.sortable) {
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
if (this.sortKey === column.key) {
|
|
1099
|
+
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
this.sortKey = column.key;
|
|
1103
|
+
this.sortDirection = 'asc';
|
|
1104
|
+
}
|
|
1105
|
+
this.sortChange.emit({
|
|
1106
|
+
key: this.sortKey,
|
|
1107
|
+
direction: this.sortDirection
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
goToPage(page) {
|
|
1111
|
+
const nextPage = Math.min(Math.max(1, page), this.totalPages);
|
|
1112
|
+
this.currentPage = nextPage;
|
|
1113
|
+
this.pageChange.emit(nextPage);
|
|
1114
|
+
}
|
|
1115
|
+
nextPage() {
|
|
1116
|
+
this.goToPage(this.currentPage + 1);
|
|
1117
|
+
}
|
|
1118
|
+
previousPage() {
|
|
1119
|
+
this.goToPage(this.currentPage - 1);
|
|
1120
|
+
}
|
|
1121
|
+
onPageSizeChange(value) {
|
|
1122
|
+
const nextSize = Number(value);
|
|
1123
|
+
if (!Number.isFinite(nextSize) || nextSize <= 0) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
this.currentPageSize = nextSize;
|
|
1127
|
+
this.pageSizeChange.emit(nextSize);
|
|
1128
|
+
this.goToPage(1);
|
|
1129
|
+
}
|
|
1130
|
+
onGlobalFilterChange(value) {
|
|
1131
|
+
this.globalFilter = value;
|
|
1132
|
+
this.emitFilterChange();
|
|
1133
|
+
this.goToPage(1);
|
|
1134
|
+
}
|
|
1135
|
+
onColumnFilterChange(columnKey, value) {
|
|
1136
|
+
this.columnFilters[columnKey] = value;
|
|
1137
|
+
this.emitFilterChange();
|
|
1138
|
+
this.goToPage(1);
|
|
1139
|
+
}
|
|
1140
|
+
columnFilterValue(columnKey) {
|
|
1141
|
+
return this.columnFilters[columnKey] || '';
|
|
1142
|
+
}
|
|
1143
|
+
toggleColumnVisibility(columnKey) {
|
|
1144
|
+
this.columnVisibility[columnKey] = !this.columnVisibility[columnKey];
|
|
1145
|
+
this.updatePinnedOffsets();
|
|
1146
|
+
}
|
|
1147
|
+
toggleSelectAll() {
|
|
1148
|
+
if (this.allVisibleSelected) {
|
|
1149
|
+
this.selectedKeys = this.selectedKeys.filter((key) => !this.displayRows.some((row) => this.rowIdentifier(row) === key));
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
const keysToAdd = this.displayRows
|
|
1153
|
+
.map((row) => this.rowIdentifier(row))
|
|
1154
|
+
.filter((key) => !this.selectedKeys.includes(key));
|
|
1155
|
+
this.selectedKeys = [...this.selectedKeys, ...keysToAdd];
|
|
1156
|
+
}
|
|
1157
|
+
this.selectionChange.emit([...this.selectedKeys]);
|
|
1158
|
+
}
|
|
1159
|
+
toggleRowSelection(row) {
|
|
1160
|
+
const key = this.rowIdentifier(row);
|
|
1161
|
+
if (this.selectedKeys.includes(key)) {
|
|
1162
|
+
this.selectedKeys = this.selectedKeys.filter((id) => id !== key);
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
this.selectedKeys = [...this.selectedKeys, key];
|
|
1166
|
+
}
|
|
1167
|
+
this.selectionChange.emit([...this.selectedKeys]);
|
|
1168
|
+
}
|
|
1169
|
+
isSelected(row) {
|
|
1170
|
+
return this.selectedKeys.includes(this.rowIdentifier(row));
|
|
1171
|
+
}
|
|
1172
|
+
runBulkAction(actionId) {
|
|
1173
|
+
this.bulkAction.emit({
|
|
1174
|
+
id: actionId,
|
|
1175
|
+
selected: this.data.filter((row) => this.selectedKeys.includes(this.rowIdentifier(row)))
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
onResizeStart(event, column) {
|
|
1179
|
+
if (column.resizable === false) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
event.preventDefault();
|
|
1183
|
+
const header = event.target.closest('th');
|
|
1184
|
+
if (!header) {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
this.isResizing = true;
|
|
1188
|
+
this.resizingColumn = column.key;
|
|
1189
|
+
this.resizeStartX = event.clientX;
|
|
1190
|
+
this.resizeStartWidth = header.getBoundingClientRect().width;
|
|
1191
|
+
const onMove = (moveEvent) => {
|
|
1192
|
+
if (!this.isResizing || !this.resizingColumn) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const delta = moveEvent.clientX - this.resizeStartX;
|
|
1196
|
+
const minWidth = column.minWidth ?? 80;
|
|
1197
|
+
const nextWidth = Math.max(minWidth, this.resizeStartWidth + delta);
|
|
1198
|
+
this.columnWidths[this.resizingColumn] = `${Math.round(nextWidth)}px`;
|
|
1199
|
+
this.updatePinnedOffsets();
|
|
1200
|
+
};
|
|
1201
|
+
const onUp = () => {
|
|
1202
|
+
this.isResizing = false;
|
|
1203
|
+
this.resizingColumn = undefined;
|
|
1204
|
+
window.removeEventListener('mousemove', onMove);
|
|
1205
|
+
window.removeEventListener('mouseup', onUp);
|
|
1206
|
+
};
|
|
1207
|
+
window.addEventListener('mousemove', onMove);
|
|
1208
|
+
window.addEventListener('mouseup', onUp);
|
|
1209
|
+
}
|
|
1210
|
+
getSortedData(rows) {
|
|
1211
|
+
if (!this.sortKey) {
|
|
1212
|
+
return rows;
|
|
1213
|
+
}
|
|
1214
|
+
const direction = this.sortDirection === 'asc' ? 1 : -1;
|
|
1215
|
+
return [...rows].sort((a, b) => {
|
|
1216
|
+
const valueA = a[this.sortKey ?? ''];
|
|
1217
|
+
const valueB = b[this.sortKey ?? ''];
|
|
1218
|
+
const normalizedA = valueA === null || valueA === undefined ? '' : String(valueA);
|
|
1219
|
+
const normalizedB = valueB === null || valueB === undefined ? '' : String(valueB);
|
|
1220
|
+
return normalizedA.localeCompare(normalizedB, undefined, { numeric: true }) * direction;
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
getFilteredData(rows) {
|
|
1224
|
+
const global = this.globalFilter.trim().toLowerCase();
|
|
1225
|
+
const filters = this.columnFilters;
|
|
1226
|
+
return rows.filter((row) => {
|
|
1227
|
+
if (global) {
|
|
1228
|
+
const matchesGlobal = this.visibleColumns.some((column) => {
|
|
1229
|
+
const value = row[column.key];
|
|
1230
|
+
return String(value ?? '').toLowerCase().includes(global);
|
|
1231
|
+
});
|
|
1232
|
+
if (!matchesGlobal) {
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return this.visibleColumns.every((column) => {
|
|
1237
|
+
if (!column.filterable) {
|
|
1238
|
+
return true;
|
|
1239
|
+
}
|
|
1240
|
+
const filterValue = (filters[column.key] ?? '').trim().toLowerCase();
|
|
1241
|
+
if (!filterValue) {
|
|
1242
|
+
return true;
|
|
1243
|
+
}
|
|
1244
|
+
const raw = row[column.key];
|
|
1245
|
+
const normalized = String(raw ?? '').toLowerCase();
|
|
1246
|
+
if (column.filterType === 'select') {
|
|
1247
|
+
return normalized === filterValue;
|
|
1248
|
+
}
|
|
1249
|
+
return normalized.includes(filterValue);
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
emitFilterChange() {
|
|
1254
|
+
this.filterChange.emit({
|
|
1255
|
+
global: this.globalFilter,
|
|
1256
|
+
columns: { ...this.columnFilters }
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
initializeVisibility() {
|
|
1260
|
+
this.columnVisibility = this.columns.reduce((acc, column) => {
|
|
1261
|
+
acc[column.key] = column.visible !== false;
|
|
1262
|
+
return acc;
|
|
1263
|
+
}, {});
|
|
1264
|
+
}
|
|
1265
|
+
initializeWidths() {
|
|
1266
|
+
this.columnWidths = this.columns.reduce((acc, column) => {
|
|
1267
|
+
if (column.width) {
|
|
1268
|
+
acc[column.key] = column.width;
|
|
1269
|
+
}
|
|
1270
|
+
return acc;
|
|
1271
|
+
}, {});
|
|
1272
|
+
}
|
|
1273
|
+
updatePinnedOffsets() {
|
|
1274
|
+
const leftOffsets = {};
|
|
1275
|
+
const rightOffsets = {};
|
|
1276
|
+
let left = 0;
|
|
1277
|
+
let right = 0;
|
|
1278
|
+
const columns = this.visibleColumns;
|
|
1279
|
+
columns.forEach((column) => {
|
|
1280
|
+
if (column.pinned === 'left') {
|
|
1281
|
+
leftOffsets[column.key] = left;
|
|
1282
|
+
left += this.getWidthValue(column);
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
[...columns].reverse().forEach((column) => {
|
|
1286
|
+
if (column.pinned === 'right') {
|
|
1287
|
+
rightOffsets[column.key] = right;
|
|
1288
|
+
right += this.getWidthValue(column);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
this.pinnedOffsetsLeft = leftOffsets;
|
|
1292
|
+
this.pinnedOffsetsRight = rightOffsets;
|
|
1293
|
+
}
|
|
1294
|
+
getWidthValue(column) {
|
|
1295
|
+
const width = this.columnWidths[column.key] ?? column.width;
|
|
1296
|
+
if (!width) {
|
|
1297
|
+
return 160;
|
|
1298
|
+
}
|
|
1299
|
+
const match = width.match(/(\d+)(px)?/);
|
|
1300
|
+
if (match) {
|
|
1301
|
+
return Number(match[1]);
|
|
1302
|
+
}
|
|
1303
|
+
return 160;
|
|
1304
|
+
}
|
|
1305
|
+
rowIdentifier(row) {
|
|
1306
|
+
const value = row[this.rowKey];
|
|
1307
|
+
if (value === undefined || value === null) {
|
|
1308
|
+
return JSON.stringify(row);
|
|
1309
|
+
}
|
|
1310
|
+
return value;
|
|
1311
|
+
}
|
|
1312
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1313
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDataTableComponent, isStandalone: true, selector: "cxs-data-table", inputs: { columns: "columns", data: "data", caption: "caption", ariaLabel: "ariaLabel", striped: "striped", bordered: "bordered", compact: "compact", loading: "loading", emptyMessage: "emptyMessage", emptyCell: "emptyCell", pageSize: "pageSize", pageIndex: "pageIndex", pageSizeOptions: "pageSizeOptions", showPagination: "showPagination", showPageSize: "showPageSize", manualPagination: "manualPagination", total: "total", sortKey: "sortKey", sortDirection: "sortDirection", manualSort: "manualSort", showToolbar: "showToolbar", showFilters: "showFilters", showColumnVisibility: "showColumnVisibility", showGlobalSearch: "showGlobalSearch", manualFilter: "manualFilter", selectable: "selectable", rowKey: "rowKey", selectedKeys: "selectedKeys", bulkActions: "bulkActions" }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", filterChange: "filterChange", selectionChange: "selectionChange", bulkAction: "bulkAction" }, queries: [{ propertyName: "cellTemplates", predicate: CxsDataTableCellDirective }], usesOnChanges: true, ngImport: i0, template: "@if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n placeholder=\"Filter\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (cellTemplate(column.key); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: row[column.key], column }\"\n ></ng-container>\n } @else {\n {{ cellValue(row, column) }}\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1314
|
+
}
|
|
1315
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, decorators: [{
|
|
1316
|
+
type: Component,
|
|
1317
|
+
args: [{ selector: 'cxs-data-table', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n placeholder=\"Filter\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (cellTemplate(column.key); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: row[column.key], column }\"\n ></ng-container>\n } @else {\n {{ cellValue(row, column) }}\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n" }]
|
|
1318
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1319
|
+
type: Attribute,
|
|
1320
|
+
args: ['class']
|
|
1321
|
+
}] }], propDecorators: { columns: [{
|
|
1322
|
+
type: Input
|
|
1323
|
+
}], data: [{
|
|
1324
|
+
type: Input
|
|
1325
|
+
}], caption: [{
|
|
1326
|
+
type: Input
|
|
1327
|
+
}], ariaLabel: [{
|
|
1328
|
+
type: Input
|
|
1329
|
+
}], striped: [{
|
|
1330
|
+
type: Input
|
|
1331
|
+
}], bordered: [{
|
|
1332
|
+
type: Input
|
|
1333
|
+
}], compact: [{
|
|
1334
|
+
type: Input
|
|
1335
|
+
}], loading: [{
|
|
1336
|
+
type: Input
|
|
1337
|
+
}], emptyMessage: [{
|
|
1338
|
+
type: Input
|
|
1339
|
+
}], emptyCell: [{
|
|
1340
|
+
type: Input
|
|
1341
|
+
}], pageSize: [{
|
|
1342
|
+
type: Input
|
|
1343
|
+
}], pageIndex: [{
|
|
1344
|
+
type: Input
|
|
1345
|
+
}], pageSizeOptions: [{
|
|
1346
|
+
type: Input
|
|
1347
|
+
}], showPagination: [{
|
|
1348
|
+
type: Input
|
|
1349
|
+
}], showPageSize: [{
|
|
1350
|
+
type: Input
|
|
1351
|
+
}], manualPagination: [{
|
|
1352
|
+
type: Input
|
|
1353
|
+
}], total: [{
|
|
1354
|
+
type: Input
|
|
1355
|
+
}], sortKey: [{
|
|
1356
|
+
type: Input
|
|
1357
|
+
}], sortDirection: [{
|
|
1358
|
+
type: Input
|
|
1359
|
+
}], manualSort: [{
|
|
1360
|
+
type: Input
|
|
1361
|
+
}], showToolbar: [{
|
|
1362
|
+
type: Input
|
|
1363
|
+
}], showFilters: [{
|
|
1364
|
+
type: Input
|
|
1365
|
+
}], showColumnVisibility: [{
|
|
1366
|
+
type: Input
|
|
1367
|
+
}], showGlobalSearch: [{
|
|
1368
|
+
type: Input
|
|
1369
|
+
}], manualFilter: [{
|
|
1370
|
+
type: Input
|
|
1371
|
+
}], selectable: [{
|
|
1372
|
+
type: Input
|
|
1373
|
+
}], rowKey: [{
|
|
1374
|
+
type: Input
|
|
1375
|
+
}], selectedKeys: [{
|
|
1376
|
+
type: Input
|
|
1377
|
+
}], bulkActions: [{
|
|
1378
|
+
type: Input
|
|
1379
|
+
}], pageChange: [{
|
|
1380
|
+
type: Output
|
|
1381
|
+
}], pageSizeChange: [{
|
|
1382
|
+
type: Output
|
|
1383
|
+
}], sortChange: [{
|
|
1384
|
+
type: Output
|
|
1385
|
+
}], filterChange: [{
|
|
1386
|
+
type: Output
|
|
1387
|
+
}], selectionChange: [{
|
|
1388
|
+
type: Output
|
|
1389
|
+
}], bulkAction: [{
|
|
1390
|
+
type: Output
|
|
1391
|
+
}], cellTemplates: [{
|
|
1392
|
+
type: ContentChildren,
|
|
1393
|
+
args: [CxsDataTableCellDirective]
|
|
1394
|
+
}] } });
|
|
1395
|
+
|
|
1396
|
+
const OVERLAY_CLASSES = 'fixed inset-0 z-50 flex items-center justify-center bg-[rgba(15,23,42,0.45)] p-4';
|
|
1397
|
+
const PANEL_BASE_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1398
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] shadow-[var(--cxs-shadow-sm)] ' +
|
|
1399
|
+
'p-6 outline-none';
|
|
1400
|
+
const PANEL_SIZE_CLASSES = {
|
|
1401
|
+
sm: 'max-w-sm',
|
|
1402
|
+
md: 'max-w-lg',
|
|
1403
|
+
lg: 'max-w-2xl'
|
|
1404
|
+
};
|
|
1405
|
+
const TITLE_CLASSES$1 = 'text-lg font-semibold';
|
|
1406
|
+
const DESCRIPTION_CLASSES = 'mt-1 text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
1407
|
+
const BODY_CLASSES = 'mt-4 text-sm text-[var(--cxs-color-on-surface)]';
|
|
1408
|
+
const ACTIONS_CLASSES$1 = 'mt-6 flex flex-wrap items-center justify-end gap-2 ' +
|
|
1409
|
+
'[&>*]:flex [&>*]:flex-wrap [&>*]:items-center [&>*]:justify-end [&>*]:gap-2';
|
|
1410
|
+
const CLOSE_BUTTON_CLASSES$1 = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
1411
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
1412
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1413
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1414
|
+
class CxsDialogComponent {
|
|
1415
|
+
hostClass;
|
|
1416
|
+
static nextId = 0;
|
|
1417
|
+
open = false;
|
|
1418
|
+
title;
|
|
1419
|
+
description;
|
|
1420
|
+
ariaLabel = 'Dialog';
|
|
1421
|
+
size = 'md';
|
|
1422
|
+
dismissible = true;
|
|
1423
|
+
closeOnBackdrop = true;
|
|
1424
|
+
closeOnEscape = true;
|
|
1425
|
+
openChange = new EventEmitter();
|
|
1426
|
+
closed = new EventEmitter();
|
|
1427
|
+
dialogPanel;
|
|
1428
|
+
titleId = `cxs-dialog-title-${CxsDialogComponent.nextId++}`;
|
|
1429
|
+
descriptionId = `cxs-dialog-description-${CxsDialogComponent.nextId++}`;
|
|
1430
|
+
constructor(hostClass) {
|
|
1431
|
+
this.hostClass = hostClass;
|
|
1432
|
+
}
|
|
1433
|
+
ngOnChanges(changes) {
|
|
1434
|
+
if (changes['open']?.currentValue) {
|
|
1435
|
+
this.focusPanelSoon();
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
ngAfterViewInit() {
|
|
1439
|
+
if (this.open) {
|
|
1440
|
+
this.focusPanelSoon();
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
get overlayClass() {
|
|
1444
|
+
return OVERLAY_CLASSES;
|
|
1445
|
+
}
|
|
1446
|
+
get panelClass() {
|
|
1447
|
+
return [PANEL_BASE_CLASSES, PANEL_SIZE_CLASSES[this.size], this.hostClass]
|
|
1448
|
+
.filter(Boolean)
|
|
1449
|
+
.join(' ');
|
|
1450
|
+
}
|
|
1451
|
+
get titleClass() {
|
|
1452
|
+
return TITLE_CLASSES$1;
|
|
1453
|
+
}
|
|
1454
|
+
get descriptionClass() {
|
|
1455
|
+
return DESCRIPTION_CLASSES;
|
|
1456
|
+
}
|
|
1457
|
+
get bodyClass() {
|
|
1458
|
+
return BODY_CLASSES;
|
|
1459
|
+
}
|
|
1460
|
+
get actionsClass() {
|
|
1461
|
+
return ACTIONS_CLASSES$1;
|
|
1462
|
+
}
|
|
1463
|
+
get closeButtonClass() {
|
|
1464
|
+
return CLOSE_BUTTON_CLASSES$1;
|
|
1465
|
+
}
|
|
1466
|
+
get ariaLabelValue() {
|
|
1467
|
+
if (this.title) {
|
|
1468
|
+
return null;
|
|
1469
|
+
}
|
|
1470
|
+
return this.ariaLabel;
|
|
1471
|
+
}
|
|
1472
|
+
requestClose(reason) {
|
|
1473
|
+
this.openChange.emit(false);
|
|
1474
|
+
this.closed.emit(reason);
|
|
1475
|
+
}
|
|
1476
|
+
onBackdropClick(event) {
|
|
1477
|
+
if (!this.closeOnBackdrop || !this.open) {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
if (event.target === event.currentTarget) {
|
|
1481
|
+
this.requestClose('backdrop');
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
onKeydown(event) {
|
|
1485
|
+
if (!this.closeOnEscape || !this.open) {
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
if (event.key === 'Escape') {
|
|
1489
|
+
event.preventDefault();
|
|
1490
|
+
this.requestClose('escape');
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
focusPanelSoon() {
|
|
1494
|
+
queueMicrotask(() => {
|
|
1495
|
+
this.dialogPanel?.nativeElement.focus();
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1499
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDialogComponent, isStandalone: true, selector: "cxs-dialog", inputs: { open: "open", title: "title", description: "description", ariaLabel: "ariaLabel", size: "size", dismissible: "dismissible", closeOnBackdrop: "closeOnBackdrop", closeOnEscape: "closeOnEscape" }, outputs: { openChange: "openChange", closed: "closed" }, viewQueries: [{ propertyName: "dialogPanel", first: true, predicate: ["dialogPanel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1500
|
+
}
|
|
1501
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, decorators: [{
|
|
1502
|
+
type: Component,
|
|
1503
|
+
args: [{ selector: 'cxs-dialog', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n" }]
|
|
1504
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1505
|
+
type: Attribute,
|
|
1506
|
+
args: ['class']
|
|
1507
|
+
}] }], propDecorators: { open: [{
|
|
1508
|
+
type: Input
|
|
1509
|
+
}], title: [{
|
|
1510
|
+
type: Input
|
|
1511
|
+
}], description: [{
|
|
1512
|
+
type: Input
|
|
1513
|
+
}], ariaLabel: [{
|
|
1514
|
+
type: Input
|
|
1515
|
+
}], size: [{
|
|
1516
|
+
type: Input
|
|
1517
|
+
}], dismissible: [{
|
|
1518
|
+
type: Input
|
|
1519
|
+
}], closeOnBackdrop: [{
|
|
1520
|
+
type: Input
|
|
1521
|
+
}], closeOnEscape: [{
|
|
1522
|
+
type: Input
|
|
1523
|
+
}], openChange: [{
|
|
1524
|
+
type: Output
|
|
1525
|
+
}], closed: [{
|
|
1526
|
+
type: Output
|
|
1527
|
+
}], dialogPanel: [{
|
|
1528
|
+
type: ViewChild,
|
|
1529
|
+
args: ['dialogPanel']
|
|
1530
|
+
}] } });
|
|
1531
|
+
|
|
1532
|
+
const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1533
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
1534
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
1535
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1536
|
+
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
1537
|
+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
1538
|
+
const VARIANT_CLASSES$3 = {
|
|
1539
|
+
outline: 'bg-[var(--cxs-color-surface)]',
|
|
1540
|
+
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
1541
|
+
};
|
|
1542
|
+
const SIZE_CLASSES$2 = {
|
|
1543
|
+
sm: 'h-8 px-3 text-sm',
|
|
1544
|
+
md: 'h-10 px-3 text-sm',
|
|
1545
|
+
lg: 'h-12 px-4 text-base'
|
|
1546
|
+
};
|
|
1547
|
+
const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
|
|
1548
|
+
'focus-visible:outline-[var(--cxs-color-danger)]';
|
|
1549
|
+
const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
|
|
1550
|
+
'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
|
|
1551
|
+
const NAV_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
1552
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
1553
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1554
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1555
|
+
const SELECT_CLASSES = 'h-8 rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1556
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] text-xs px-2 ' +
|
|
1557
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1558
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1559
|
+
const DAY_BUTTON_BASE = 'flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] text-xs ' +
|
|
1560
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1561
|
+
'focus-visible:outline-[var(--cxs-color-focus)] disabled:cursor-not-allowed disabled:opacity-40';
|
|
1562
|
+
const DAY_OUTSIDE_MONTH = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
1563
|
+
const DAY_TODAY = 'border border-[var(--cxs-color-primary)]';
|
|
1564
|
+
const DAY_SELECTED = 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)]';
|
|
1565
|
+
const DAY_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
|
|
1566
|
+
class CxsDatepickerComponent {
|
|
1567
|
+
value = '';
|
|
1568
|
+
variant = 'outline';
|
|
1569
|
+
size = 'md';
|
|
1570
|
+
useNative = true;
|
|
1571
|
+
disabled = false;
|
|
1572
|
+
readonly = false;
|
|
1573
|
+
required = false;
|
|
1574
|
+
invalid = false;
|
|
1575
|
+
autofocus = false;
|
|
1576
|
+
id;
|
|
1577
|
+
name;
|
|
1578
|
+
min;
|
|
1579
|
+
max;
|
|
1580
|
+
placeholder;
|
|
1581
|
+
ariaLabel;
|
|
1582
|
+
ariaDescribedby;
|
|
1583
|
+
valueChange = new EventEmitter();
|
|
1584
|
+
static nextId = 0;
|
|
1585
|
+
fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
|
|
1586
|
+
disabledFromControl = false;
|
|
1587
|
+
onChange = () => { };
|
|
1588
|
+
onTouched = () => { };
|
|
1589
|
+
isOpen = false;
|
|
1590
|
+
displayMonth = new Date();
|
|
1591
|
+
calendarDays = [];
|
|
1592
|
+
weekDayLabels = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
1593
|
+
monthOptions = Array.from({ length: 12 }, (_, index) => ({
|
|
1594
|
+
value: index,
|
|
1595
|
+
label: new Date(2020, index, 1).toLocaleString('en-US', { month: 'short' })
|
|
1596
|
+
}));
|
|
1597
|
+
get isDisabled() {
|
|
1598
|
+
return this.disabled || this.disabledFromControl;
|
|
1599
|
+
}
|
|
1600
|
+
get panelId() {
|
|
1601
|
+
return this.id ? `${this.id}-panel` : this.fallbackId;
|
|
1602
|
+
}
|
|
1603
|
+
get inputClass() {
|
|
1604
|
+
return [
|
|
1605
|
+
BASE_CLASSES$3,
|
|
1606
|
+
SIZE_CLASSES$2[this.size],
|
|
1607
|
+
VARIANT_CLASSES$3[this.variant],
|
|
1608
|
+
this.invalid ? INVALID_CLASSES$3 : ''
|
|
1609
|
+
]
|
|
1610
|
+
.filter(Boolean)
|
|
1611
|
+
.join(' ');
|
|
1612
|
+
}
|
|
1613
|
+
get popoverClass() {
|
|
1614
|
+
return POPOVER_CLASSES;
|
|
1615
|
+
}
|
|
1616
|
+
get navButtonClass() {
|
|
1617
|
+
return NAV_BUTTON_CLASSES;
|
|
1618
|
+
}
|
|
1619
|
+
get selectClass() {
|
|
1620
|
+
return SELECT_CLASSES;
|
|
1621
|
+
}
|
|
1622
|
+
get displayMonthLabel() {
|
|
1623
|
+
return this.displayMonth.toLocaleString('en-US', { month: 'long', year: 'numeric' });
|
|
1624
|
+
}
|
|
1625
|
+
get yearOptions() {
|
|
1626
|
+
const baseYear = this.displayMonth.getFullYear();
|
|
1627
|
+
const minYear = this.parseDate(this.min)?.getFullYear() ?? baseYear - 10;
|
|
1628
|
+
const maxYear = this.parseDate(this.max)?.getFullYear() ?? baseYear + 10;
|
|
1629
|
+
const start = Math.min(minYear, maxYear);
|
|
1630
|
+
const end = Math.max(minYear, maxYear);
|
|
1631
|
+
return Array.from({ length: end - start + 1 }, (_, index) => start + index);
|
|
1632
|
+
}
|
|
1633
|
+
writeValue(value) {
|
|
1634
|
+
this.value = value ?? '';
|
|
1635
|
+
this.syncDisplayMonthWithValue();
|
|
1636
|
+
}
|
|
1637
|
+
registerOnChange(fn) {
|
|
1638
|
+
this.onChange = fn;
|
|
1639
|
+
}
|
|
1640
|
+
registerOnTouched(fn) {
|
|
1641
|
+
this.onTouched = fn;
|
|
1642
|
+
}
|
|
1643
|
+
setDisabledState(isDisabled) {
|
|
1644
|
+
this.disabledFromControl = isDisabled;
|
|
1645
|
+
}
|
|
1646
|
+
onInput(event) {
|
|
1647
|
+
const target = event.target;
|
|
1648
|
+
const nextValue = target.value;
|
|
1649
|
+
this.value = nextValue;
|
|
1650
|
+
this.onChange(nextValue);
|
|
1651
|
+
this.valueChange.emit(nextValue);
|
|
1652
|
+
}
|
|
1653
|
+
onDateSelect(day) {
|
|
1654
|
+
if (day.disabled || this.isDisabled) {
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const nextValue = this.formatDate(day.date);
|
|
1658
|
+
this.value = nextValue;
|
|
1659
|
+
this.onChange(nextValue);
|
|
1660
|
+
this.valueChange.emit(nextValue);
|
|
1661
|
+
this.isOpen = false;
|
|
1662
|
+
}
|
|
1663
|
+
onBlur() {
|
|
1664
|
+
this.onTouched();
|
|
1665
|
+
}
|
|
1666
|
+
open() {
|
|
1667
|
+
if (this.isDisabled || this.useNative) {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
this.isOpen = true;
|
|
1671
|
+
this.syncDisplayMonthWithValue();
|
|
1672
|
+
}
|
|
1673
|
+
toggle() {
|
|
1674
|
+
if (this.isOpen) {
|
|
1675
|
+
this.isOpen = false;
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
this.open();
|
|
1679
|
+
}
|
|
1680
|
+
prevMonth() {
|
|
1681
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), this.displayMonth.getMonth() - 1, 1);
|
|
1682
|
+
this.updateCalendar();
|
|
1683
|
+
}
|
|
1684
|
+
nextMonth() {
|
|
1685
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), this.displayMonth.getMonth() + 1, 1);
|
|
1686
|
+
this.updateCalendar();
|
|
1687
|
+
}
|
|
1688
|
+
onMonthChange(event) {
|
|
1689
|
+
const target = event.target;
|
|
1690
|
+
const nextMonth = Number(target.value);
|
|
1691
|
+
if (Number.isNaN(nextMonth)) {
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), nextMonth, 1);
|
|
1695
|
+
this.updateCalendar();
|
|
1696
|
+
}
|
|
1697
|
+
onYearChange(event) {
|
|
1698
|
+
const target = event.target;
|
|
1699
|
+
const nextYear = Number(target.value);
|
|
1700
|
+
if (Number.isNaN(nextYear)) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
this.displayMonth = new Date(nextYear, this.displayMonth.getMonth(), 1);
|
|
1704
|
+
this.updateCalendar();
|
|
1705
|
+
}
|
|
1706
|
+
dayButtonClass(day) {
|
|
1707
|
+
return [
|
|
1708
|
+
DAY_BUTTON_BASE,
|
|
1709
|
+
day.inMonth ? '' : DAY_OUTSIDE_MONTH,
|
|
1710
|
+
day.isToday ? DAY_TODAY : '',
|
|
1711
|
+
this.isSelected(day.date) ? DAY_SELECTED : DAY_HOVER
|
|
1712
|
+
]
|
|
1713
|
+
.filter(Boolean)
|
|
1714
|
+
.join(' ');
|
|
1715
|
+
}
|
|
1716
|
+
onDocumentClick(event) {
|
|
1717
|
+
if (this.useNative || !this.isOpen) {
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const target = event.target;
|
|
1721
|
+
if (target && !target.closest(`#${this.panelId}`) && !target.closest(`[data-cxs-datepicker="${this.panelId}"]`)) {
|
|
1722
|
+
this.isOpen = false;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
onEscape() {
|
|
1726
|
+
if (this.useNative || !this.isOpen) {
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
this.isOpen = false;
|
|
1730
|
+
}
|
|
1731
|
+
syncDisplayMonthWithValue() {
|
|
1732
|
+
const selected = this.parseDate(this.value);
|
|
1733
|
+
this.displayMonth = selected ?? new Date();
|
|
1734
|
+
this.updateCalendar();
|
|
1735
|
+
}
|
|
1736
|
+
updateCalendar() {
|
|
1737
|
+
const year = this.displayMonth.getFullYear();
|
|
610
1738
|
const month = this.displayMonth.getMonth();
|
|
611
1739
|
const startOfMonth = new Date(year, month, 1);
|
|
612
1740
|
const startDay = startOfMonth.getDay();
|
|
@@ -663,7 +1791,7 @@ class CxsDatepickerComponent {
|
|
|
663
1791
|
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
664
1792
|
multi: true
|
|
665
1793
|
}
|
|
666
|
-
], ngImport: i0, template: "@if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n} @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n
|
|
1794
|
+
], ngImport: i0, template: "@if (useNative) {\r\n <input\r\n type=\"date\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.min]=\"min\"\r\n [attr.max]=\"max\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n} @else {\r\n <div class=\"relative w-full\">\r\n <input\r\n type=\"text\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\r\n [attr.aria-controls]=\"panelId\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [attr.data-cxs-datepicker]=\"panelId\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"true\"\r\n [required]=\"required\"\r\n (click)=\"open()\"\r\n (focus)=\"open()\"\r\n (blur)=\"onBlur()\"\r\n />\r\n @if (isOpen) {\r\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\r\n <div class=\"flex items-center justify-between\">\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\r\n </svg>\r\n </button>\r\n <div class=\"flex items-center gap-2\">\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getMonth()\"\r\n aria-label=\"Month\"\r\n (change)=\"onMonthChange($event)\"\r\n >\r\n @for (month of monthOptions; track month.value) {\r\n <option [value]=\"month.value\">{{ month.label }}</option>\r\n }\r\n </select>\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getFullYear()\"\r\n aria-label=\"Year\"\r\n (change)=\"onYearChange($event)\"\r\n >\r\n @for (year of yearOptions; track year) {\r\n <option [value]=\"year\">{{ year }}</option>\r\n }\r\n </select>\r\n </div>\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\r\n @for (label of weekDayLabels; track label) {\r\n <div>{{ label }}</div>\r\n }\r\n </div>\r\n\r\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\r\n @for (day of calendarDays; track day.key) {\r\n <button\r\n type=\"button\"\r\n [class]=\"dayButtonClass(day)\"\r\n [disabled]=\"day.disabled\"\r\n [attr.data-date]=\"day.key\"\r\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n (click)=\"onDateSelect(day)\"\r\n >\r\n {{ day.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
667
1795
|
}
|
|
668
1796
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, decorators: [{
|
|
669
1797
|
type: Component,
|
|
@@ -673,7 +1801,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
673
1801
|
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
674
1802
|
multi: true
|
|
675
1803
|
}
|
|
676
|
-
], template: "@if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n} @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n
|
|
1804
|
+
], template: "@if (useNative) {\r\n <input\r\n type=\"date\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.min]=\"min\"\r\n [attr.max]=\"max\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n} @else {\r\n <div class=\"relative w-full\">\r\n <input\r\n type=\"text\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\r\n [attr.aria-controls]=\"panelId\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [attr.data-cxs-datepicker]=\"panelId\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"true\"\r\n [required]=\"required\"\r\n (click)=\"open()\"\r\n (focus)=\"open()\"\r\n (blur)=\"onBlur()\"\r\n />\r\n @if (isOpen) {\r\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\r\n <div class=\"flex items-center justify-between\">\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\r\n </svg>\r\n </button>\r\n <div class=\"flex items-center gap-2\">\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getMonth()\"\r\n aria-label=\"Month\"\r\n (change)=\"onMonthChange($event)\"\r\n >\r\n @for (month of monthOptions; track month.value) {\r\n <option [value]=\"month.value\">{{ month.label }}</option>\r\n }\r\n </select>\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getFullYear()\"\r\n aria-label=\"Year\"\r\n (change)=\"onYearChange($event)\"\r\n >\r\n @for (year of yearOptions; track year) {\r\n <option [value]=\"year\">{{ year }}</option>\r\n }\r\n </select>\r\n </div>\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\r\n @for (label of weekDayLabels; track label) {\r\n <div>{{ label }}</div>\r\n }\r\n </div>\r\n\r\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\r\n @for (day of calendarDays; track day.key) {\r\n <button\r\n type=\"button\"\r\n [class]=\"dayButtonClass(day)\"\r\n [disabled]=\"day.disabled\"\r\n [attr.data-date]=\"day.key\"\r\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n (click)=\"onDateSelect(day)\"\r\n >\r\n {{ day.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n" }]
|
|
677
1805
|
}], propDecorators: { value: [{
|
|
678
1806
|
type: Input
|
|
679
1807
|
}], variant: [{
|
|
@@ -716,13 +1844,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
716
1844
|
args: ['document:keydown.escape']
|
|
717
1845
|
}] } });
|
|
718
1846
|
|
|
719
|
-
const BASE_CLASSES$
|
|
1847
|
+
const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
720
1848
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
721
1849
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
722
1850
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
723
1851
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
724
1852
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
725
|
-
const VARIANT_CLASSES$
|
|
1853
|
+
const VARIANT_CLASSES$2 = {
|
|
726
1854
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
727
1855
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
728
1856
|
};
|
|
@@ -760,9 +1888,9 @@ class CxsInputComponent {
|
|
|
760
1888
|
}
|
|
761
1889
|
get inputClass() {
|
|
762
1890
|
return [
|
|
763
|
-
BASE_CLASSES$
|
|
1891
|
+
BASE_CLASSES$2,
|
|
764
1892
|
SIZE_CLASSES$1[this.size],
|
|
765
|
-
VARIANT_CLASSES$
|
|
1893
|
+
VARIANT_CLASSES$2[this.variant],
|
|
766
1894
|
this.invalid ? INVALID_CLASSES$2 : ''
|
|
767
1895
|
]
|
|
768
1896
|
.filter(Boolean)
|
|
@@ -787,63 +1915,204 @@ class CxsInputComponent {
|
|
|
787
1915
|
this.onChange(nextValue);
|
|
788
1916
|
this.valueChange.emit(nextValue);
|
|
789
1917
|
}
|
|
790
|
-
onBlur() {
|
|
791
|
-
this.onTouched();
|
|
1918
|
+
onBlur() {
|
|
1919
|
+
this.onTouched();
|
|
1920
|
+
}
|
|
1921
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1922
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsInputComponent, isStandalone: true, selector: "cxs-input", inputs: { value: "value", type: "type", variant: "variant", size: "size", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", id: "id", name: "name", placeholder: "placeholder", autocomplete: "autocomplete", inputmode: "inputmode", spellcheck: "spellcheck", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
|
|
1923
|
+
{
|
|
1924
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1925
|
+
useExisting: forwardRef(() => CxsInputComponent),
|
|
1926
|
+
multi: true
|
|
1927
|
+
}
|
|
1928
|
+
], ngImport: i0, template: "<input\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.type]=\"type\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.inputmode]=\"inputmode\"\r\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n [value]=\"value\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n/>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1929
|
+
}
|
|
1930
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, decorators: [{
|
|
1931
|
+
type: Component,
|
|
1932
|
+
args: [{ selector: 'cxs-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1933
|
+
{
|
|
1934
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1935
|
+
useExisting: forwardRef(() => CxsInputComponent),
|
|
1936
|
+
multi: true
|
|
1937
|
+
}
|
|
1938
|
+
], template: "<input\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.type]=\"type\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.inputmode]=\"inputmode\"\r\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n [value]=\"value\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n/>\r\n" }]
|
|
1939
|
+
}], propDecorators: { value: [{
|
|
1940
|
+
type: Input
|
|
1941
|
+
}], type: [{
|
|
1942
|
+
type: Input
|
|
1943
|
+
}], variant: [{
|
|
1944
|
+
type: Input
|
|
1945
|
+
}], size: [{
|
|
1946
|
+
type: Input
|
|
1947
|
+
}], disabled: [{
|
|
1948
|
+
type: Input
|
|
1949
|
+
}], readonly: [{
|
|
1950
|
+
type: Input
|
|
1951
|
+
}], required: [{
|
|
1952
|
+
type: Input
|
|
1953
|
+
}], invalid: [{
|
|
1954
|
+
type: Input
|
|
1955
|
+
}], autofocus: [{
|
|
1956
|
+
type: Input
|
|
1957
|
+
}], id: [{
|
|
1958
|
+
type: Input
|
|
1959
|
+
}], name: [{
|
|
1960
|
+
type: Input
|
|
1961
|
+
}], placeholder: [{
|
|
1962
|
+
type: Input
|
|
1963
|
+
}], autocomplete: [{
|
|
1964
|
+
type: Input
|
|
1965
|
+
}], inputmode: [{
|
|
1966
|
+
type: Input
|
|
1967
|
+
}], spellcheck: [{
|
|
1968
|
+
type: Input
|
|
1969
|
+
}], ariaLabel: [{
|
|
1970
|
+
type: Input
|
|
1971
|
+
}], ariaDescribedby: [{
|
|
1972
|
+
type: Input
|
|
1973
|
+
}], valueChange: [{
|
|
1974
|
+
type: Output
|
|
1975
|
+
}] } });
|
|
1976
|
+
|
|
1977
|
+
const BAR_BASE_CLASSES = 'm-0 flex list-none flex-wrap items-center gap-1 rounded-[var(--cxs-radius-md)] border border-transparent p-1';
|
|
1978
|
+
const BAR_SIZE_CLASSES = {
|
|
1979
|
+
sm: 'text-xs',
|
|
1980
|
+
md: 'text-sm',
|
|
1981
|
+
lg: 'text-base'
|
|
1982
|
+
};
|
|
1983
|
+
const BAR_VARIANT_CLASSES = {
|
|
1984
|
+
default: 'bg-transparent',
|
|
1985
|
+
surface: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)] shadow-[var(--cxs-shadow-sm)]'
|
|
1986
|
+
};
|
|
1987
|
+
const ITEM_BASE_CLASSES = 'inline-flex items-center gap-2 rounded-[var(--cxs-radius-md)] px-3 py-1.5 font-medium ' +
|
|
1988
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1989
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1990
|
+
const ITEM_SIZE_CLASSES = {
|
|
1991
|
+
sm: 'px-2.5 py-1 text-xs',
|
|
1992
|
+
md: 'px-3 py-1.5 text-sm',
|
|
1993
|
+
lg: 'px-4 py-2 text-base'
|
|
1994
|
+
};
|
|
1995
|
+
const ITEM_ACTIVE_CLASSES = 'bg-[var(--cxs-color-primary-ghost)] text-[var(--cxs-color-primary)]';
|
|
1996
|
+
const ITEM_INACTIVE_CLASSES = 'text-[var(--cxs-color-on-surface)] hover:bg-[var(--cxs-color-surface-hover)]';
|
|
1997
|
+
const ITEM_DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] opacity-60 pointer-events-none';
|
|
1998
|
+
class CxsMenubarComponent {
|
|
1999
|
+
hostClass;
|
|
2000
|
+
items = [];
|
|
2001
|
+
ariaLabel = 'Menubar';
|
|
2002
|
+
size = 'md';
|
|
2003
|
+
variant = 'default';
|
|
2004
|
+
disabled = false;
|
|
2005
|
+
itemSelected = new EventEmitter();
|
|
2006
|
+
menuItems;
|
|
2007
|
+
constructor(hostClass) {
|
|
2008
|
+
this.hostClass = hostClass;
|
|
2009
|
+
}
|
|
2010
|
+
get menubarClass() {
|
|
2011
|
+
return [
|
|
2012
|
+
BAR_BASE_CLASSES,
|
|
2013
|
+
BAR_SIZE_CLASSES[this.size],
|
|
2014
|
+
BAR_VARIANT_CLASSES[this.variant],
|
|
2015
|
+
this.hostClass
|
|
2016
|
+
]
|
|
2017
|
+
.filter(Boolean)
|
|
2018
|
+
.join(' ');
|
|
2019
|
+
}
|
|
2020
|
+
isItemDisabled(item) {
|
|
2021
|
+
return this.disabled || !!item.disabled;
|
|
2022
|
+
}
|
|
2023
|
+
getItemClass(item) {
|
|
2024
|
+
return [
|
|
2025
|
+
ITEM_BASE_CLASSES,
|
|
2026
|
+
ITEM_SIZE_CLASSES[this.size],
|
|
2027
|
+
item.active ? ITEM_ACTIVE_CLASSES : ITEM_INACTIVE_CLASSES,
|
|
2028
|
+
this.isItemDisabled(item) ? ITEM_DISABLED_CLASSES : ''
|
|
2029
|
+
]
|
|
2030
|
+
.filter(Boolean)
|
|
2031
|
+
.join(' ');
|
|
2032
|
+
}
|
|
2033
|
+
getItemHref(item) {
|
|
2034
|
+
if (item.href && !this.isItemDisabled(item)) {
|
|
2035
|
+
return item.href;
|
|
2036
|
+
}
|
|
2037
|
+
return null;
|
|
2038
|
+
}
|
|
2039
|
+
getItemRel(item) {
|
|
2040
|
+
if (item.target === '_blank') {
|
|
2041
|
+
return item.rel ?? 'noopener noreferrer';
|
|
2042
|
+
}
|
|
2043
|
+
return item.rel ?? null;
|
|
2044
|
+
}
|
|
2045
|
+
onItemClick(item, event) {
|
|
2046
|
+
if (this.isItemDisabled(item)) {
|
|
2047
|
+
event.preventDefault();
|
|
2048
|
+
event.stopPropagation();
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
this.itemSelected.emit(item);
|
|
2052
|
+
}
|
|
2053
|
+
onKeydown(event) {
|
|
2054
|
+
if (this.disabled) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
if (typeof document === 'undefined') {
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
const keys = ['ArrowRight', 'ArrowLeft', 'Home', 'End'];
|
|
2061
|
+
if (!keys.includes(event.key)) {
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2064
|
+
const items = this.getFocusableItems();
|
|
2065
|
+
if (!items.length) {
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
const currentIndex = items.findIndex((item) => item === document.activeElement);
|
|
2069
|
+
let nextIndex = 0;
|
|
2070
|
+
switch (event.key) {
|
|
2071
|
+
case 'Home':
|
|
2072
|
+
nextIndex = 0;
|
|
2073
|
+
break;
|
|
2074
|
+
case 'End':
|
|
2075
|
+
nextIndex = items.length - 1;
|
|
2076
|
+
break;
|
|
2077
|
+
case 'ArrowRight':
|
|
2078
|
+
nextIndex = currentIndex >= 0 ? (currentIndex + 1) % items.length : 0;
|
|
2079
|
+
break;
|
|
2080
|
+
case 'ArrowLeft':
|
|
2081
|
+
nextIndex = currentIndex >= 0 ? (currentIndex - 1 + items.length) % items.length : items.length - 1;
|
|
2082
|
+
break;
|
|
2083
|
+
}
|
|
2084
|
+
items[nextIndex]?.focus();
|
|
2085
|
+
event.preventDefault();
|
|
2086
|
+
}
|
|
2087
|
+
getFocusableItems() {
|
|
2088
|
+
return (this.menuItems?.toArray() ?? [])
|
|
2089
|
+
.map((item) => item.nativeElement)
|
|
2090
|
+
.filter((item) => !item.hasAttribute('data-disabled'));
|
|
792
2091
|
}
|
|
793
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
794
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
795
|
-
{
|
|
796
|
-
provide: NG_VALUE_ACCESSOR,
|
|
797
|
-
useExisting: forwardRef(() => CxsInputComponent),
|
|
798
|
-
multi: true
|
|
799
|
-
}
|
|
800
|
-
], ngImport: i0, template: "<input\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n/>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2092
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMenubarComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
2093
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsMenubarComponent, isStandalone: true, selector: "cxs-menubar", inputs: { items: "items", ariaLabel: "ariaLabel", size: "size", variant: "variant", disabled: "disabled" }, outputs: { itemSelected: "itemSelected" }, viewQueries: [{ propertyName: "menuItems", predicate: ["menuItem"], descendants: true, read: ElementRef }], ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ul [class]=\"menubarClass\" role=\"menubar\" (keydown)=\"onKeydown($event)\">\n @for (item of items; track item) {\n <li>\n @if (item.href) {\n <a\n #menuItem\n role=\"menuitem\"\n [class]=\"getItemClass(item)\"\n [attr.href]=\"getItemHref(item)\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n [attr.aria-disabled]=\"isItemDisabled(item) ? 'true' : null\"\n [attr.tabindex]=\"isItemDisabled(item) ? -1 : null\"\n [attr.data-disabled]=\"isItemDisabled(item) ? '' : null\"\n (click)=\"onItemClick(item, $event)\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n #menuItem\n type=\"button\"\n role=\"menuitem\"\n [class]=\"getItemClass(item)\"\n [disabled]=\"isItemDisabled(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n [attr.data-disabled]=\"isItemDisabled(item) ? '' : null\"\n (click)=\"onItemClick(item, $event)\"\n >\n {{ item.label }}\n </button>\n }\n </li>\n }\n </ul>\n</nav>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
801
2094
|
}
|
|
802
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
2095
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMenubarComponent, decorators: [{
|
|
803
2096
|
type: Component,
|
|
804
|
-
args: [{ selector: 'cxs-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
810
|
-
], template: "<input\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n/>\r\n" }]
|
|
811
|
-
}], propDecorators: { value: [{
|
|
812
|
-
type: Input
|
|
813
|
-
}], type: [{
|
|
2097
|
+
args: [{ selector: 'cxs-menubar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ul [class]=\"menubarClass\" role=\"menubar\" (keydown)=\"onKeydown($event)\">\n @for (item of items; track item) {\n <li>\n @if (item.href) {\n <a\n #menuItem\n role=\"menuitem\"\n [class]=\"getItemClass(item)\"\n [attr.href]=\"getItemHref(item)\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n [attr.aria-disabled]=\"isItemDisabled(item) ? 'true' : null\"\n [attr.tabindex]=\"isItemDisabled(item) ? -1 : null\"\n [attr.data-disabled]=\"isItemDisabled(item) ? '' : null\"\n (click)=\"onItemClick(item, $event)\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n #menuItem\n type=\"button\"\n role=\"menuitem\"\n [class]=\"getItemClass(item)\"\n [disabled]=\"isItemDisabled(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n [attr.aria-current]=\"item.active ? 'page' : null\"\n [attr.data-disabled]=\"isItemDisabled(item) ? '' : null\"\n (click)=\"onItemClick(item, $event)\"\n >\n {{ item.label }}\n </button>\n }\n </li>\n }\n </ul>\n</nav>\n" }]
|
|
2098
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2099
|
+
type: Attribute,
|
|
2100
|
+
args: ['class']
|
|
2101
|
+
}] }], propDecorators: { items: [{
|
|
814
2102
|
type: Input
|
|
815
|
-
}],
|
|
2103
|
+
}], ariaLabel: [{
|
|
816
2104
|
type: Input
|
|
817
2105
|
}], size: [{
|
|
818
2106
|
type: Input
|
|
819
|
-
}],
|
|
820
|
-
type: Input
|
|
821
|
-
}], readonly: [{
|
|
822
|
-
type: Input
|
|
823
|
-
}], required: [{
|
|
824
|
-
type: Input
|
|
825
|
-
}], invalid: [{
|
|
826
|
-
type: Input
|
|
827
|
-
}], autofocus: [{
|
|
828
|
-
type: Input
|
|
829
|
-
}], id: [{
|
|
830
|
-
type: Input
|
|
831
|
-
}], name: [{
|
|
832
|
-
type: Input
|
|
833
|
-
}], placeholder: [{
|
|
834
|
-
type: Input
|
|
835
|
-
}], autocomplete: [{
|
|
836
|
-
type: Input
|
|
837
|
-
}], inputmode: [{
|
|
838
|
-
type: Input
|
|
839
|
-
}], spellcheck: [{
|
|
840
|
-
type: Input
|
|
841
|
-
}], ariaLabel: [{
|
|
2107
|
+
}], variant: [{
|
|
842
2108
|
type: Input
|
|
843
|
-
}],
|
|
2109
|
+
}], disabled: [{
|
|
844
2110
|
type: Input
|
|
845
|
-
}],
|
|
2111
|
+
}], itemSelected: [{
|
|
846
2112
|
type: Output
|
|
2113
|
+
}], menuItems: [{
|
|
2114
|
+
type: ViewChildren,
|
|
2115
|
+
args: ['menuItem', { read: ElementRef }]
|
|
847
2116
|
}] } });
|
|
848
2117
|
|
|
849
2118
|
const WRAPPER_BASE = 'inline-flex items-center gap-2 select-none';
|
|
@@ -958,7 +2227,7 @@ class CxsRadioComponent {
|
|
|
958
2227
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
959
2228
|
multi: true
|
|
960
2229
|
}
|
|
961
|
-
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"radio\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.value]=\"value\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n</label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2230
|
+
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"radio\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.value]=\"value\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"isChecked\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onRadioChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n</label>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
962
2231
|
}
|
|
963
2232
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsRadioComponent, decorators: [{
|
|
964
2233
|
type: Component,
|
|
@@ -968,7 +2237,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
968
2237
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
969
2238
|
multi: true
|
|
970
2239
|
}
|
|
971
|
-
], template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"radio\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.value]=\"value\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n</label>\n" }]
|
|
2240
|
+
], template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"radio\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.value]=\"value\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"isChecked\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onRadioChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n</label>\r\n" }]
|
|
972
2241
|
}], propDecorators: { value: [{
|
|
973
2242
|
type: Input
|
|
974
2243
|
}], name: [{
|
|
@@ -995,13 +2264,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
995
2264
|
type: Output
|
|
996
2265
|
}] } });
|
|
997
2266
|
|
|
998
|
-
const BASE_CLASSES = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
2267
|
+
const BASE_CLASSES$1 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
999
2268
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
1000
2269
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
1001
2270
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1002
2271
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
1003
2272
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
1004
|
-
const VARIANT_CLASSES = {
|
|
2273
|
+
const VARIANT_CLASSES$1 = {
|
|
1005
2274
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
1006
2275
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
1007
2276
|
};
|
|
@@ -1034,9 +2303,9 @@ class CxsSelectComponent {
|
|
|
1034
2303
|
}
|
|
1035
2304
|
get selectClass() {
|
|
1036
2305
|
return [
|
|
1037
|
-
BASE_CLASSES,
|
|
2306
|
+
BASE_CLASSES$1,
|
|
1038
2307
|
SIZE_CLASSES[this.size],
|
|
1039
|
-
VARIANT_CLASSES[this.variant],
|
|
2308
|
+
VARIANT_CLASSES$1[this.variant],
|
|
1040
2309
|
this.invalid ? INVALID_CLASSES : ''
|
|
1041
2310
|
]
|
|
1042
2311
|
.filter(Boolean)
|
|
@@ -1077,7 +2346,7 @@ class CxsSelectComponent {
|
|
|
1077
2346
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
1078
2347
|
multi: true
|
|
1079
2348
|
}
|
|
1080
|
-
], ngImport: i0, template: "<div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n</div>\r\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2349
|
+
], ngImport: i0, template: "<div class=\"relative\">\r\n <select\r\n [class]=\"selectClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n [value]=\"selectValue\"\r\n (change)=\"onSelectChange($event)\"\r\n (blur)=\"onBlur()\"\r\n >\r\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\r\n {{ placeholder }}\r\n </option>\r\n <ng-content></ng-content>\r\n </select>\r\n <span\r\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\r\n aria-hidden=\"true\"\r\n >\r\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\r\n clip-rule=\"evenodd\"\r\n />\r\n </svg>\r\n </span>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1081
2350
|
}
|
|
1082
2351
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, decorators: [{
|
|
1083
2352
|
type: Component,
|
|
@@ -1087,7 +2356,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1087
2356
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
1088
2357
|
multi: true
|
|
1089
2358
|
}
|
|
1090
|
-
], template: "<div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n</div>\r\n" }]
|
|
2359
|
+
], template: "<div class=\"relative\">\r\n <select\r\n [class]=\"selectClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n [value]=\"selectValue\"\r\n (change)=\"onSelectChange($event)\"\r\n (blur)=\"onBlur()\"\r\n >\r\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\r\n {{ placeholder }}\r\n </option>\r\n <ng-content></ng-content>\r\n </select>\r\n <span\r\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\r\n aria-hidden=\"true\"\r\n >\r\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\r\n clip-rule=\"evenodd\"\r\n />\r\n </svg>\r\n </span>\r\n</div>\r\n" }]
|
|
1091
2360
|
}], propDecorators: { value: [{
|
|
1092
2361
|
type: Input
|
|
1093
2362
|
}], variant: [{
|
|
@@ -1116,6 +2385,446 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1116
2385
|
type: Output
|
|
1117
2386
|
}] } });
|
|
1118
2387
|
|
|
2388
|
+
const WRAPPER_BASE_CLASSES = 'w-full overflow-hidden';
|
|
2389
|
+
const WRAPPER_BORDERED_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
|
|
2390
|
+
const TABLE_BASE_CLASSES = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
|
|
2391
|
+
const TABLE_COMPACT_CLASSES = 'text-xs';
|
|
2392
|
+
const HEADER_ROW_CLASSES = 'border-b border-[var(--cxs-color-border)] text-xs uppercase tracking-[0.2em] ' +
|
|
2393
|
+
'text-[var(--cxs-color-on-surface-muted)]';
|
|
2394
|
+
const HEADER_CELL_BASE_CLASSES = 'px-3 py-2 text-left font-semibold';
|
|
2395
|
+
const BODY_ROW_BASE_CLASSES = 'border-b border-[var(--cxs-color-border)] last:border-b-0';
|
|
2396
|
+
const BODY_ROW_STRIPED_CLASSES = 'odd:bg-[var(--cxs-color-surface)] even:bg-[var(--cxs-color-surface-hover)]';
|
|
2397
|
+
const BODY_CELL_BASE_CLASSES = 'px-3 py-2 align-top';
|
|
2398
|
+
const BODY_CELL_COMPACT_CLASSES = 'px-2 py-1.5';
|
|
2399
|
+
const ALIGN_CLASSES = {
|
|
2400
|
+
left: 'text-left',
|
|
2401
|
+
center: 'text-center',
|
|
2402
|
+
right: 'text-right'
|
|
2403
|
+
};
|
|
2404
|
+
const EMPTY_ROW_CLASSES = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
2405
|
+
class CxsTableComponent {
|
|
2406
|
+
hostClass;
|
|
2407
|
+
columns = [];
|
|
2408
|
+
data = [];
|
|
2409
|
+
caption;
|
|
2410
|
+
ariaLabel = 'Table';
|
|
2411
|
+
striped = false;
|
|
2412
|
+
bordered = false;
|
|
2413
|
+
compact = false;
|
|
2414
|
+
emptyMessage = 'No data available';
|
|
2415
|
+
emptyCell = '—';
|
|
2416
|
+
constructor(hostClass) {
|
|
2417
|
+
this.hostClass = hostClass;
|
|
2418
|
+
}
|
|
2419
|
+
get wrapperClass() {
|
|
2420
|
+
return [
|
|
2421
|
+
WRAPPER_BASE_CLASSES,
|
|
2422
|
+
this.bordered ? WRAPPER_BORDERED_CLASSES : '',
|
|
2423
|
+
this.hostClass
|
|
2424
|
+
]
|
|
2425
|
+
.filter(Boolean)
|
|
2426
|
+
.join(' ');
|
|
2427
|
+
}
|
|
2428
|
+
get tableClass() {
|
|
2429
|
+
return [TABLE_BASE_CLASSES, this.compact ? TABLE_COMPACT_CLASSES : '']
|
|
2430
|
+
.filter(Boolean)
|
|
2431
|
+
.join(' ');
|
|
2432
|
+
}
|
|
2433
|
+
get headerRowClass() {
|
|
2434
|
+
return HEADER_ROW_CLASSES;
|
|
2435
|
+
}
|
|
2436
|
+
get bodyRowClass() {
|
|
2437
|
+
return [
|
|
2438
|
+
BODY_ROW_BASE_CLASSES,
|
|
2439
|
+
this.striped ? BODY_ROW_STRIPED_CLASSES : ''
|
|
2440
|
+
]
|
|
2441
|
+
.filter(Boolean)
|
|
2442
|
+
.join(' ');
|
|
2443
|
+
}
|
|
2444
|
+
get emptyRowClass() {
|
|
2445
|
+
return EMPTY_ROW_CLASSES;
|
|
2446
|
+
}
|
|
2447
|
+
get colSpan() {
|
|
2448
|
+
return Math.max(this.columns.length, 1);
|
|
2449
|
+
}
|
|
2450
|
+
headerCellClass(column) {
|
|
2451
|
+
return [
|
|
2452
|
+
HEADER_CELL_BASE_CLASSES,
|
|
2453
|
+
ALIGN_CLASSES[column.align ?? 'left'],
|
|
2454
|
+
column.headerClass ?? ''
|
|
2455
|
+
]
|
|
2456
|
+
.filter(Boolean)
|
|
2457
|
+
.join(' ');
|
|
2458
|
+
}
|
|
2459
|
+
bodyCellClass(column) {
|
|
2460
|
+
return [
|
|
2461
|
+
BODY_CELL_BASE_CLASSES,
|
|
2462
|
+
this.compact ? BODY_CELL_COMPACT_CLASSES : '',
|
|
2463
|
+
ALIGN_CLASSES[column.align ?? 'left'],
|
|
2464
|
+
column.cellClass ?? ''
|
|
2465
|
+
]
|
|
2466
|
+
.filter(Boolean)
|
|
2467
|
+
.join(' ');
|
|
2468
|
+
}
|
|
2469
|
+
cellValue(row, column) {
|
|
2470
|
+
const value = row[column.key];
|
|
2471
|
+
if (value === null || value === undefined || value === '') {
|
|
2472
|
+
return this.emptyCell;
|
|
2473
|
+
}
|
|
2474
|
+
return String(value);
|
|
2475
|
+
}
|
|
2476
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTableComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
2477
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsTableComponent, isStandalone: true, selector: "cxs-table", inputs: { columns: "columns", data: "data", caption: "caption", ariaLabel: "ariaLabel", striped: "striped", bordered: "bordered", compact: "compact", emptyMessage: "emptyMessage", emptyCell: "emptyCell" }, ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @for (column of columns; track column) {\n <th\n [class]=\"headerCellClass(column)\"\n [style.width]=\"column.width ?? null\"\n scope=\"col\"\n >\n {{ column.label }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (data.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of data; track row; let rowIndex = $index) {\n <tr [class]=\"bodyRowClass\">\n @for (column of columns; track column) {\n <td [class]=\"bodyCellClass(column)\">\n {{ cellValue(row, column) }}\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2478
|
+
}
|
|
2479
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTableComponent, decorators: [{
|
|
2480
|
+
type: Component,
|
|
2481
|
+
args: [{ selector: 'cxs-table', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @for (column of columns; track column) {\n <th\n [class]=\"headerCellClass(column)\"\n [style.width]=\"column.width ?? null\"\n scope=\"col\"\n >\n {{ column.label }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (data.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of data; track row; let rowIndex = $index) {\n <tr [class]=\"bodyRowClass\">\n @for (column of columns; track column) {\n <td [class]=\"bodyCellClass(column)\">\n {{ cellValue(row, column) }}\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n" }]
|
|
2482
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2483
|
+
type: Attribute,
|
|
2484
|
+
args: ['class']
|
|
2485
|
+
}] }], propDecorators: { columns: [{
|
|
2486
|
+
type: Input
|
|
2487
|
+
}], data: [{
|
|
2488
|
+
type: Input
|
|
2489
|
+
}], caption: [{
|
|
2490
|
+
type: Input
|
|
2491
|
+
}], ariaLabel: [{
|
|
2492
|
+
type: Input
|
|
2493
|
+
}], striped: [{
|
|
2494
|
+
type: Input
|
|
2495
|
+
}], bordered: [{
|
|
2496
|
+
type: Input
|
|
2497
|
+
}], compact: [{
|
|
2498
|
+
type: Input
|
|
2499
|
+
}], emptyMessage: [{
|
|
2500
|
+
type: Input
|
|
2501
|
+
}], emptyCell: [{
|
|
2502
|
+
type: Input
|
|
2503
|
+
}] } });
|
|
2504
|
+
|
|
2505
|
+
const WRAPPER_CLASSES$1 = 'inline-flex items-center gap-2';
|
|
2506
|
+
const LABEL_BASE_CLASSES = 'text-sm text-[var(--cxs-color-on-surface)] select-none';
|
|
2507
|
+
const LABEL_DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
2508
|
+
const TRACK_BASE_CLASSES = 'relative inline-flex items-center rounded-full border transition-colors ' +
|
|
2509
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
2510
|
+
'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-60';
|
|
2511
|
+
const TRACK_SIZE_CLASSES = {
|
|
2512
|
+
sm: 'h-5 w-9 p-0.5',
|
|
2513
|
+
md: 'h-6 w-11 p-0.5',
|
|
2514
|
+
lg: 'h-8 w-14 p-0.5'
|
|
2515
|
+
};
|
|
2516
|
+
const TRACK_STATE_CLASSES = {
|
|
2517
|
+
on: 'bg-[var(--cxs-color-primary)] border-[var(--cxs-color-primary)]',
|
|
2518
|
+
off: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)]'
|
|
2519
|
+
};
|
|
2520
|
+
const THUMB_BASE_CLASSES = 'absolute left-0.5 top-0.5 rounded-full transition-transform duration-200 ease-out';
|
|
2521
|
+
const THUMB_SIZE_CLASSES = {
|
|
2522
|
+
sm: 'h-4 w-4',
|
|
2523
|
+
md: 'h-5 w-5',
|
|
2524
|
+
lg: 'h-7 w-7'
|
|
2525
|
+
};
|
|
2526
|
+
const THUMB_STATE_CLASSES = {
|
|
2527
|
+
on: {
|
|
2528
|
+
sm: 'translate-x-[18px] bg-[var(--cxs-color-on-primary)]',
|
|
2529
|
+
md: 'translate-x-[22px] bg-[var(--cxs-color-on-primary)]',
|
|
2530
|
+
lg: 'translate-x-[26px] bg-[var(--cxs-color-on-primary)]'
|
|
2531
|
+
},
|
|
2532
|
+
off: 'translate-x-0 bg-[var(--cxs-color-surface)]'
|
|
2533
|
+
};
|
|
2534
|
+
class CxsToggleComponent {
|
|
2535
|
+
static nextId = 0;
|
|
2536
|
+
checked = false;
|
|
2537
|
+
disabled = false;
|
|
2538
|
+
size = 'md';
|
|
2539
|
+
label;
|
|
2540
|
+
ariaLabel = 'Toggle';
|
|
2541
|
+
checkedChange = new EventEmitter();
|
|
2542
|
+
labelId = `cxs-toggle-label-${CxsToggleComponent.nextId++}`;
|
|
2543
|
+
get wrapperClass() {
|
|
2544
|
+
return WRAPPER_CLASSES$1;
|
|
2545
|
+
}
|
|
2546
|
+
get labelClass() {
|
|
2547
|
+
return [LABEL_BASE_CLASSES, this.disabled ? LABEL_DISABLED_CLASSES : '']
|
|
2548
|
+
.filter(Boolean)
|
|
2549
|
+
.join(' ');
|
|
2550
|
+
}
|
|
2551
|
+
get trackClass() {
|
|
2552
|
+
return [
|
|
2553
|
+
TRACK_BASE_CLASSES,
|
|
2554
|
+
TRACK_SIZE_CLASSES[this.size],
|
|
2555
|
+
this.checked ? TRACK_STATE_CLASSES.on : TRACK_STATE_CLASSES.off
|
|
2556
|
+
].join(' ');
|
|
2557
|
+
}
|
|
2558
|
+
get thumbClass() {
|
|
2559
|
+
const thumbState = this.checked
|
|
2560
|
+
? THUMB_STATE_CLASSES.on[this.size]
|
|
2561
|
+
: THUMB_STATE_CLASSES.off;
|
|
2562
|
+
return [THUMB_BASE_CLASSES, THUMB_SIZE_CLASSES[this.size], thumbState].join(' ');
|
|
2563
|
+
}
|
|
2564
|
+
get ariaLabelValue() {
|
|
2565
|
+
if (this.label) {
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
return this.ariaLabel;
|
|
2569
|
+
}
|
|
2570
|
+
toggle() {
|
|
2571
|
+
if (this.disabled) {
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
this.checkedChange.emit(!this.checked);
|
|
2575
|
+
}
|
|
2576
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2577
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsToggleComponent, isStandalone: true, selector: "cxs-toggle", inputs: { checked: "checked", disabled: "disabled", size: "size", label: "label", ariaLabel: "ariaLabel" }, outputs: { checkedChange: "checkedChange" }, ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <button\n type=\"button\"\n [class]=\"trackClass\"\n role=\"switch\"\n [disabled]=\"disabled\"\n [attr.aria-checked]=\"checked ? 'true' : 'false'\"\n [attr.aria-labelledby]=\"label ? labelId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n (click)=\"toggle()\"\n >\n <span [class]=\"thumbClass\" aria-hidden=\"true\"></span>\n </button>\n @if (label) {\n <span [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</span>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2578
|
+
}
|
|
2579
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToggleComponent, decorators: [{
|
|
2580
|
+
type: Component,
|
|
2581
|
+
args: [{ selector: 'cxs-toggle', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n <button\n type=\"button\"\n [class]=\"trackClass\"\n role=\"switch\"\n [disabled]=\"disabled\"\n [attr.aria-checked]=\"checked ? 'true' : 'false'\"\n [attr.aria-labelledby]=\"label ? labelId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n (click)=\"toggle()\"\n >\n <span [class]=\"thumbClass\" aria-hidden=\"true\"></span>\n </button>\n @if (label) {\n <span [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</span>\n }\n</div>\n" }]
|
|
2582
|
+
}], propDecorators: { checked: [{
|
|
2583
|
+
type: Input
|
|
2584
|
+
}], disabled: [{
|
|
2585
|
+
type: Input
|
|
2586
|
+
}], size: [{
|
|
2587
|
+
type: Input
|
|
2588
|
+
}], label: [{
|
|
2589
|
+
type: Input
|
|
2590
|
+
}], ariaLabel: [{
|
|
2591
|
+
type: Input
|
|
2592
|
+
}], checkedChange: [{
|
|
2593
|
+
type: Output
|
|
2594
|
+
}] } });
|
|
2595
|
+
|
|
2596
|
+
const HOST_BASE_CLASSES = 'pointer-events-none';
|
|
2597
|
+
const POSITION_CLASSES = {
|
|
2598
|
+
'bottom-right': 'fixed bottom-6 right-6 items-end',
|
|
2599
|
+
bottom: 'fixed bottom-6 left-1/2 -translate-x-1/2 items-end',
|
|
2600
|
+
'bottom-left': 'fixed bottom-6 left-6 items-start',
|
|
2601
|
+
'top-right': 'fixed top-6 right-6 items-end',
|
|
2602
|
+
top: 'fixed top-6 left-1/2 -translate-x-1/2 items-start',
|
|
2603
|
+
'top-left': 'fixed top-6 left-6 items-start',
|
|
2604
|
+
right: 'fixed right-6 top-1/2 -translate-y-1/2 items-end',
|
|
2605
|
+
left: 'fixed left-6 top-1/2 -translate-y-1/2 items-start',
|
|
2606
|
+
center: 'fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 items-center'
|
|
2607
|
+
};
|
|
2608
|
+
const BASE_CLASSES = 'pointer-events-auto flex w-full items-start gap-3 rounded-[var(--cxs-radius-md)] ' +
|
|
2609
|
+
'border px-4 py-3 shadow-[var(--cxs-shadow-sm)]';
|
|
2610
|
+
const WIDTH_CLASSES = {
|
|
2611
|
+
sm: 'max-w-sm',
|
|
2612
|
+
md: 'max-w-md',
|
|
2613
|
+
lg: 'max-w-lg',
|
|
2614
|
+
xl: 'max-w-xl',
|
|
2615
|
+
none: 'max-w-none'
|
|
2616
|
+
};
|
|
2617
|
+
const VARIANT_CLASSES = {
|
|
2618
|
+
info: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
|
|
2619
|
+
'text-[var(--cxs-color-on-surface)]',
|
|
2620
|
+
neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
2621
|
+
'text-[var(--cxs-color-on-surface)]',
|
|
2622
|
+
danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
|
|
2623
|
+
'text-[var(--cxs-color-on-surface)]'
|
|
2624
|
+
};
|
|
2625
|
+
const TITLE_CLASSES = 'text-sm font-semibold';
|
|
2626
|
+
const MESSAGE_CLASSES = 'mt-1 text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
2627
|
+
const ACTIONS_CLASSES = 'mt-3 flex flex-wrap items-center gap-2 empty:hidden';
|
|
2628
|
+
const CLOSE_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
2629
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
2630
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
2631
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
2632
|
+
class CxsToastComponent {
|
|
2633
|
+
hostClass;
|
|
2634
|
+
open = false;
|
|
2635
|
+
title;
|
|
2636
|
+
message;
|
|
2637
|
+
ariaLabel = 'Notification';
|
|
2638
|
+
variant = 'info';
|
|
2639
|
+
dismissible = true;
|
|
2640
|
+
duration = 0;
|
|
2641
|
+
position = 'bottom-right';
|
|
2642
|
+
maxWidth = 'sm';
|
|
2643
|
+
openChange = new EventEmitter();
|
|
2644
|
+
dismissed = new EventEmitter();
|
|
2645
|
+
timeoutId = null;
|
|
2646
|
+
constructor(hostClass) {
|
|
2647
|
+
this.hostClass = hostClass;
|
|
2648
|
+
}
|
|
2649
|
+
ngOnChanges(changes) {
|
|
2650
|
+
if (changes['open'] || changes['duration']) {
|
|
2651
|
+
this.resetTimer();
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
ngOnDestroy() {
|
|
2655
|
+
this.clearTimer();
|
|
2656
|
+
}
|
|
2657
|
+
get hostClassName() {
|
|
2658
|
+
return [HOST_BASE_CLASSES, POSITION_CLASSES[this.position]].join(' ');
|
|
2659
|
+
}
|
|
2660
|
+
get toastClass() {
|
|
2661
|
+
return [
|
|
2662
|
+
BASE_CLASSES,
|
|
2663
|
+
WIDTH_CLASSES[this.maxWidth],
|
|
2664
|
+
VARIANT_CLASSES[this.variant],
|
|
2665
|
+
this.hostClass
|
|
2666
|
+
]
|
|
2667
|
+
.filter(Boolean)
|
|
2668
|
+
.join(' ');
|
|
2669
|
+
}
|
|
2670
|
+
get titleClass() {
|
|
2671
|
+
return TITLE_CLASSES;
|
|
2672
|
+
}
|
|
2673
|
+
get messageClass() {
|
|
2674
|
+
return MESSAGE_CLASSES;
|
|
2675
|
+
}
|
|
2676
|
+
get actionsClass() {
|
|
2677
|
+
return ACTIONS_CLASSES;
|
|
2678
|
+
}
|
|
2679
|
+
get closeButtonClass() {
|
|
2680
|
+
return CLOSE_BUTTON_CLASSES;
|
|
2681
|
+
}
|
|
2682
|
+
get role() {
|
|
2683
|
+
return this.variant === 'danger' ? 'alert' : 'status';
|
|
2684
|
+
}
|
|
2685
|
+
get ariaLive() {
|
|
2686
|
+
return this.variant === 'danger' ? 'assertive' : 'polite';
|
|
2687
|
+
}
|
|
2688
|
+
get ariaLabelValue() {
|
|
2689
|
+
if (this.title) {
|
|
2690
|
+
return null;
|
|
2691
|
+
}
|
|
2692
|
+
return this.ariaLabel;
|
|
2693
|
+
}
|
|
2694
|
+
requestClose(reason) {
|
|
2695
|
+
this.openChange.emit(false);
|
|
2696
|
+
this.dismissed.emit(reason);
|
|
2697
|
+
}
|
|
2698
|
+
resetTimer() {
|
|
2699
|
+
this.clearTimer();
|
|
2700
|
+
if (this.open && this.duration > 0) {
|
|
2701
|
+
this.timeoutId = setTimeout(() => {
|
|
2702
|
+
this.requestClose('timeout');
|
|
2703
|
+
}, this.duration);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
clearTimer() {
|
|
2707
|
+
if (this.timeoutId) {
|
|
2708
|
+
clearTimeout(this.timeoutId);
|
|
2709
|
+
this.timeoutId = null;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
2713
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsToastComponent, isStandalone: true, selector: "cxs-toast", inputs: { open: "open", title: "title", message: "message", ariaLabel: "ariaLabel", variant: "variant", dismissible: "dismissible", duration: "duration", position: "position", maxWidth: "maxWidth" }, outputs: { openChange: "openChange", dismissed: "dismissed" }, usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2714
|
+
}
|
|
2715
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, decorators: [{
|
|
2716
|
+
type: Component,
|
|
2717
|
+
args: [{ selector: 'cxs-toast', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n </div>\n}\n" }]
|
|
2718
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2719
|
+
type: Attribute,
|
|
2720
|
+
args: ['class']
|
|
2721
|
+
}] }], propDecorators: { open: [{
|
|
2722
|
+
type: Input
|
|
2723
|
+
}], title: [{
|
|
2724
|
+
type: Input
|
|
2725
|
+
}], message: [{
|
|
2726
|
+
type: Input
|
|
2727
|
+
}], ariaLabel: [{
|
|
2728
|
+
type: Input
|
|
2729
|
+
}], variant: [{
|
|
2730
|
+
type: Input
|
|
2731
|
+
}], dismissible: [{
|
|
2732
|
+
type: Input
|
|
2733
|
+
}], duration: [{
|
|
2734
|
+
type: Input
|
|
2735
|
+
}], position: [{
|
|
2736
|
+
type: Input
|
|
2737
|
+
}], maxWidth: [{
|
|
2738
|
+
type: Input
|
|
2739
|
+
}], openChange: [{
|
|
2740
|
+
type: Output
|
|
2741
|
+
}], dismissed: [{
|
|
2742
|
+
type: Output
|
|
2743
|
+
}] } });
|
|
2744
|
+
|
|
2745
|
+
const WRAPPER_CLASSES = 'relative inline-flex';
|
|
2746
|
+
const TOOLTIP_BASE_CLASSES = 'pointer-events-none absolute z-50 max-w-xs rounded-[var(--cxs-radius-md)] px-2 py-1 text-xs ' +
|
|
2747
|
+
'text-[var(--cxs-color-on-primary)] bg-[var(--cxs-color-on-surface)] shadow-[var(--cxs-shadow-sm)]';
|
|
2748
|
+
const TOOLTIP_POSITION_CLASSES = {
|
|
2749
|
+
top: 'bottom-full left-1/2 mb-2 -translate-x-1/2',
|
|
2750
|
+
right: 'left-full top-1/2 ml-2 -translate-y-1/2',
|
|
2751
|
+
bottom: 'top-full left-1/2 mt-2 -translate-x-1/2',
|
|
2752
|
+
left: 'right-full top-1/2 mr-2 -translate-y-1/2'
|
|
2753
|
+
};
|
|
2754
|
+
class CxsTooltipComponent {
|
|
2755
|
+
static nextId = 0;
|
|
2756
|
+
text = '';
|
|
2757
|
+
position = 'top';
|
|
2758
|
+
disabled = false;
|
|
2759
|
+
open = false;
|
|
2760
|
+
tooltipId = `cxs-tooltip-${CxsTooltipComponent.nextId++}`;
|
|
2761
|
+
get wrapperClass() {
|
|
2762
|
+
return WRAPPER_CLASSES;
|
|
2763
|
+
}
|
|
2764
|
+
get tooltipClass() {
|
|
2765
|
+
return [TOOLTIP_BASE_CLASSES, TOOLTIP_POSITION_CLASSES[this.position]].join(' ');
|
|
2766
|
+
}
|
|
2767
|
+
get describedBy() {
|
|
2768
|
+
if (!this.text || this.disabled) {
|
|
2769
|
+
return null;
|
|
2770
|
+
}
|
|
2771
|
+
return this.tooltipId;
|
|
2772
|
+
}
|
|
2773
|
+
show() {
|
|
2774
|
+
if (this.disabled || !this.text) {
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
this.open = true;
|
|
2778
|
+
}
|
|
2779
|
+
hide() {
|
|
2780
|
+
this.open = false;
|
|
2781
|
+
}
|
|
2782
|
+
onMouseEnter() {
|
|
2783
|
+
this.show();
|
|
2784
|
+
}
|
|
2785
|
+
onMouseLeave() {
|
|
2786
|
+
this.hide();
|
|
2787
|
+
}
|
|
2788
|
+
onFocusIn() {
|
|
2789
|
+
this.show();
|
|
2790
|
+
}
|
|
2791
|
+
onFocusOut() {
|
|
2792
|
+
this.hide();
|
|
2793
|
+
}
|
|
2794
|
+
onKeydown(event) {
|
|
2795
|
+
if (event.key === 'Escape') {
|
|
2796
|
+
this.hide();
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2800
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsTooltipComponent, isStandalone: true, selector: "cxs-tooltip", inputs: { text: "text", position: "position", disabled: "disabled" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "focusin": "onFocusIn()", "focusout": "onFocusOut()", "keydown": "onKeydown($event)" } }, ngImport: i0, template: "<span [class]=\"wrapperClass\">\n <span [attr.aria-describedby]=\"describedBy\">\n <ng-content></ng-content>\n </span>\n @if (open) {\n <span [id]=\"tooltipId\" role=\"tooltip\" [class]=\"tooltipClass\">\n {{ text }}\n </span>\n }\n</span>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2801
|
+
}
|
|
2802
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTooltipComponent, decorators: [{
|
|
2803
|
+
type: Component,
|
|
2804
|
+
args: [{ selector: 'cxs-tooltip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<span [class]=\"wrapperClass\">\n <span [attr.aria-describedby]=\"describedBy\">\n <ng-content></ng-content>\n </span>\n @if (open) {\n <span [id]=\"tooltipId\" role=\"tooltip\" [class]=\"tooltipClass\">\n {{ text }}\n </span>\n }\n</span>\n" }]
|
|
2805
|
+
}], propDecorators: { text: [{
|
|
2806
|
+
type: Input
|
|
2807
|
+
}], position: [{
|
|
2808
|
+
type: Input
|
|
2809
|
+
}], disabled: [{
|
|
2810
|
+
type: Input
|
|
2811
|
+
}], onMouseEnter: [{
|
|
2812
|
+
type: HostListener,
|
|
2813
|
+
args: ['mouseenter']
|
|
2814
|
+
}], onMouseLeave: [{
|
|
2815
|
+
type: HostListener,
|
|
2816
|
+
args: ['mouseleave']
|
|
2817
|
+
}], onFocusIn: [{
|
|
2818
|
+
type: HostListener,
|
|
2819
|
+
args: ['focusin']
|
|
2820
|
+
}], onFocusOut: [{
|
|
2821
|
+
type: HostListener,
|
|
2822
|
+
args: ['focusout']
|
|
2823
|
+
}], onKeydown: [{
|
|
2824
|
+
type: HostListener,
|
|
2825
|
+
args: ['keydown', ['$event']]
|
|
2826
|
+
}] } });
|
|
2827
|
+
|
|
1119
2828
|
const DEFAULT_DARK_CLASS = 'cxs-theme-dark';
|
|
1120
2829
|
class CxsThemeDirective {
|
|
1121
2830
|
host;
|
|
@@ -1223,5 +2932,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1223
2932
|
* Generated bundle index. Do not edit.
|
|
1224
2933
|
*/
|
|
1225
2934
|
|
|
1226
|
-
export { CerxosUi, CxsAlertComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCheckboxComponent, CxsDatepickerComponent, CxsInputComponent, CxsRadioComponent, CxsSelectComponent, CxsThemeDirective };
|
|
2935
|
+
export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsDataTableCellDirective, CxsDataTableComponent, CxsDatepickerComponent, CxsDialogComponent, CxsInputComponent, CxsMenubarComponent, CxsRadioComponent, CxsSelectComponent, CxsTableComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
|
|
1227
2936
|
//# sourceMappingURL=cerxos-ui.mjs.map
|