cerxos-ui 0.0.2 → 0.0.4
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 +2457 -28
- package/fesm2022/cerxos-ui.mjs.map +1 -1
- package/index.d.ts +627 -5
- package/package.json +3 -2
- package/styles/tailwind.css +3 -2
- package/tokens/theme-dark.css +16 -0
- 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, Input, ChangeDetectionStrategy,
|
|
3
|
-
import { NgIf } from '@angular/common';
|
|
2
|
+
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, ViewChild, HostListener, ElementRef, ViewChildren, Directive } from '@angular/core';
|
|
4
3
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
|
+
import { 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,58 +20,1807 @@ 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
|
+
'text-[var(--cxs-color-on-surface)]';
|
|
25
|
+
const VARIANT_CLASSES$7 = {
|
|
26
|
+
info: 'border-[var(--cxs-color-primary)] border-l-[var(--cxs-color-primary)] ' +
|
|
27
|
+
'bg-[var(--cxs-color-primary-ghost)]',
|
|
28
|
+
neutral: 'border-[var(--cxs-color-border)] border-l-[var(--cxs-color-border)] ' +
|
|
29
|
+
'bg-[var(--cxs-color-surface)]',
|
|
30
|
+
danger: 'border-[var(--cxs-color-danger)] border-l-[var(--cxs-color-danger)] ' +
|
|
31
|
+
'bg-[var(--cxs-color-surface)]'
|
|
32
|
+
};
|
|
33
|
+
const TITLE_BASE = 'font-semibold';
|
|
34
|
+
const TITLE_VARIANT = {
|
|
35
|
+
info: 'text-[var(--cxs-color-primary)]',
|
|
36
|
+
neutral: 'text-[var(--cxs-color-on-surface)]',
|
|
37
|
+
danger: 'text-[var(--cxs-color-danger)]'
|
|
38
|
+
};
|
|
39
|
+
const CLOSE_BUTTON_CLASSES$2 = 'ml-auto inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
40
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
41
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
42
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
43
|
+
class CxsAlertComponent {
|
|
44
|
+
variant = 'info';
|
|
45
|
+
title;
|
|
46
|
+
dismissible = false;
|
|
47
|
+
closed = new EventEmitter();
|
|
48
|
+
isVisible = true;
|
|
49
|
+
get alertClass() {
|
|
50
|
+
return [BASE_CLASSES$a, VARIANT_CLASSES$7[this.variant]].join(' ');
|
|
51
|
+
}
|
|
52
|
+
get titleClass() {
|
|
53
|
+
return [TITLE_BASE, TITLE_VARIANT[this.variant]].join(' ');
|
|
54
|
+
}
|
|
55
|
+
get closeButtonClass() {
|
|
56
|
+
return CLOSE_BUTTON_CLASSES$2;
|
|
57
|
+
}
|
|
58
|
+
onClose() {
|
|
59
|
+
this.isVisible = false;
|
|
60
|
+
this.closed.emit();
|
|
61
|
+
}
|
|
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) {\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
|
+
}
|
|
65
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAlertComponent, decorators: [{
|
|
66
|
+
type: Component,
|
|
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
|
+
}], propDecorators: { variant: [{
|
|
69
|
+
type: Input
|
|
70
|
+
}], title: [{
|
|
71
|
+
type: Input
|
|
72
|
+
}], dismissible: [{
|
|
73
|
+
type: Input
|
|
74
|
+
}], closed: [{
|
|
75
|
+
type: Output
|
|
76
|
+
}] } });
|
|
77
|
+
|
|
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 ' +
|
|
176
|
+
'leading-none';
|
|
177
|
+
const VARIANT_CLASSES$6 = {
|
|
178
|
+
primary: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
|
|
179
|
+
'text-[var(--cxs-color-primary)]',
|
|
180
|
+
neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
181
|
+
'text-[var(--cxs-color-on-surface)]',
|
|
182
|
+
danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
|
|
183
|
+
'text-[var(--cxs-color-danger)]'
|
|
184
|
+
};
|
|
185
|
+
const SIZE_CLASSES$7 = {
|
|
186
|
+
sm: 'text-[11px]',
|
|
187
|
+
md: 'text-xs'
|
|
188
|
+
};
|
|
189
|
+
class CxsBadgeComponent {
|
|
190
|
+
variant = 'primary';
|
|
191
|
+
size = 'md';
|
|
192
|
+
get badgeClass() {
|
|
193
|
+
return [BASE_CLASSES$8, VARIANT_CLASSES$6[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
|
|
194
|
+
}
|
|
195
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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 });
|
|
197
|
+
}
|
|
198
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, decorators: [{
|
|
199
|
+
type: Component,
|
|
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" }]
|
|
201
|
+
}], propDecorators: { variant: [{
|
|
202
|
+
type: Input
|
|
203
|
+
}], size: [{
|
|
204
|
+
type: Input
|
|
205
|
+
}] } });
|
|
206
|
+
|
|
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';
|
|
311
|
+
const ITEM_CLASSES = 'flex items-center gap-1';
|
|
312
|
+
const LINK_BASE_CLASSES = 'rounded-[var(--cxs-radius-md)] transition-colors focus-visible:outline focus-visible:outline-2 ' +
|
|
313
|
+
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
314
|
+
const NON_LINK_CLASSES = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
315
|
+
const SEPARATOR_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] select-none';
|
|
316
|
+
const DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] opacity-60';
|
|
317
|
+
const SIZE_CLASSES$5 = {
|
|
318
|
+
sm: 'text-xs',
|
|
319
|
+
md: 'text-sm',
|
|
320
|
+
lg: 'text-base'
|
|
321
|
+
};
|
|
322
|
+
const LINK_VARIANT_CLASSES = {
|
|
323
|
+
default: 'text-[var(--cxs-color-primary)] hover:text-[var(--cxs-color-primary-hover)]',
|
|
324
|
+
muted: 'text-[var(--cxs-color-on-surface-muted)] hover:text-[var(--cxs-color-on-surface)]'
|
|
325
|
+
};
|
|
326
|
+
const CURRENT_VARIANT_CLASSES = {
|
|
327
|
+
default: 'text-[var(--cxs-color-on-surface)]',
|
|
328
|
+
muted: 'text-[var(--cxs-color-on-surface-muted)]'
|
|
329
|
+
};
|
|
330
|
+
class CxsBreadcrumbComponent {
|
|
331
|
+
items = [];
|
|
332
|
+
separator = '/';
|
|
333
|
+
ariaLabel = 'Breadcrumb';
|
|
334
|
+
size = 'md';
|
|
335
|
+
variant = 'default';
|
|
336
|
+
disabled = false;
|
|
337
|
+
get listClass() {
|
|
338
|
+
return [BASE_CLASSES$6, SIZE_CLASSES$5[this.size], this.disabled ? 'opacity-60' : '']
|
|
339
|
+
.filter(Boolean)
|
|
340
|
+
.join(' ');
|
|
341
|
+
}
|
|
342
|
+
get itemClass() {
|
|
343
|
+
return ITEM_CLASSES;
|
|
344
|
+
}
|
|
345
|
+
get separatorClass() {
|
|
346
|
+
return SEPARATOR_CLASSES;
|
|
347
|
+
}
|
|
348
|
+
isLink(item, isLast) {
|
|
349
|
+
return !!item.href && !isLast && !item.disabled && !this.disabled;
|
|
350
|
+
}
|
|
351
|
+
getLinkClass(item) {
|
|
352
|
+
return [
|
|
353
|
+
LINK_BASE_CLASSES,
|
|
354
|
+
LINK_VARIANT_CLASSES[this.variant],
|
|
355
|
+
item.disabled || this.disabled ? DISABLED_CLASSES : ''
|
|
356
|
+
]
|
|
357
|
+
.filter(Boolean)
|
|
358
|
+
.join(' ');
|
|
359
|
+
}
|
|
360
|
+
getLabelClass(item, isLast) {
|
|
361
|
+
if (isLast) {
|
|
362
|
+
return [
|
|
363
|
+
CURRENT_VARIANT_CLASSES[this.variant],
|
|
364
|
+
item.disabled || this.disabled ? DISABLED_CLASSES : ''
|
|
365
|
+
]
|
|
366
|
+
.filter(Boolean)
|
|
367
|
+
.join(' ');
|
|
368
|
+
}
|
|
369
|
+
return [NON_LINK_CLASSES, item.disabled || this.disabled ? DISABLED_CLASSES : '']
|
|
370
|
+
.filter(Boolean)
|
|
371
|
+
.join(' ');
|
|
372
|
+
}
|
|
373
|
+
getItemRel(item) {
|
|
374
|
+
if (item.target === '_blank') {
|
|
375
|
+
return item.rel ?? 'noopener noreferrer';
|
|
376
|
+
}
|
|
377
|
+
return item.rel ?? null;
|
|
378
|
+
}
|
|
379
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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 });
|
|
381
|
+
}
|
|
382
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, decorators: [{
|
|
383
|
+
type: Component,
|
|
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" }]
|
|
385
|
+
}], propDecorators: { items: [{
|
|
386
|
+
type: Input
|
|
387
|
+
}], separator: [{
|
|
388
|
+
type: Input
|
|
389
|
+
}], ariaLabel: [{
|
|
390
|
+
type: Input
|
|
391
|
+
}], size: [{
|
|
392
|
+
type: Input
|
|
393
|
+
}], variant: [{
|
|
394
|
+
type: Input
|
|
395
|
+
}], disabled: [{
|
|
396
|
+
type: Input
|
|
397
|
+
}] } });
|
|
398
|
+
|
|
399
|
+
const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
|
|
24
400
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
25
401
|
'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-50';
|
|
26
|
-
const VARIANT_CLASSES$
|
|
402
|
+
const VARIANT_CLASSES$5 = {
|
|
27
403
|
primary: 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)] ' +
|
|
28
404
|
'hover:bg-[var(--cxs-color-primary-hover)] shadow-[var(--cxs-shadow-sm)]',
|
|
29
405
|
secondary: 'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
30
406
|
'border border-[var(--cxs-color-border)] hover:bg-[var(--cxs-color-surface-hover)]',
|
|
31
407
|
ghost: 'bg-transparent text-[var(--cxs-color-primary)] hover:bg-[var(--cxs-color-primary-ghost)]'
|
|
32
408
|
};
|
|
33
|
-
const SIZE_CLASSES$
|
|
409
|
+
const SIZE_CLASSES$4 = {
|
|
34
410
|
sm: 'h-8 px-3 text-sm rounded-[var(--cxs-radius-md)]',
|
|
35
411
|
md: 'h-10 px-4 text-sm rounded-[var(--cxs-radius-md)]',
|
|
36
412
|
lg: 'h-12 px-5 text-base rounded-[var(--cxs-radius-md)]'
|
|
37
413
|
};
|
|
38
414
|
class CxsButtonComponent {
|
|
415
|
+
hostClass;
|
|
39
416
|
variant = 'primary';
|
|
40
417
|
size = 'md';
|
|
41
418
|
disabled = false;
|
|
42
419
|
loading = false;
|
|
43
420
|
type = 'button';
|
|
421
|
+
constructor(hostClass) {
|
|
422
|
+
this.hostClass = hostClass;
|
|
423
|
+
}
|
|
44
424
|
get isDisabled() {
|
|
45
425
|
return this.disabled || this.loading;
|
|
46
426
|
}
|
|
47
427
|
get buttonClass() {
|
|
48
|
-
return [BASE_CLASSES$
|
|
428
|
+
return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$5[this.variant], this.hostClass]
|
|
429
|
+
.filter(Boolean)
|
|
430
|
+
.join(' ');
|
|
49
431
|
}
|
|
50
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
51
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
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 });
|
|
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 });
|
|
52
434
|
}
|
|
53
435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, decorators: [{
|
|
54
436
|
type: Component,
|
|
55
|
-
args: [{ selector: 'cxs-button', standalone: true,
|
|
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" }]
|
|
438
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
439
|
+
type: Attribute,
|
|
440
|
+
args: ['class']
|
|
441
|
+
}] }], propDecorators: { variant: [{
|
|
442
|
+
type: Input
|
|
443
|
+
}], size: [{
|
|
444
|
+
type: Input
|
|
445
|
+
}], disabled: [{
|
|
446
|
+
type: Input
|
|
447
|
+
}], loading: [{
|
|
448
|
+
type: Input
|
|
449
|
+
}], type: [{
|
|
450
|
+
type: Input
|
|
451
|
+
}] } });
|
|
452
|
+
|
|
453
|
+
const BASE_CLASSES$4 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
454
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
|
|
455
|
+
const VARIANT_CLASSES$4 = {
|
|
456
|
+
surface: 'bg-[var(--cxs-color-surface)]',
|
|
457
|
+
muted: 'bg-[var(--cxs-color-surface-hover)]',
|
|
458
|
+
outline: 'bg-transparent'
|
|
459
|
+
};
|
|
460
|
+
const SIZE_CLASSES$3 = {
|
|
461
|
+
sm: 'p-3',
|
|
462
|
+
md: 'p-5',
|
|
463
|
+
lg: 'p-7'
|
|
464
|
+
};
|
|
465
|
+
class CxsCardComponent {
|
|
466
|
+
variant = 'surface';
|
|
467
|
+
size = 'md';
|
|
468
|
+
elevated = true;
|
|
469
|
+
ariaLabel;
|
|
470
|
+
ariaLabelledby;
|
|
471
|
+
get cardClass() {
|
|
472
|
+
return [
|
|
473
|
+
BASE_CLASSES$4,
|
|
474
|
+
VARIANT_CLASSES$4[this.variant],
|
|
475
|
+
SIZE_CLASSES$3[this.size],
|
|
476
|
+
this.elevated ? 'shadow-[var(--cxs-shadow-sm)]' : ''
|
|
477
|
+
]
|
|
478
|
+
.filter(Boolean)
|
|
479
|
+
.join(' ');
|
|
480
|
+
}
|
|
481
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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 });
|
|
483
|
+
}
|
|
484
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, decorators: [{
|
|
485
|
+
type: Component,
|
|
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" }]
|
|
56
487
|
}], propDecorators: { variant: [{
|
|
57
488
|
type: Input
|
|
58
|
-
}], size: [{
|
|
489
|
+
}], size: [{
|
|
490
|
+
type: Input
|
|
491
|
+
}], elevated: [{
|
|
492
|
+
type: Input
|
|
493
|
+
}], ariaLabel: [{
|
|
494
|
+
type: Input
|
|
495
|
+
}], ariaLabelledby: [{
|
|
496
|
+
type: Input
|
|
497
|
+
}] } });
|
|
498
|
+
|
|
499
|
+
const WRAPPER_BASE$1 = 'inline-flex items-center gap-2 select-none';
|
|
500
|
+
const WRAPPER_ENABLED$1 = 'cursor-pointer';
|
|
501
|
+
const WRAPPER_DISABLED$1 = 'cursor-not-allowed opacity-60';
|
|
502
|
+
const LABEL_BASE$1 = 'text-[var(--cxs-color-on-surface)]';
|
|
503
|
+
const LABEL_DISABLED$1 = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
504
|
+
const LABEL_SIZE_CLASSES$1 = {
|
|
505
|
+
sm: 'text-sm',
|
|
506
|
+
md: 'text-sm',
|
|
507
|
+
lg: 'text-base'
|
|
508
|
+
};
|
|
509
|
+
const CONTROL_BASE$1 = "relative flex shrink-0 items-center justify-center rounded-[var(--cxs-radius-md)] border " +
|
|
510
|
+
"border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-primary)] " +
|
|
511
|
+
"transition-colors after:absolute after:origin-center after:rotate-45 after:content-[''] " +
|
|
512
|
+
'after:opacity-0 after:transition-opacity after:border-b-2 after:border-r-2 after:border-current ' +
|
|
513
|
+
"before:absolute before:content-[''] before:opacity-0 before:transition-opacity before:bg-current " +
|
|
514
|
+
'peer-checked:bg-[var(--cxs-color-primary)] peer-checked:border-[var(--cxs-color-primary)] ' +
|
|
515
|
+
'peer-checked:after:opacity-100 ' +
|
|
516
|
+
'peer-indeterminate:bg-[var(--cxs-color-primary)] peer-indeterminate:border-[var(--cxs-color-primary)] ' +
|
|
517
|
+
'peer-indeterminate:before:opacity-100 peer-indeterminate:after:opacity-0 ' +
|
|
518
|
+
'peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 ' +
|
|
519
|
+
'peer-focus-visible:outline-[var(--cxs-color-focus)]';
|
|
520
|
+
const CONTROL_SIZE_CLASSES$1 = {
|
|
521
|
+
sm: 'h-4 w-4',
|
|
522
|
+
md: 'h-5 w-5',
|
|
523
|
+
lg: 'h-6 w-6'
|
|
524
|
+
};
|
|
525
|
+
const MARK_SIZE_CLASSES = {
|
|
526
|
+
sm: 'after:h-2 after:w-1 before:h-0.5 before:w-2',
|
|
527
|
+
md: 'after:h-2.5 after:w-1.5 before:h-0.5 before:w-3',
|
|
528
|
+
lg: 'after:h-3 after:w-2 before:h-0.5 before:w-4'
|
|
529
|
+
};
|
|
530
|
+
class CxsCheckboxComponent {
|
|
531
|
+
checked = false;
|
|
532
|
+
indeterminate = false;
|
|
533
|
+
disabled = false;
|
|
534
|
+
label;
|
|
535
|
+
size = 'md';
|
|
536
|
+
id;
|
|
537
|
+
name;
|
|
538
|
+
required = false;
|
|
539
|
+
autofocus = false;
|
|
540
|
+
ariaLabel;
|
|
541
|
+
ariaDescribedby;
|
|
542
|
+
valueChange = new EventEmitter();
|
|
543
|
+
disabledFromControl = false;
|
|
544
|
+
onChange = () => { };
|
|
545
|
+
onTouched = () => { };
|
|
546
|
+
get isDisabled() {
|
|
547
|
+
return this.disabled || this.disabledFromControl;
|
|
548
|
+
}
|
|
549
|
+
get wrapperClass() {
|
|
550
|
+
return [
|
|
551
|
+
WRAPPER_BASE$1,
|
|
552
|
+
this.isDisabled ? WRAPPER_DISABLED$1 : WRAPPER_ENABLED$1
|
|
553
|
+
].join(' ');
|
|
554
|
+
}
|
|
555
|
+
get labelClass() {
|
|
556
|
+
return [
|
|
557
|
+
LABEL_BASE$1,
|
|
558
|
+
LABEL_SIZE_CLASSES$1[this.size],
|
|
559
|
+
this.isDisabled ? LABEL_DISABLED$1 : ''
|
|
560
|
+
]
|
|
561
|
+
.filter(Boolean)
|
|
562
|
+
.join(' ');
|
|
563
|
+
}
|
|
564
|
+
get controlClass() {
|
|
565
|
+
return [
|
|
566
|
+
CONTROL_BASE$1,
|
|
567
|
+
CONTROL_SIZE_CLASSES$1[this.size],
|
|
568
|
+
MARK_SIZE_CLASSES[this.size]
|
|
569
|
+
].join(' ');
|
|
570
|
+
}
|
|
571
|
+
get ariaChecked() {
|
|
572
|
+
return this.indeterminate ? 'mixed' : null;
|
|
573
|
+
}
|
|
574
|
+
writeValue(value) {
|
|
575
|
+
this.checked = value ?? false;
|
|
576
|
+
}
|
|
577
|
+
registerOnChange(fn) {
|
|
578
|
+
this.onChange = fn;
|
|
579
|
+
}
|
|
580
|
+
registerOnTouched(fn) {
|
|
581
|
+
this.onTouched = fn;
|
|
582
|
+
}
|
|
583
|
+
setDisabledState(isDisabled) {
|
|
584
|
+
this.disabledFromControl = isDisabled;
|
|
585
|
+
}
|
|
586
|
+
onCheckboxChange(event) {
|
|
587
|
+
const target = event.target;
|
|
588
|
+
const nextValue = target.checked;
|
|
589
|
+
this.indeterminate = false;
|
|
590
|
+
this.checked = nextValue;
|
|
591
|
+
this.onChange(nextValue);
|
|
592
|
+
this.valueChange.emit(nextValue);
|
|
593
|
+
}
|
|
594
|
+
onBlur() {
|
|
595
|
+
this.onTouched();
|
|
596
|
+
}
|
|
597
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
598
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsCheckboxComponent, isStandalone: true, selector: "cxs-checkbox", inputs: { checked: "checked", indeterminate: "indeterminate", disabled: "disabled", label: "label", size: "size", id: "id", name: "name", required: "required", autofocus: "autofocus", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
|
|
599
|
+
{
|
|
600
|
+
provide: NG_VALUE_ACCESSOR,
|
|
601
|
+
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
602
|
+
multi: true
|
|
603
|
+
}
|
|
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 });
|
|
605
|
+
}
|
|
606
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCheckboxComponent, decorators: [{
|
|
607
|
+
type: Component,
|
|
608
|
+
args: [{ selector: 'cxs-checkbox', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
609
|
+
{
|
|
610
|
+
provide: NG_VALUE_ACCESSOR,
|
|
611
|
+
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
612
|
+
multi: true
|
|
613
|
+
}
|
|
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" }]
|
|
615
|
+
}], propDecorators: { checked: [{
|
|
616
|
+
type: Input
|
|
617
|
+
}], indeterminate: [{
|
|
618
|
+
type: Input
|
|
619
|
+
}], disabled: [{
|
|
620
|
+
type: Input
|
|
621
|
+
}], label: [{
|
|
622
|
+
type: Input
|
|
623
|
+
}], size: [{
|
|
624
|
+
type: Input
|
|
625
|
+
}], id: [{
|
|
626
|
+
type: Input
|
|
627
|
+
}], name: [{
|
|
628
|
+
type: Input
|
|
629
|
+
}], required: [{
|
|
630
|
+
type: Input
|
|
631
|
+
}], autofocus: [{
|
|
632
|
+
type: Input
|
|
633
|
+
}], ariaLabel: [{
|
|
634
|
+
type: Input
|
|
635
|
+
}], ariaDescribedby: [{
|
|
636
|
+
type: Input
|
|
637
|
+
}], valueChange: [{
|
|
638
|
+
type: Output
|
|
639
|
+
}] } });
|
|
640
|
+
|
|
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)] ' +
|
|
648
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
649
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
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;
|
|
667
|
+
}
|
|
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
|
+
}
|
|
675
|
+
}
|
|
676
|
+
ngAfterViewInit() {
|
|
677
|
+
this.resetAutoplay();
|
|
678
|
+
}
|
|
679
|
+
ngOnDestroy() {
|
|
680
|
+
this.clearAutoplay();
|
|
681
|
+
}
|
|
682
|
+
get wrapperClass() {
|
|
683
|
+
return [WRAPPER_BASE_CLASSES$2, this.hostClass].filter(Boolean).join(' ');
|
|
684
|
+
}
|
|
685
|
+
get trackStyle() {
|
|
686
|
+
return `translateX(-${this.activeIndex * 100}%)`;
|
|
687
|
+
}
|
|
688
|
+
get trackClass() {
|
|
689
|
+
return TRACK_CLASSES;
|
|
690
|
+
}
|
|
691
|
+
get slideClass() {
|
|
692
|
+
return SLIDE_BASE_CLASSES;
|
|
693
|
+
}
|
|
694
|
+
get imageClass() {
|
|
695
|
+
return IMAGE_CLASSES;
|
|
696
|
+
}
|
|
697
|
+
get contentClass() {
|
|
698
|
+
return CONTENT_CLASSES;
|
|
699
|
+
}
|
|
700
|
+
get controlClass() {
|
|
701
|
+
return CONTROL_CLASSES;
|
|
702
|
+
}
|
|
703
|
+
get indicatorContainerClass() {
|
|
704
|
+
return INDICATOR_CONTAINER_CLASSES;
|
|
705
|
+
}
|
|
706
|
+
indicatorClass(isActive) {
|
|
707
|
+
return [INDICATOR_BASE_CLASSES, isActive ? INDICATOR_ACTIVE_CLASSES : '']
|
|
708
|
+
.filter(Boolean)
|
|
709
|
+
.join(' ');
|
|
710
|
+
}
|
|
711
|
+
previous() {
|
|
712
|
+
this.goTo(this.activeIndex - 1);
|
|
713
|
+
}
|
|
714
|
+
next() {
|
|
715
|
+
this.goTo(this.activeIndex + 1);
|
|
716
|
+
}
|
|
717
|
+
goTo(index) {
|
|
718
|
+
const nextIndex = this.normalizeIndex(index);
|
|
719
|
+
this.activeIndex = nextIndex;
|
|
720
|
+
this.activeIndexChange.emit(nextIndex);
|
|
721
|
+
}
|
|
722
|
+
normalizeIndex(index) {
|
|
723
|
+
if (!this.items.length) {
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
if (this.loop) {
|
|
727
|
+
const total = this.items.length;
|
|
728
|
+
return (index + total) % total;
|
|
729
|
+
}
|
|
730
|
+
return this.clampIndex(index);
|
|
731
|
+
}
|
|
732
|
+
clampIndex(index) {
|
|
733
|
+
if (!this.items.length) {
|
|
734
|
+
return 0;
|
|
735
|
+
}
|
|
736
|
+
return Math.min(Math.max(0, index), this.items.length - 1);
|
|
737
|
+
}
|
|
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
|
+
}
|
|
753
|
+
}
|
|
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
|
+
const WRAPPER_BASE_CLASSES$1 = 'w-full overflow-hidden';
|
|
784
|
+
const WRAPPER_BORDERED_CLASSES$1 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
|
|
785
|
+
const TABLE_BASE_CLASSES$1 = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
|
|
786
|
+
const TABLE_COMPACT_CLASSES$1 = 'text-xs';
|
|
787
|
+
const HEADER_ROW_CLASSES$1 = 'border-b border-[var(--cxs-color-border)] text-xs font-semibold ' +
|
|
788
|
+
'text-[var(--cxs-color-on-surface-muted)]';
|
|
789
|
+
const HEADER_CELL_BASE_CLASSES$1 = 'px-3 py-2 text-left';
|
|
790
|
+
const HEADER_BUTTON_CLASSES = 'inline-flex items-center gap-2 rounded-[var(--cxs-radius-md)] px-2 py-1 ' +
|
|
791
|
+
'transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
792
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
793
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
794
|
+
const HEADER_FILTER_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
795
|
+
'bg-[var(--cxs-color-surface)] px-2 py-1 text-xs text-[var(--cxs-color-on-surface)] ' +
|
|
796
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
|
|
797
|
+
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
798
|
+
const BODY_ROW_BASE_CLASSES$1 = 'border-b border-[var(--cxs-color-border)] last:border-b-0';
|
|
799
|
+
const BODY_ROW_STRIPED_CLASSES$1 = 'odd:bg-[var(--cxs-color-surface)] even:bg-[var(--cxs-color-surface-hover)]';
|
|
800
|
+
const BODY_CELL_BASE_CLASSES$1 = 'px-3 py-2 align-top';
|
|
801
|
+
const BODY_CELL_COMPACT_CLASSES$1 = 'px-2 py-1.5';
|
|
802
|
+
const ALIGN_CLASSES$1 = {
|
|
803
|
+
left: 'text-left',
|
|
804
|
+
center: 'text-center',
|
|
805
|
+
right: 'text-right'
|
|
806
|
+
};
|
|
807
|
+
const EMPTY_ROW_CLASSES$1 = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
808
|
+
const PAGINATION_CLASSES = 'mt-4 flex flex-wrap items-center justify-between gap-3 text-sm text-[var(--cxs-color-on-surface)]';
|
|
809
|
+
const PAGE_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
810
|
+
'px-3 py-1.5 text-sm transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
811
|
+
'disabled:cursor-not-allowed disabled:opacity-60';
|
|
812
|
+
const PAGE_SELECT_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
813
|
+
'px-2 py-1 text-sm';
|
|
814
|
+
const TOOLBAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 text-sm text-[var(--cxs-color-on-surface)]';
|
|
815
|
+
const TOOLBAR_GROUP_CLASSES = 'flex flex-wrap items-center gap-2';
|
|
816
|
+
const TOOLBAR_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
817
|
+
'bg-[var(--cxs-color-surface)] px-3 py-2 text-sm text-[var(--cxs-color-on-surface)] ' +
|
|
818
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
|
|
819
|
+
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
820
|
+
const TOOLBAR_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
821
|
+
'px-3 py-2 text-sm transition-colors hover:bg-[var(--cxs-color-surface-hover)]';
|
|
822
|
+
const BULK_BAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 rounded-[var(--cxs-radius-md)] ' +
|
|
823
|
+
'border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] px-3 py-2 text-sm';
|
|
824
|
+
const RESIZE_HANDLE_CLASSES = 'absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none';
|
|
825
|
+
class CxsDataTableComponent {
|
|
826
|
+
hostClass;
|
|
827
|
+
columns = [];
|
|
828
|
+
data = [];
|
|
829
|
+
caption;
|
|
830
|
+
ariaLabel = 'Data table';
|
|
831
|
+
striped = false;
|
|
832
|
+
bordered = false;
|
|
833
|
+
compact = false;
|
|
834
|
+
loading = false;
|
|
835
|
+
emptyMessage = 'No data available';
|
|
836
|
+
emptyCell = '—';
|
|
837
|
+
pageSize = 10;
|
|
838
|
+
pageIndex = 1;
|
|
839
|
+
pageSizeOptions = [10, 20, 50];
|
|
840
|
+
showPagination = true;
|
|
841
|
+
showPageSize = true;
|
|
842
|
+
manualPagination = false;
|
|
843
|
+
total;
|
|
844
|
+
sortKey;
|
|
845
|
+
sortDirection = 'asc';
|
|
846
|
+
manualSort = false;
|
|
847
|
+
showToolbar = true;
|
|
848
|
+
showFilters = true;
|
|
849
|
+
showColumnVisibility = true;
|
|
850
|
+
showGlobalSearch = true;
|
|
851
|
+
manualFilter = false;
|
|
852
|
+
selectable = false;
|
|
853
|
+
rowKey = 'id';
|
|
854
|
+
selectedKeys = [];
|
|
855
|
+
bulkActions = [];
|
|
856
|
+
pageChange = new EventEmitter();
|
|
857
|
+
pageSizeChange = new EventEmitter();
|
|
858
|
+
sortChange = new EventEmitter();
|
|
859
|
+
filterChange = new EventEmitter();
|
|
860
|
+
selectionChange = new EventEmitter();
|
|
861
|
+
bulkAction = new EventEmitter();
|
|
862
|
+
currentPage = 1;
|
|
863
|
+
currentPageSize = 10;
|
|
864
|
+
globalFilter = '';
|
|
865
|
+
columnFilters = {};
|
|
866
|
+
columnVisibility = {};
|
|
867
|
+
columnWidths = {};
|
|
868
|
+
isResizing = false;
|
|
869
|
+
resizingColumn;
|
|
870
|
+
pinnedOffsetsLeft = {};
|
|
871
|
+
pinnedOffsetsRight = {};
|
|
872
|
+
filtersOpen = true;
|
|
873
|
+
resizeStartX = 0;
|
|
874
|
+
resizeStartWidth = 0;
|
|
875
|
+
constructor(hostClass) {
|
|
876
|
+
this.hostClass = hostClass;
|
|
877
|
+
}
|
|
878
|
+
ngOnChanges(changes) {
|
|
879
|
+
if (changes['pageIndex']) {
|
|
880
|
+
this.currentPage = Math.max(1, this.pageIndex);
|
|
881
|
+
}
|
|
882
|
+
if (changes['pageSize']) {
|
|
883
|
+
this.currentPageSize = Math.max(1, this.pageSize);
|
|
884
|
+
}
|
|
885
|
+
if (changes['columns']) {
|
|
886
|
+
this.initializeVisibility();
|
|
887
|
+
this.initializeWidths();
|
|
888
|
+
this.updatePinnedOffsets();
|
|
889
|
+
}
|
|
890
|
+
if (changes['showFilters']) {
|
|
891
|
+
this.filtersOpen = this.showFilters;
|
|
892
|
+
}
|
|
893
|
+
if (changes['selectedKeys']) {
|
|
894
|
+
this.selectedKeys = [...this.selectedKeys];
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
get wrapperClass() {
|
|
898
|
+
return [
|
|
899
|
+
WRAPPER_BASE_CLASSES$1,
|
|
900
|
+
this.bordered ? WRAPPER_BORDERED_CLASSES$1 : '',
|
|
901
|
+
this.hostClass
|
|
902
|
+
]
|
|
903
|
+
.filter(Boolean)
|
|
904
|
+
.join(' ');
|
|
905
|
+
}
|
|
906
|
+
get tableClass() {
|
|
907
|
+
return [TABLE_BASE_CLASSES$1, this.compact ? TABLE_COMPACT_CLASSES$1 : '']
|
|
908
|
+
.filter(Boolean)
|
|
909
|
+
.join(' ');
|
|
910
|
+
}
|
|
911
|
+
get headerRowClass() {
|
|
912
|
+
return HEADER_ROW_CLASSES$1;
|
|
913
|
+
}
|
|
914
|
+
get bodyRowClass() {
|
|
915
|
+
return [
|
|
916
|
+
BODY_ROW_BASE_CLASSES$1,
|
|
917
|
+
this.striped ? BODY_ROW_STRIPED_CLASSES$1 : ''
|
|
918
|
+
]
|
|
919
|
+
.filter(Boolean)
|
|
920
|
+
.join(' ');
|
|
921
|
+
}
|
|
922
|
+
get emptyRowClass() {
|
|
923
|
+
return EMPTY_ROW_CLASSES$1;
|
|
924
|
+
}
|
|
925
|
+
get paginationClass() {
|
|
926
|
+
return PAGINATION_CLASSES;
|
|
927
|
+
}
|
|
928
|
+
get pageButtonClass() {
|
|
929
|
+
return PAGE_BUTTON_CLASSES;
|
|
930
|
+
}
|
|
931
|
+
get pageSelectClass() {
|
|
932
|
+
return PAGE_SELECT_CLASSES;
|
|
933
|
+
}
|
|
934
|
+
get toolbarClass() {
|
|
935
|
+
return TOOLBAR_CLASSES;
|
|
936
|
+
}
|
|
937
|
+
get toolbarGroupClass() {
|
|
938
|
+
return TOOLBAR_GROUP_CLASSES;
|
|
939
|
+
}
|
|
940
|
+
get toolbarInputClass() {
|
|
941
|
+
return TOOLBAR_INPUT_CLASSES;
|
|
942
|
+
}
|
|
943
|
+
get toolbarButtonClass() {
|
|
944
|
+
return TOOLBAR_BUTTON_CLASSES;
|
|
945
|
+
}
|
|
946
|
+
get bulkBarClass() {
|
|
947
|
+
return BULK_BAR_CLASSES;
|
|
948
|
+
}
|
|
949
|
+
get resizeHandleClass() {
|
|
950
|
+
return RESIZE_HANDLE_CLASSES;
|
|
951
|
+
}
|
|
952
|
+
get colSpan() {
|
|
953
|
+
return Math.max(this.visibleColumns.length + (this.selectable ? 1 : 0), 1);
|
|
954
|
+
}
|
|
955
|
+
get totalItems() {
|
|
956
|
+
if (this.manualPagination && this.total !== undefined) {
|
|
957
|
+
return this.total;
|
|
958
|
+
}
|
|
959
|
+
return this.data.length;
|
|
960
|
+
}
|
|
961
|
+
get totalPages() {
|
|
962
|
+
return Math.max(1, Math.ceil(this.totalItems / this.currentPageSize));
|
|
963
|
+
}
|
|
964
|
+
get pageLabel() {
|
|
965
|
+
return `Page ${this.currentPage} of ${this.totalPages}`;
|
|
966
|
+
}
|
|
967
|
+
get displayRows() {
|
|
968
|
+
const filtered = this.manualFilter ? this.data : this.getFilteredData(this.data);
|
|
969
|
+
const sorted = this.manualSort ? filtered : this.getSortedData(filtered);
|
|
970
|
+
if (this.manualPagination) {
|
|
971
|
+
return sorted;
|
|
972
|
+
}
|
|
973
|
+
const start = (this.currentPage - 1) * this.currentPageSize;
|
|
974
|
+
return sorted.slice(start, start + this.currentPageSize);
|
|
975
|
+
}
|
|
976
|
+
get visibleColumns() {
|
|
977
|
+
return this.columns.filter((column) => this.columnVisibility[column.key] !== false);
|
|
978
|
+
}
|
|
979
|
+
get selectedCount() {
|
|
980
|
+
return this.selectedKeys.length;
|
|
981
|
+
}
|
|
982
|
+
get allVisibleSelected() {
|
|
983
|
+
if (!this.displayRows.length) {
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
return this.displayRows.every((row) => this.isSelected(row));
|
|
987
|
+
}
|
|
988
|
+
get someVisibleSelected() {
|
|
989
|
+
return this.displayRows.some((row) => this.isSelected(row)) && !this.allVisibleSelected;
|
|
990
|
+
}
|
|
991
|
+
headerCellClass(column) {
|
|
992
|
+
return [
|
|
993
|
+
HEADER_CELL_BASE_CLASSES$1,
|
|
994
|
+
ALIGN_CLASSES$1[column.align ?? 'left'],
|
|
995
|
+
column.headerClass ?? ''
|
|
996
|
+
]
|
|
997
|
+
.filter(Boolean)
|
|
998
|
+
.join(' ');
|
|
999
|
+
}
|
|
1000
|
+
headerButtonClass() {
|
|
1001
|
+
return HEADER_BUTTON_CLASSES;
|
|
1002
|
+
}
|
|
1003
|
+
headerFilterInputClass() {
|
|
1004
|
+
return HEADER_FILTER_INPUT_CLASSES;
|
|
1005
|
+
}
|
|
1006
|
+
bodyCellClass(column) {
|
|
1007
|
+
return [
|
|
1008
|
+
BODY_CELL_BASE_CLASSES$1,
|
|
1009
|
+
this.compact ? BODY_CELL_COMPACT_CLASSES$1 : '',
|
|
1010
|
+
ALIGN_CLASSES$1[column.align ?? 'left'],
|
|
1011
|
+
column.cellClass ?? ''
|
|
1012
|
+
]
|
|
1013
|
+
.filter(Boolean)
|
|
1014
|
+
.join(' ');
|
|
1015
|
+
}
|
|
1016
|
+
cellValue(row, column) {
|
|
1017
|
+
const value = row[column.key];
|
|
1018
|
+
if (column.formatter) {
|
|
1019
|
+
return column.formatter(value, row);
|
|
1020
|
+
}
|
|
1021
|
+
if (value === null || value === undefined || value === '') {
|
|
1022
|
+
return this.emptyCell;
|
|
1023
|
+
}
|
|
1024
|
+
return String(value);
|
|
1025
|
+
}
|
|
1026
|
+
columnWidth(column) {
|
|
1027
|
+
return this.columnWidths[column.key] ?? column.width ?? null;
|
|
1028
|
+
}
|
|
1029
|
+
columnMinWidth(column) {
|
|
1030
|
+
if (column.minWidth) {
|
|
1031
|
+
return `${column.minWidth}px`;
|
|
1032
|
+
}
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
pinnedStyle(column) {
|
|
1036
|
+
if (!column.pinned) {
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
if (column.pinned === 'left') {
|
|
1040
|
+
return { left: `${this.pinnedOffsetsLeft[column.key] ?? 0}px` };
|
|
1041
|
+
}
|
|
1042
|
+
return { right: `${this.pinnedOffsetsRight[column.key] ?? 0}px` };
|
|
1043
|
+
}
|
|
1044
|
+
pinnedLeft(column) {
|
|
1045
|
+
const style = this.pinnedStyle(column);
|
|
1046
|
+
return style ? style['left'] ?? null : null;
|
|
1047
|
+
}
|
|
1048
|
+
pinnedRight(column) {
|
|
1049
|
+
const style = this.pinnedStyle(column);
|
|
1050
|
+
return style ? style['right'] ?? null : null;
|
|
1051
|
+
}
|
|
1052
|
+
pinnedClass(column) {
|
|
1053
|
+
if (!column.pinned) {
|
|
1054
|
+
return '';
|
|
1055
|
+
}
|
|
1056
|
+
return 'sticky z-10';
|
|
1057
|
+
}
|
|
1058
|
+
ariaSort(column) {
|
|
1059
|
+
if (!column.sortable) {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
if (this.sortKey !== column.key) {
|
|
1063
|
+
return 'none';
|
|
1064
|
+
}
|
|
1065
|
+
return this.sortDirection === 'asc' ? 'ascending' : 'descending';
|
|
1066
|
+
}
|
|
1067
|
+
onSort(column) {
|
|
1068
|
+
if (!column.sortable) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
if (this.sortKey === column.key) {
|
|
1072
|
+
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
this.sortKey = column.key;
|
|
1076
|
+
this.sortDirection = 'asc';
|
|
1077
|
+
}
|
|
1078
|
+
this.sortChange.emit({
|
|
1079
|
+
key: this.sortKey,
|
|
1080
|
+
direction: this.sortDirection
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
goToPage(page) {
|
|
1084
|
+
const nextPage = Math.min(Math.max(1, page), this.totalPages);
|
|
1085
|
+
this.currentPage = nextPage;
|
|
1086
|
+
this.pageChange.emit(nextPage);
|
|
1087
|
+
}
|
|
1088
|
+
nextPage() {
|
|
1089
|
+
this.goToPage(this.currentPage + 1);
|
|
1090
|
+
}
|
|
1091
|
+
previousPage() {
|
|
1092
|
+
this.goToPage(this.currentPage - 1);
|
|
1093
|
+
}
|
|
1094
|
+
onPageSizeChange(value) {
|
|
1095
|
+
const nextSize = Number(value);
|
|
1096
|
+
if (!Number.isFinite(nextSize) || nextSize <= 0) {
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
this.currentPageSize = nextSize;
|
|
1100
|
+
this.pageSizeChange.emit(nextSize);
|
|
1101
|
+
this.goToPage(1);
|
|
1102
|
+
}
|
|
1103
|
+
onGlobalFilterChange(value) {
|
|
1104
|
+
this.globalFilter = value;
|
|
1105
|
+
this.emitFilterChange();
|
|
1106
|
+
this.goToPage(1);
|
|
1107
|
+
}
|
|
1108
|
+
onColumnFilterChange(columnKey, value) {
|
|
1109
|
+
this.columnFilters[columnKey] = value;
|
|
1110
|
+
this.emitFilterChange();
|
|
1111
|
+
this.goToPage(1);
|
|
1112
|
+
}
|
|
1113
|
+
columnFilterValue(columnKey) {
|
|
1114
|
+
return this.columnFilters[columnKey] || '';
|
|
1115
|
+
}
|
|
1116
|
+
toggleColumnVisibility(columnKey) {
|
|
1117
|
+
this.columnVisibility[columnKey] = !this.columnVisibility[columnKey];
|
|
1118
|
+
this.updatePinnedOffsets();
|
|
1119
|
+
}
|
|
1120
|
+
toggleSelectAll() {
|
|
1121
|
+
if (this.allVisibleSelected) {
|
|
1122
|
+
this.selectedKeys = this.selectedKeys.filter((key) => !this.displayRows.some((row) => this.rowIdentifier(row) === key));
|
|
1123
|
+
}
|
|
1124
|
+
else {
|
|
1125
|
+
const keysToAdd = this.displayRows
|
|
1126
|
+
.map((row) => this.rowIdentifier(row))
|
|
1127
|
+
.filter((key) => !this.selectedKeys.includes(key));
|
|
1128
|
+
this.selectedKeys = [...this.selectedKeys, ...keysToAdd];
|
|
1129
|
+
}
|
|
1130
|
+
this.selectionChange.emit([...this.selectedKeys]);
|
|
1131
|
+
}
|
|
1132
|
+
toggleRowSelection(row) {
|
|
1133
|
+
const key = this.rowIdentifier(row);
|
|
1134
|
+
if (this.selectedKeys.includes(key)) {
|
|
1135
|
+
this.selectedKeys = this.selectedKeys.filter((id) => id !== key);
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
this.selectedKeys = [...this.selectedKeys, key];
|
|
1139
|
+
}
|
|
1140
|
+
this.selectionChange.emit([...this.selectedKeys]);
|
|
1141
|
+
}
|
|
1142
|
+
isSelected(row) {
|
|
1143
|
+
return this.selectedKeys.includes(this.rowIdentifier(row));
|
|
1144
|
+
}
|
|
1145
|
+
runBulkAction(actionId) {
|
|
1146
|
+
this.bulkAction.emit({
|
|
1147
|
+
id: actionId,
|
|
1148
|
+
selected: this.data.filter((row) => this.selectedKeys.includes(this.rowIdentifier(row)))
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
onResizeStart(event, column) {
|
|
1152
|
+
if (column.resizable === false) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
event.preventDefault();
|
|
1156
|
+
const header = event.target.closest('th');
|
|
1157
|
+
if (!header) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
this.isResizing = true;
|
|
1161
|
+
this.resizingColumn = column.key;
|
|
1162
|
+
this.resizeStartX = event.clientX;
|
|
1163
|
+
this.resizeStartWidth = header.getBoundingClientRect().width;
|
|
1164
|
+
const onMove = (moveEvent) => {
|
|
1165
|
+
if (!this.isResizing || !this.resizingColumn) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
const delta = moveEvent.clientX - this.resizeStartX;
|
|
1169
|
+
const minWidth = column.minWidth ?? 80;
|
|
1170
|
+
const nextWidth = Math.max(minWidth, this.resizeStartWidth + delta);
|
|
1171
|
+
this.columnWidths[this.resizingColumn] = `${Math.round(nextWidth)}px`;
|
|
1172
|
+
this.updatePinnedOffsets();
|
|
1173
|
+
};
|
|
1174
|
+
const onUp = () => {
|
|
1175
|
+
this.isResizing = false;
|
|
1176
|
+
this.resizingColumn = undefined;
|
|
1177
|
+
window.removeEventListener('mousemove', onMove);
|
|
1178
|
+
window.removeEventListener('mouseup', onUp);
|
|
1179
|
+
};
|
|
1180
|
+
window.addEventListener('mousemove', onMove);
|
|
1181
|
+
window.addEventListener('mouseup', onUp);
|
|
1182
|
+
}
|
|
1183
|
+
getSortedData(rows) {
|
|
1184
|
+
if (!this.sortKey) {
|
|
1185
|
+
return rows;
|
|
1186
|
+
}
|
|
1187
|
+
const direction = this.sortDirection === 'asc' ? 1 : -1;
|
|
1188
|
+
return [...rows].sort((a, b) => {
|
|
1189
|
+
const valueA = a[this.sortKey ?? ''];
|
|
1190
|
+
const valueB = b[this.sortKey ?? ''];
|
|
1191
|
+
const normalizedA = valueA === null || valueA === undefined ? '' : String(valueA);
|
|
1192
|
+
const normalizedB = valueB === null || valueB === undefined ? '' : String(valueB);
|
|
1193
|
+
return normalizedA.localeCompare(normalizedB, undefined, { numeric: true }) * direction;
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
getFilteredData(rows) {
|
|
1197
|
+
const global = this.globalFilter.trim().toLowerCase();
|
|
1198
|
+
const filters = this.columnFilters;
|
|
1199
|
+
return rows.filter((row) => {
|
|
1200
|
+
if (global) {
|
|
1201
|
+
const matchesGlobal = this.visibleColumns.some((column) => {
|
|
1202
|
+
const value = row[column.key];
|
|
1203
|
+
return String(value ?? '').toLowerCase().includes(global);
|
|
1204
|
+
});
|
|
1205
|
+
if (!matchesGlobal) {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return this.visibleColumns.every((column) => {
|
|
1210
|
+
if (!column.filterable) {
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1213
|
+
const filterValue = (filters[column.key] ?? '').trim().toLowerCase();
|
|
1214
|
+
if (!filterValue) {
|
|
1215
|
+
return true;
|
|
1216
|
+
}
|
|
1217
|
+
const raw = row[column.key];
|
|
1218
|
+
const normalized = String(raw ?? '').toLowerCase();
|
|
1219
|
+
if (column.filterType === 'select') {
|
|
1220
|
+
return normalized === filterValue;
|
|
1221
|
+
}
|
|
1222
|
+
return normalized.includes(filterValue);
|
|
1223
|
+
});
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
emitFilterChange() {
|
|
1227
|
+
this.filterChange.emit({
|
|
1228
|
+
global: this.globalFilter,
|
|
1229
|
+
columns: { ...this.columnFilters }
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
initializeVisibility() {
|
|
1233
|
+
this.columnVisibility = this.columns.reduce((acc, column) => {
|
|
1234
|
+
acc[column.key] = column.visible !== false;
|
|
1235
|
+
return acc;
|
|
1236
|
+
}, {});
|
|
1237
|
+
}
|
|
1238
|
+
initializeWidths() {
|
|
1239
|
+
this.columnWidths = this.columns.reduce((acc, column) => {
|
|
1240
|
+
if (column.width) {
|
|
1241
|
+
acc[column.key] = column.width;
|
|
1242
|
+
}
|
|
1243
|
+
return acc;
|
|
1244
|
+
}, {});
|
|
1245
|
+
}
|
|
1246
|
+
updatePinnedOffsets() {
|
|
1247
|
+
const leftOffsets = {};
|
|
1248
|
+
const rightOffsets = {};
|
|
1249
|
+
let left = 0;
|
|
1250
|
+
let right = 0;
|
|
1251
|
+
const columns = this.visibleColumns;
|
|
1252
|
+
columns.forEach((column) => {
|
|
1253
|
+
if (column.pinned === 'left') {
|
|
1254
|
+
leftOffsets[column.key] = left;
|
|
1255
|
+
left += this.getWidthValue(column);
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
[...columns].reverse().forEach((column) => {
|
|
1259
|
+
if (column.pinned === 'right') {
|
|
1260
|
+
rightOffsets[column.key] = right;
|
|
1261
|
+
right += this.getWidthValue(column);
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
this.pinnedOffsetsLeft = leftOffsets;
|
|
1265
|
+
this.pinnedOffsetsRight = rightOffsets;
|
|
1266
|
+
}
|
|
1267
|
+
getWidthValue(column) {
|
|
1268
|
+
const width = this.columnWidths[column.key] ?? column.width;
|
|
1269
|
+
if (!width) {
|
|
1270
|
+
return 160;
|
|
1271
|
+
}
|
|
1272
|
+
const match = width.match(/(\d+)(px)?/);
|
|
1273
|
+
if (match) {
|
|
1274
|
+
return Number(match[1]);
|
|
1275
|
+
}
|
|
1276
|
+
return 160;
|
|
1277
|
+
}
|
|
1278
|
+
rowIdentifier(row) {
|
|
1279
|
+
const value = row[this.rowKey];
|
|
1280
|
+
if (value === undefined || value === null) {
|
|
1281
|
+
return JSON.stringify(row);
|
|
1282
|
+
}
|
|
1283
|
+
return value;
|
|
1284
|
+
}
|
|
1285
|
+
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 });
|
|
1286
|
+
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" }, 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 {{ cellValue(row, column) }}\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", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1287
|
+
}
|
|
1288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, decorators: [{
|
|
1289
|
+
type: Component,
|
|
1290
|
+
args: [{ selector: 'cxs-data-table', standalone: true, 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 {{ cellValue(row, column) }}\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" }]
|
|
1291
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1292
|
+
type: Attribute,
|
|
1293
|
+
args: ['class']
|
|
1294
|
+
}] }], propDecorators: { columns: [{
|
|
1295
|
+
type: Input
|
|
1296
|
+
}], data: [{
|
|
1297
|
+
type: Input
|
|
1298
|
+
}], caption: [{
|
|
1299
|
+
type: Input
|
|
1300
|
+
}], ariaLabel: [{
|
|
1301
|
+
type: Input
|
|
1302
|
+
}], striped: [{
|
|
1303
|
+
type: Input
|
|
1304
|
+
}], bordered: [{
|
|
1305
|
+
type: Input
|
|
1306
|
+
}], compact: [{
|
|
1307
|
+
type: Input
|
|
1308
|
+
}], loading: [{
|
|
1309
|
+
type: Input
|
|
1310
|
+
}], emptyMessage: [{
|
|
1311
|
+
type: Input
|
|
1312
|
+
}], emptyCell: [{
|
|
1313
|
+
type: Input
|
|
1314
|
+
}], pageSize: [{
|
|
1315
|
+
type: Input
|
|
1316
|
+
}], pageIndex: [{
|
|
1317
|
+
type: Input
|
|
1318
|
+
}], pageSizeOptions: [{
|
|
1319
|
+
type: Input
|
|
1320
|
+
}], showPagination: [{
|
|
1321
|
+
type: Input
|
|
1322
|
+
}], showPageSize: [{
|
|
1323
|
+
type: Input
|
|
1324
|
+
}], manualPagination: [{
|
|
1325
|
+
type: Input
|
|
1326
|
+
}], total: [{
|
|
1327
|
+
type: Input
|
|
1328
|
+
}], sortKey: [{
|
|
1329
|
+
type: Input
|
|
1330
|
+
}], sortDirection: [{
|
|
1331
|
+
type: Input
|
|
1332
|
+
}], manualSort: [{
|
|
1333
|
+
type: Input
|
|
1334
|
+
}], showToolbar: [{
|
|
1335
|
+
type: Input
|
|
1336
|
+
}], showFilters: [{
|
|
1337
|
+
type: Input
|
|
1338
|
+
}], showColumnVisibility: [{
|
|
1339
|
+
type: Input
|
|
1340
|
+
}], showGlobalSearch: [{
|
|
1341
|
+
type: Input
|
|
1342
|
+
}], manualFilter: [{
|
|
1343
|
+
type: Input
|
|
1344
|
+
}], selectable: [{
|
|
1345
|
+
type: Input
|
|
1346
|
+
}], rowKey: [{
|
|
1347
|
+
type: Input
|
|
1348
|
+
}], selectedKeys: [{
|
|
1349
|
+
type: Input
|
|
1350
|
+
}], bulkActions: [{
|
|
1351
|
+
type: Input
|
|
1352
|
+
}], pageChange: [{
|
|
1353
|
+
type: Output
|
|
1354
|
+
}], pageSizeChange: [{
|
|
1355
|
+
type: Output
|
|
1356
|
+
}], sortChange: [{
|
|
1357
|
+
type: Output
|
|
1358
|
+
}], filterChange: [{
|
|
1359
|
+
type: Output
|
|
1360
|
+
}], selectionChange: [{
|
|
1361
|
+
type: Output
|
|
1362
|
+
}], bulkAction: [{
|
|
1363
|
+
type: Output
|
|
1364
|
+
}] } });
|
|
1365
|
+
|
|
1366
|
+
const OVERLAY_CLASSES = 'fixed inset-0 z-50 flex items-center justify-center bg-[rgba(15,23,42,0.45)] p-4';
|
|
1367
|
+
const PANEL_BASE_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1368
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] shadow-[var(--cxs-shadow-sm)] ' +
|
|
1369
|
+
'p-6 outline-none';
|
|
1370
|
+
const PANEL_SIZE_CLASSES = {
|
|
1371
|
+
sm: 'max-w-sm',
|
|
1372
|
+
md: 'max-w-lg',
|
|
1373
|
+
lg: 'max-w-2xl'
|
|
1374
|
+
};
|
|
1375
|
+
const TITLE_CLASSES$1 = 'text-lg font-semibold';
|
|
1376
|
+
const DESCRIPTION_CLASSES = 'mt-1 text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
1377
|
+
const BODY_CLASSES = 'mt-4 text-sm text-[var(--cxs-color-on-surface)]';
|
|
1378
|
+
const ACTIONS_CLASSES$1 = 'mt-6 flex flex-wrap items-center justify-end gap-2 ' +
|
|
1379
|
+
'[&>*]:flex [&>*]:flex-wrap [&>*]:items-center [&>*]:justify-end [&>*]:gap-2';
|
|
1380
|
+
const CLOSE_BUTTON_CLASSES$1 = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
1381
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
1382
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1383
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1384
|
+
class CxsDialogComponent {
|
|
1385
|
+
hostClass;
|
|
1386
|
+
static nextId = 0;
|
|
1387
|
+
open = false;
|
|
1388
|
+
title;
|
|
1389
|
+
description;
|
|
1390
|
+
ariaLabel = 'Dialog';
|
|
1391
|
+
size = 'md';
|
|
1392
|
+
dismissible = true;
|
|
1393
|
+
closeOnBackdrop = true;
|
|
1394
|
+
closeOnEscape = true;
|
|
1395
|
+
openChange = new EventEmitter();
|
|
1396
|
+
closed = new EventEmitter();
|
|
1397
|
+
dialogPanel;
|
|
1398
|
+
titleId = `cxs-dialog-title-${CxsDialogComponent.nextId++}`;
|
|
1399
|
+
descriptionId = `cxs-dialog-description-${CxsDialogComponent.nextId++}`;
|
|
1400
|
+
constructor(hostClass) {
|
|
1401
|
+
this.hostClass = hostClass;
|
|
1402
|
+
}
|
|
1403
|
+
ngOnChanges(changes) {
|
|
1404
|
+
if (changes['open']?.currentValue) {
|
|
1405
|
+
this.focusPanelSoon();
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
ngAfterViewInit() {
|
|
1409
|
+
if (this.open) {
|
|
1410
|
+
this.focusPanelSoon();
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
get overlayClass() {
|
|
1414
|
+
return OVERLAY_CLASSES;
|
|
1415
|
+
}
|
|
1416
|
+
get panelClass() {
|
|
1417
|
+
return [PANEL_BASE_CLASSES, PANEL_SIZE_CLASSES[this.size], this.hostClass]
|
|
1418
|
+
.filter(Boolean)
|
|
1419
|
+
.join(' ');
|
|
1420
|
+
}
|
|
1421
|
+
get titleClass() {
|
|
1422
|
+
return TITLE_CLASSES$1;
|
|
1423
|
+
}
|
|
1424
|
+
get descriptionClass() {
|
|
1425
|
+
return DESCRIPTION_CLASSES;
|
|
1426
|
+
}
|
|
1427
|
+
get bodyClass() {
|
|
1428
|
+
return BODY_CLASSES;
|
|
1429
|
+
}
|
|
1430
|
+
get actionsClass() {
|
|
1431
|
+
return ACTIONS_CLASSES$1;
|
|
1432
|
+
}
|
|
1433
|
+
get closeButtonClass() {
|
|
1434
|
+
return CLOSE_BUTTON_CLASSES$1;
|
|
1435
|
+
}
|
|
1436
|
+
get ariaLabelValue() {
|
|
1437
|
+
if (this.title) {
|
|
1438
|
+
return null;
|
|
1439
|
+
}
|
|
1440
|
+
return this.ariaLabel;
|
|
1441
|
+
}
|
|
1442
|
+
requestClose(reason) {
|
|
1443
|
+
this.openChange.emit(false);
|
|
1444
|
+
this.closed.emit(reason);
|
|
1445
|
+
}
|
|
1446
|
+
onBackdropClick(event) {
|
|
1447
|
+
if (!this.closeOnBackdrop || !this.open) {
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
if (event.target === event.currentTarget) {
|
|
1451
|
+
this.requestClose('backdrop');
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
onKeydown(event) {
|
|
1455
|
+
if (!this.closeOnEscape || !this.open) {
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
if (event.key === 'Escape') {
|
|
1459
|
+
event.preventDefault();
|
|
1460
|
+
this.requestClose('escape');
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
focusPanelSoon() {
|
|
1464
|
+
queueMicrotask(() => {
|
|
1465
|
+
this.dialogPanel?.nativeElement.focus();
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
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 });
|
|
1469
|
+
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 });
|
|
1470
|
+
}
|
|
1471
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, decorators: [{
|
|
1472
|
+
type: Component,
|
|
1473
|
+
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" }]
|
|
1474
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1475
|
+
type: Attribute,
|
|
1476
|
+
args: ['class']
|
|
1477
|
+
}] }], propDecorators: { open: [{
|
|
1478
|
+
type: Input
|
|
1479
|
+
}], title: [{
|
|
1480
|
+
type: Input
|
|
1481
|
+
}], description: [{
|
|
1482
|
+
type: Input
|
|
1483
|
+
}], ariaLabel: [{
|
|
1484
|
+
type: Input
|
|
1485
|
+
}], size: [{
|
|
1486
|
+
type: Input
|
|
1487
|
+
}], dismissible: [{
|
|
1488
|
+
type: Input
|
|
1489
|
+
}], closeOnBackdrop: [{
|
|
1490
|
+
type: Input
|
|
1491
|
+
}], closeOnEscape: [{
|
|
1492
|
+
type: Input
|
|
1493
|
+
}], openChange: [{
|
|
1494
|
+
type: Output
|
|
1495
|
+
}], closed: [{
|
|
1496
|
+
type: Output
|
|
1497
|
+
}], dialogPanel: [{
|
|
1498
|
+
type: ViewChild,
|
|
1499
|
+
args: ['dialogPanel']
|
|
1500
|
+
}] } });
|
|
1501
|
+
|
|
1502
|
+
const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1503
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
1504
|
+
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
1505
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1506
|
+
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
1507
|
+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
1508
|
+
const VARIANT_CLASSES$3 = {
|
|
1509
|
+
outline: 'bg-[var(--cxs-color-surface)]',
|
|
1510
|
+
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
1511
|
+
};
|
|
1512
|
+
const SIZE_CLASSES$2 = {
|
|
1513
|
+
sm: 'h-8 px-3 text-sm',
|
|
1514
|
+
md: 'h-10 px-3 text-sm',
|
|
1515
|
+
lg: 'h-12 px-4 text-base'
|
|
1516
|
+
};
|
|
1517
|
+
const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
|
|
1518
|
+
'focus-visible:outline-[var(--cxs-color-danger)]';
|
|
1519
|
+
const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
|
|
1520
|
+
'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
|
|
1521
|
+
const NAV_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
1522
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
1523
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1524
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1525
|
+
const SELECT_CLASSES = 'h-8 rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
1526
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] text-xs px-2 ' +
|
|
1527
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1528
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1529
|
+
const DAY_BUTTON_BASE = 'flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] text-xs ' +
|
|
1530
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1531
|
+
'focus-visible:outline-[var(--cxs-color-focus)] disabled:cursor-not-allowed disabled:opacity-40';
|
|
1532
|
+
const DAY_OUTSIDE_MONTH = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
1533
|
+
const DAY_TODAY = 'border border-[var(--cxs-color-primary)]';
|
|
1534
|
+
const DAY_SELECTED = 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)]';
|
|
1535
|
+
const DAY_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
|
|
1536
|
+
class CxsDatepickerComponent {
|
|
1537
|
+
value = '';
|
|
1538
|
+
variant = 'outline';
|
|
1539
|
+
size = 'md';
|
|
1540
|
+
useNative = true;
|
|
1541
|
+
disabled = false;
|
|
1542
|
+
readonly = false;
|
|
1543
|
+
required = false;
|
|
1544
|
+
invalid = false;
|
|
1545
|
+
autofocus = false;
|
|
1546
|
+
id;
|
|
1547
|
+
name;
|
|
1548
|
+
min;
|
|
1549
|
+
max;
|
|
1550
|
+
placeholder;
|
|
1551
|
+
ariaLabel;
|
|
1552
|
+
ariaDescribedby;
|
|
1553
|
+
valueChange = new EventEmitter();
|
|
1554
|
+
static nextId = 0;
|
|
1555
|
+
fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
|
|
1556
|
+
disabledFromControl = false;
|
|
1557
|
+
onChange = () => { };
|
|
1558
|
+
onTouched = () => { };
|
|
1559
|
+
isOpen = false;
|
|
1560
|
+
displayMonth = new Date();
|
|
1561
|
+
calendarDays = [];
|
|
1562
|
+
weekDayLabels = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
1563
|
+
monthOptions = Array.from({ length: 12 }, (_, index) => ({
|
|
1564
|
+
value: index,
|
|
1565
|
+
label: new Date(2020, index, 1).toLocaleString('en-US', { month: 'short' })
|
|
1566
|
+
}));
|
|
1567
|
+
get isDisabled() {
|
|
1568
|
+
return this.disabled || this.disabledFromControl;
|
|
1569
|
+
}
|
|
1570
|
+
get panelId() {
|
|
1571
|
+
return this.id ? `${this.id}-panel` : this.fallbackId;
|
|
1572
|
+
}
|
|
1573
|
+
get inputClass() {
|
|
1574
|
+
return [
|
|
1575
|
+
BASE_CLASSES$3,
|
|
1576
|
+
SIZE_CLASSES$2[this.size],
|
|
1577
|
+
VARIANT_CLASSES$3[this.variant],
|
|
1578
|
+
this.invalid ? INVALID_CLASSES$3 : ''
|
|
1579
|
+
]
|
|
1580
|
+
.filter(Boolean)
|
|
1581
|
+
.join(' ');
|
|
1582
|
+
}
|
|
1583
|
+
get popoverClass() {
|
|
1584
|
+
return POPOVER_CLASSES;
|
|
1585
|
+
}
|
|
1586
|
+
get navButtonClass() {
|
|
1587
|
+
return NAV_BUTTON_CLASSES;
|
|
1588
|
+
}
|
|
1589
|
+
get selectClass() {
|
|
1590
|
+
return SELECT_CLASSES;
|
|
1591
|
+
}
|
|
1592
|
+
get displayMonthLabel() {
|
|
1593
|
+
return this.displayMonth.toLocaleString('en-US', { month: 'long', year: 'numeric' });
|
|
1594
|
+
}
|
|
1595
|
+
get yearOptions() {
|
|
1596
|
+
const baseYear = this.displayMonth.getFullYear();
|
|
1597
|
+
const minYear = this.parseDate(this.min)?.getFullYear() ?? baseYear - 10;
|
|
1598
|
+
const maxYear = this.parseDate(this.max)?.getFullYear() ?? baseYear + 10;
|
|
1599
|
+
const start = Math.min(minYear, maxYear);
|
|
1600
|
+
const end = Math.max(minYear, maxYear);
|
|
1601
|
+
return Array.from({ length: end - start + 1 }, (_, index) => start + index);
|
|
1602
|
+
}
|
|
1603
|
+
writeValue(value) {
|
|
1604
|
+
this.value = value ?? '';
|
|
1605
|
+
this.syncDisplayMonthWithValue();
|
|
1606
|
+
}
|
|
1607
|
+
registerOnChange(fn) {
|
|
1608
|
+
this.onChange = fn;
|
|
1609
|
+
}
|
|
1610
|
+
registerOnTouched(fn) {
|
|
1611
|
+
this.onTouched = fn;
|
|
1612
|
+
}
|
|
1613
|
+
setDisabledState(isDisabled) {
|
|
1614
|
+
this.disabledFromControl = isDisabled;
|
|
1615
|
+
}
|
|
1616
|
+
onInput(event) {
|
|
1617
|
+
const target = event.target;
|
|
1618
|
+
const nextValue = target.value;
|
|
1619
|
+
this.value = nextValue;
|
|
1620
|
+
this.onChange(nextValue);
|
|
1621
|
+
this.valueChange.emit(nextValue);
|
|
1622
|
+
}
|
|
1623
|
+
onDateSelect(day) {
|
|
1624
|
+
if (day.disabled || this.isDisabled) {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
const nextValue = this.formatDate(day.date);
|
|
1628
|
+
this.value = nextValue;
|
|
1629
|
+
this.onChange(nextValue);
|
|
1630
|
+
this.valueChange.emit(nextValue);
|
|
1631
|
+
this.isOpen = false;
|
|
1632
|
+
}
|
|
1633
|
+
onBlur() {
|
|
1634
|
+
this.onTouched();
|
|
1635
|
+
}
|
|
1636
|
+
open() {
|
|
1637
|
+
if (this.isDisabled || this.useNative) {
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
this.isOpen = true;
|
|
1641
|
+
this.syncDisplayMonthWithValue();
|
|
1642
|
+
}
|
|
1643
|
+
toggle() {
|
|
1644
|
+
if (this.isOpen) {
|
|
1645
|
+
this.isOpen = false;
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
this.open();
|
|
1649
|
+
}
|
|
1650
|
+
prevMonth() {
|
|
1651
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), this.displayMonth.getMonth() - 1, 1);
|
|
1652
|
+
this.updateCalendar();
|
|
1653
|
+
}
|
|
1654
|
+
nextMonth() {
|
|
1655
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), this.displayMonth.getMonth() + 1, 1);
|
|
1656
|
+
this.updateCalendar();
|
|
1657
|
+
}
|
|
1658
|
+
onMonthChange(event) {
|
|
1659
|
+
const target = event.target;
|
|
1660
|
+
const nextMonth = Number(target.value);
|
|
1661
|
+
if (Number.isNaN(nextMonth)) {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
this.displayMonth = new Date(this.displayMonth.getFullYear(), nextMonth, 1);
|
|
1665
|
+
this.updateCalendar();
|
|
1666
|
+
}
|
|
1667
|
+
onYearChange(event) {
|
|
1668
|
+
const target = event.target;
|
|
1669
|
+
const nextYear = Number(target.value);
|
|
1670
|
+
if (Number.isNaN(nextYear)) {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
this.displayMonth = new Date(nextYear, this.displayMonth.getMonth(), 1);
|
|
1674
|
+
this.updateCalendar();
|
|
1675
|
+
}
|
|
1676
|
+
dayButtonClass(day) {
|
|
1677
|
+
return [
|
|
1678
|
+
DAY_BUTTON_BASE,
|
|
1679
|
+
day.inMonth ? '' : DAY_OUTSIDE_MONTH,
|
|
1680
|
+
day.isToday ? DAY_TODAY : '',
|
|
1681
|
+
this.isSelected(day.date) ? DAY_SELECTED : DAY_HOVER
|
|
1682
|
+
]
|
|
1683
|
+
.filter(Boolean)
|
|
1684
|
+
.join(' ');
|
|
1685
|
+
}
|
|
1686
|
+
onDocumentClick(event) {
|
|
1687
|
+
if (this.useNative || !this.isOpen) {
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
const target = event.target;
|
|
1691
|
+
if (target && !target.closest(`#${this.panelId}`) && !target.closest(`[data-cxs-datepicker="${this.panelId}"]`)) {
|
|
1692
|
+
this.isOpen = false;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
onEscape() {
|
|
1696
|
+
if (this.useNative || !this.isOpen) {
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
this.isOpen = false;
|
|
1700
|
+
}
|
|
1701
|
+
syncDisplayMonthWithValue() {
|
|
1702
|
+
const selected = this.parseDate(this.value);
|
|
1703
|
+
this.displayMonth = selected ?? new Date();
|
|
1704
|
+
this.updateCalendar();
|
|
1705
|
+
}
|
|
1706
|
+
updateCalendar() {
|
|
1707
|
+
const year = this.displayMonth.getFullYear();
|
|
1708
|
+
const month = this.displayMonth.getMonth();
|
|
1709
|
+
const startOfMonth = new Date(year, month, 1);
|
|
1710
|
+
const startDay = startOfMonth.getDay();
|
|
1711
|
+
const calendarStart = new Date(year, month, 1 - startDay);
|
|
1712
|
+
const minDate = this.parseDate(this.min);
|
|
1713
|
+
const maxDate = this.parseDate(this.max);
|
|
1714
|
+
const today = this.stripTime(new Date());
|
|
1715
|
+
this.calendarDays = Array.from({ length: 42 }, (_, index) => {
|
|
1716
|
+
const date = new Date(calendarStart.getFullYear(), calendarStart.getMonth(), calendarStart.getDate() + index);
|
|
1717
|
+
const dayValue = this.stripTime(date);
|
|
1718
|
+
const disabled = (minDate && dayValue < minDate) || (maxDate && dayValue > maxDate) || this.isDisabled;
|
|
1719
|
+
return {
|
|
1720
|
+
date,
|
|
1721
|
+
label: String(date.getDate()),
|
|
1722
|
+
inMonth: date.getMonth() === month,
|
|
1723
|
+
disabled,
|
|
1724
|
+
isToday: dayValue.getTime() === today.getTime(),
|
|
1725
|
+
key: this.formatDate(date)
|
|
1726
|
+
};
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
isSelected(date) {
|
|
1730
|
+
const selected = this.parseDate(this.value);
|
|
1731
|
+
if (!selected) {
|
|
1732
|
+
return false;
|
|
1733
|
+
}
|
|
1734
|
+
return (selected.getFullYear() === date.getFullYear() &&
|
|
1735
|
+
selected.getMonth() === date.getMonth() &&
|
|
1736
|
+
selected.getDate() === date.getDate());
|
|
1737
|
+
}
|
|
1738
|
+
parseDate(value) {
|
|
1739
|
+
if (!value) {
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
const [year, month, day] = value.split('-').map(Number);
|
|
1743
|
+
if (!year || !month || !day) {
|
|
1744
|
+
return null;
|
|
1745
|
+
}
|
|
1746
|
+
return new Date(year, month - 1, day);
|
|
1747
|
+
}
|
|
1748
|
+
formatDate(date) {
|
|
1749
|
+
const year = date.getFullYear();
|
|
1750
|
+
const month = `${date.getMonth() + 1}`.padStart(2, '0');
|
|
1751
|
+
const day = `${date.getDate()}`.padStart(2, '0');
|
|
1752
|
+
return `${year}-${month}-${day}`;
|
|
1753
|
+
}
|
|
1754
|
+
stripTime(date) {
|
|
1755
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
1756
|
+
}
|
|
1757
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1758
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDatepickerComponent, isStandalone: true, selector: "cxs-datepicker", inputs: { value: "value", variant: "variant", size: "size", useNative: "useNative", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", id: "id", name: "name", min: "min", max: "max", placeholder: "placeholder", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, providers: [
|
|
1759
|
+
{
|
|
1760
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1761
|
+
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
1762
|
+
multi: true
|
|
1763
|
+
}
|
|
1764
|
+
], 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 });
|
|
1765
|
+
}
|
|
1766
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, decorators: [{
|
|
1767
|
+
type: Component,
|
|
1768
|
+
args: [{ selector: 'cxs-datepicker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1769
|
+
{
|
|
1770
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1771
|
+
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
1772
|
+
multi: true
|
|
1773
|
+
}
|
|
1774
|
+
], 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" }]
|
|
1775
|
+
}], propDecorators: { value: [{
|
|
1776
|
+
type: Input
|
|
1777
|
+
}], variant: [{
|
|
1778
|
+
type: Input
|
|
1779
|
+
}], size: [{
|
|
1780
|
+
type: Input
|
|
1781
|
+
}], useNative: [{
|
|
1782
|
+
type: Input
|
|
1783
|
+
}], disabled: [{
|
|
1784
|
+
type: Input
|
|
1785
|
+
}], readonly: [{
|
|
1786
|
+
type: Input
|
|
1787
|
+
}], required: [{
|
|
1788
|
+
type: Input
|
|
1789
|
+
}], invalid: [{
|
|
1790
|
+
type: Input
|
|
1791
|
+
}], autofocus: [{
|
|
1792
|
+
type: Input
|
|
1793
|
+
}], id: [{
|
|
1794
|
+
type: Input
|
|
1795
|
+
}], name: [{
|
|
1796
|
+
type: Input
|
|
1797
|
+
}], min: [{
|
|
1798
|
+
type: Input
|
|
1799
|
+
}], max: [{
|
|
59
1800
|
type: Input
|
|
60
|
-
}],
|
|
1801
|
+
}], placeholder: [{
|
|
61
1802
|
type: Input
|
|
62
|
-
}],
|
|
1803
|
+
}], ariaLabel: [{
|
|
63
1804
|
type: Input
|
|
64
|
-
}],
|
|
1805
|
+
}], ariaDescribedby: [{
|
|
65
1806
|
type: Input
|
|
1807
|
+
}], valueChange: [{
|
|
1808
|
+
type: Output
|
|
1809
|
+
}], onDocumentClick: [{
|
|
1810
|
+
type: HostListener,
|
|
1811
|
+
args: ['document:click', ['$event']]
|
|
1812
|
+
}], onEscape: [{
|
|
1813
|
+
type: HostListener,
|
|
1814
|
+
args: ['document:keydown.escape']
|
|
66
1815
|
}] } });
|
|
67
1816
|
|
|
68
|
-
const BASE_CLASSES$
|
|
1817
|
+
const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
69
1818
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
70
1819
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
71
1820
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
72
1821
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
73
1822
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
74
|
-
const VARIANT_CLASSES$
|
|
1823
|
+
const VARIANT_CLASSES$2 = {
|
|
75
1824
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
76
1825
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
77
1826
|
};
|
|
@@ -109,9 +1858,9 @@ class CxsInputComponent {
|
|
|
109
1858
|
}
|
|
110
1859
|
get inputClass() {
|
|
111
1860
|
return [
|
|
112
|
-
BASE_CLASSES$
|
|
1861
|
+
BASE_CLASSES$2,
|
|
113
1862
|
SIZE_CLASSES$1[this.size],
|
|
114
|
-
VARIANT_CLASSES$
|
|
1863
|
+
VARIANT_CLASSES$2[this.variant],
|
|
115
1864
|
this.invalid ? INVALID_CLASSES$2 : ''
|
|
116
1865
|
]
|
|
117
1866
|
.filter(Boolean)
|
|
@@ -146,7 +1895,7 @@ class CxsInputComponent {
|
|
|
146
1895
|
useExisting: forwardRef(() => CxsInputComponent),
|
|
147
1896
|
multi: true
|
|
148
1897
|
}
|
|
149
|
-
], 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 });
|
|
1898
|
+
], 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 });
|
|
150
1899
|
}
|
|
151
1900
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, decorators: [{
|
|
152
1901
|
type: Component,
|
|
@@ -156,7 +1905,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
156
1905
|
useExisting: forwardRef(() => CxsInputComponent),
|
|
157
1906
|
multi: true
|
|
158
1907
|
}
|
|
159
|
-
], 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" }]
|
|
1908
|
+
], 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" }]
|
|
160
1909
|
}], propDecorators: { value: [{
|
|
161
1910
|
type: Input
|
|
162
1911
|
}], type: [{
|
|
@@ -195,6 +1944,147 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
195
1944
|
type: Output
|
|
196
1945
|
}] } });
|
|
197
1946
|
|
|
1947
|
+
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';
|
|
1948
|
+
const BAR_SIZE_CLASSES = {
|
|
1949
|
+
sm: 'text-xs',
|
|
1950
|
+
md: 'text-sm',
|
|
1951
|
+
lg: 'text-base'
|
|
1952
|
+
};
|
|
1953
|
+
const BAR_VARIANT_CLASSES = {
|
|
1954
|
+
default: 'bg-transparent',
|
|
1955
|
+
surface: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)] shadow-[var(--cxs-shadow-sm)]'
|
|
1956
|
+
};
|
|
1957
|
+
const ITEM_BASE_CLASSES = 'inline-flex items-center gap-2 rounded-[var(--cxs-radius-md)] px-3 py-1.5 font-medium ' +
|
|
1958
|
+
'transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1959
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1960
|
+
const ITEM_SIZE_CLASSES = {
|
|
1961
|
+
sm: 'px-2.5 py-1 text-xs',
|
|
1962
|
+
md: 'px-3 py-1.5 text-sm',
|
|
1963
|
+
lg: 'px-4 py-2 text-base'
|
|
1964
|
+
};
|
|
1965
|
+
const ITEM_ACTIVE_CLASSES = 'bg-[var(--cxs-color-primary-ghost)] text-[var(--cxs-color-primary)]';
|
|
1966
|
+
const ITEM_INACTIVE_CLASSES = 'text-[var(--cxs-color-on-surface)] hover:bg-[var(--cxs-color-surface-hover)]';
|
|
1967
|
+
const ITEM_DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] opacity-60 pointer-events-none';
|
|
1968
|
+
class CxsMenubarComponent {
|
|
1969
|
+
hostClass;
|
|
1970
|
+
items = [];
|
|
1971
|
+
ariaLabel = 'Menubar';
|
|
1972
|
+
size = 'md';
|
|
1973
|
+
variant = 'default';
|
|
1974
|
+
disabled = false;
|
|
1975
|
+
itemSelected = new EventEmitter();
|
|
1976
|
+
menuItems;
|
|
1977
|
+
constructor(hostClass) {
|
|
1978
|
+
this.hostClass = hostClass;
|
|
1979
|
+
}
|
|
1980
|
+
get menubarClass() {
|
|
1981
|
+
return [
|
|
1982
|
+
BAR_BASE_CLASSES,
|
|
1983
|
+
BAR_SIZE_CLASSES[this.size],
|
|
1984
|
+
BAR_VARIANT_CLASSES[this.variant],
|
|
1985
|
+
this.hostClass
|
|
1986
|
+
]
|
|
1987
|
+
.filter(Boolean)
|
|
1988
|
+
.join(' ');
|
|
1989
|
+
}
|
|
1990
|
+
isItemDisabled(item) {
|
|
1991
|
+
return this.disabled || !!item.disabled;
|
|
1992
|
+
}
|
|
1993
|
+
getItemClass(item) {
|
|
1994
|
+
return [
|
|
1995
|
+
ITEM_BASE_CLASSES,
|
|
1996
|
+
ITEM_SIZE_CLASSES[this.size],
|
|
1997
|
+
item.active ? ITEM_ACTIVE_CLASSES : ITEM_INACTIVE_CLASSES,
|
|
1998
|
+
this.isItemDisabled(item) ? ITEM_DISABLED_CLASSES : ''
|
|
1999
|
+
]
|
|
2000
|
+
.filter(Boolean)
|
|
2001
|
+
.join(' ');
|
|
2002
|
+
}
|
|
2003
|
+
getItemHref(item) {
|
|
2004
|
+
if (item.href && !this.isItemDisabled(item)) {
|
|
2005
|
+
return item.href;
|
|
2006
|
+
}
|
|
2007
|
+
return null;
|
|
2008
|
+
}
|
|
2009
|
+
getItemRel(item) {
|
|
2010
|
+
if (item.target === '_blank') {
|
|
2011
|
+
return item.rel ?? 'noopener noreferrer';
|
|
2012
|
+
}
|
|
2013
|
+
return item.rel ?? null;
|
|
2014
|
+
}
|
|
2015
|
+
onItemClick(item, event) {
|
|
2016
|
+
if (this.isItemDisabled(item)) {
|
|
2017
|
+
event.preventDefault();
|
|
2018
|
+
event.stopPropagation();
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
this.itemSelected.emit(item);
|
|
2022
|
+
}
|
|
2023
|
+
onKeydown(event) {
|
|
2024
|
+
if (this.disabled) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
if (typeof document === 'undefined') {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
const keys = ['ArrowRight', 'ArrowLeft', 'Home', 'End'];
|
|
2031
|
+
if (!keys.includes(event.key)) {
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
const items = this.getFocusableItems();
|
|
2035
|
+
if (!items.length) {
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
const currentIndex = items.findIndex((item) => item === document.activeElement);
|
|
2039
|
+
let nextIndex = 0;
|
|
2040
|
+
switch (event.key) {
|
|
2041
|
+
case 'Home':
|
|
2042
|
+
nextIndex = 0;
|
|
2043
|
+
break;
|
|
2044
|
+
case 'End':
|
|
2045
|
+
nextIndex = items.length - 1;
|
|
2046
|
+
break;
|
|
2047
|
+
case 'ArrowRight':
|
|
2048
|
+
nextIndex = currentIndex >= 0 ? (currentIndex + 1) % items.length : 0;
|
|
2049
|
+
break;
|
|
2050
|
+
case 'ArrowLeft':
|
|
2051
|
+
nextIndex = currentIndex >= 0 ? (currentIndex - 1 + items.length) % items.length : items.length - 1;
|
|
2052
|
+
break;
|
|
2053
|
+
}
|
|
2054
|
+
items[nextIndex]?.focus();
|
|
2055
|
+
event.preventDefault();
|
|
2056
|
+
}
|
|
2057
|
+
getFocusableItems() {
|
|
2058
|
+
return (this.menuItems?.toArray() ?? [])
|
|
2059
|
+
.map((item) => item.nativeElement)
|
|
2060
|
+
.filter((item) => !item.hasAttribute('data-disabled'));
|
|
2061
|
+
}
|
|
2062
|
+
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 });
|
|
2063
|
+
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 });
|
|
2064
|
+
}
|
|
2065
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMenubarComponent, decorators: [{
|
|
2066
|
+
type: Component,
|
|
2067
|
+
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" }]
|
|
2068
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2069
|
+
type: Attribute,
|
|
2070
|
+
args: ['class']
|
|
2071
|
+
}] }], propDecorators: { items: [{
|
|
2072
|
+
type: Input
|
|
2073
|
+
}], ariaLabel: [{
|
|
2074
|
+
type: Input
|
|
2075
|
+
}], size: [{
|
|
2076
|
+
type: Input
|
|
2077
|
+
}], variant: [{
|
|
2078
|
+
type: Input
|
|
2079
|
+
}], disabled: [{
|
|
2080
|
+
type: Input
|
|
2081
|
+
}], itemSelected: [{
|
|
2082
|
+
type: Output
|
|
2083
|
+
}], menuItems: [{
|
|
2084
|
+
type: ViewChildren,
|
|
2085
|
+
args: ['menuItem', { read: ElementRef }]
|
|
2086
|
+
}] } });
|
|
2087
|
+
|
|
198
2088
|
const WRAPPER_BASE = 'inline-flex items-center gap-2 select-none';
|
|
199
2089
|
const WRAPPER_ENABLED = 'cursor-pointer';
|
|
200
2090
|
const WRAPPER_DISABLED = 'cursor-not-allowed opacity-60';
|
|
@@ -307,7 +2197,7 @@ class CxsRadioComponent {
|
|
|
307
2197
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
308
2198
|
multi: true
|
|
309
2199
|
}
|
|
310
|
-
], 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 });
|
|
2200
|
+
], 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 });
|
|
311
2201
|
}
|
|
312
2202
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsRadioComponent, decorators: [{
|
|
313
2203
|
type: Component,
|
|
@@ -317,7 +2207,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
317
2207
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
318
2208
|
multi: true
|
|
319
2209
|
}
|
|
320
|
-
], 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" }]
|
|
2210
|
+
], 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" }]
|
|
321
2211
|
}], propDecorators: { value: [{
|
|
322
2212
|
type: Input
|
|
323
2213
|
}], name: [{
|
|
@@ -344,13 +2234,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
344
2234
|
type: Output
|
|
345
2235
|
}] } });
|
|
346
2236
|
|
|
347
|
-
const BASE_CLASSES = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
2237
|
+
const BASE_CLASSES$1 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
348
2238
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
349
2239
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
350
2240
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
351
2241
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
352
2242
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
353
|
-
const VARIANT_CLASSES = {
|
|
2243
|
+
const VARIANT_CLASSES$1 = {
|
|
354
2244
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
355
2245
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
356
2246
|
};
|
|
@@ -383,9 +2273,9 @@ class CxsSelectComponent {
|
|
|
383
2273
|
}
|
|
384
2274
|
get selectClass() {
|
|
385
2275
|
return [
|
|
386
|
-
BASE_CLASSES,
|
|
2276
|
+
BASE_CLASSES$1,
|
|
387
2277
|
SIZE_CLASSES[this.size],
|
|
388
|
-
VARIANT_CLASSES[this.variant],
|
|
2278
|
+
VARIANT_CLASSES$1[this.variant],
|
|
389
2279
|
this.invalid ? INVALID_CLASSES : ''
|
|
390
2280
|
]
|
|
391
2281
|
.filter(Boolean)
|
|
@@ -426,7 +2316,7 @@ class CxsSelectComponent {
|
|
|
426
2316
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
427
2317
|
multi: true
|
|
428
2318
|
}
|
|
429
|
-
], 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 });
|
|
2319
|
+
], 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 });
|
|
430
2320
|
}
|
|
431
2321
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, decorators: [{
|
|
432
2322
|
type: Component,
|
|
@@ -436,7 +2326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
436
2326
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
437
2327
|
multi: true
|
|
438
2328
|
}
|
|
439
|
-
], 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" }]
|
|
2329
|
+
], 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" }]
|
|
440
2330
|
}], propDecorators: { value: [{
|
|
441
2331
|
type: Input
|
|
442
2332
|
}], variant: [{
|
|
@@ -465,6 +2355,545 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
465
2355
|
type: Output
|
|
466
2356
|
}] } });
|
|
467
2357
|
|
|
2358
|
+
const WRAPPER_BASE_CLASSES = 'w-full overflow-hidden';
|
|
2359
|
+
const WRAPPER_BORDERED_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
|
|
2360
|
+
const TABLE_BASE_CLASSES = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
|
|
2361
|
+
const TABLE_COMPACT_CLASSES = 'text-xs';
|
|
2362
|
+
const HEADER_ROW_CLASSES = 'border-b border-[var(--cxs-color-border)] text-xs uppercase tracking-[0.2em] ' +
|
|
2363
|
+
'text-[var(--cxs-color-on-surface-muted)]';
|
|
2364
|
+
const HEADER_CELL_BASE_CLASSES = 'px-3 py-2 text-left font-semibold';
|
|
2365
|
+
const BODY_ROW_BASE_CLASSES = 'border-b border-[var(--cxs-color-border)] last:border-b-0';
|
|
2366
|
+
const BODY_ROW_STRIPED_CLASSES = 'odd:bg-[var(--cxs-color-surface)] even:bg-[var(--cxs-color-surface-hover)]';
|
|
2367
|
+
const BODY_CELL_BASE_CLASSES = 'px-3 py-2 align-top';
|
|
2368
|
+
const BODY_CELL_COMPACT_CLASSES = 'px-2 py-1.5';
|
|
2369
|
+
const ALIGN_CLASSES = {
|
|
2370
|
+
left: 'text-left',
|
|
2371
|
+
center: 'text-center',
|
|
2372
|
+
right: 'text-right'
|
|
2373
|
+
};
|
|
2374
|
+
const EMPTY_ROW_CLASSES = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
2375
|
+
class CxsTableComponent {
|
|
2376
|
+
hostClass;
|
|
2377
|
+
columns = [];
|
|
2378
|
+
data = [];
|
|
2379
|
+
caption;
|
|
2380
|
+
ariaLabel = 'Table';
|
|
2381
|
+
striped = false;
|
|
2382
|
+
bordered = false;
|
|
2383
|
+
compact = false;
|
|
2384
|
+
emptyMessage = 'No data available';
|
|
2385
|
+
emptyCell = '—';
|
|
2386
|
+
constructor(hostClass) {
|
|
2387
|
+
this.hostClass = hostClass;
|
|
2388
|
+
}
|
|
2389
|
+
get wrapperClass() {
|
|
2390
|
+
return [
|
|
2391
|
+
WRAPPER_BASE_CLASSES,
|
|
2392
|
+
this.bordered ? WRAPPER_BORDERED_CLASSES : '',
|
|
2393
|
+
this.hostClass
|
|
2394
|
+
]
|
|
2395
|
+
.filter(Boolean)
|
|
2396
|
+
.join(' ');
|
|
2397
|
+
}
|
|
2398
|
+
get tableClass() {
|
|
2399
|
+
return [TABLE_BASE_CLASSES, this.compact ? TABLE_COMPACT_CLASSES : '']
|
|
2400
|
+
.filter(Boolean)
|
|
2401
|
+
.join(' ');
|
|
2402
|
+
}
|
|
2403
|
+
get headerRowClass() {
|
|
2404
|
+
return HEADER_ROW_CLASSES;
|
|
2405
|
+
}
|
|
2406
|
+
get bodyRowClass() {
|
|
2407
|
+
return [
|
|
2408
|
+
BODY_ROW_BASE_CLASSES,
|
|
2409
|
+
this.striped ? BODY_ROW_STRIPED_CLASSES : ''
|
|
2410
|
+
]
|
|
2411
|
+
.filter(Boolean)
|
|
2412
|
+
.join(' ');
|
|
2413
|
+
}
|
|
2414
|
+
get emptyRowClass() {
|
|
2415
|
+
return EMPTY_ROW_CLASSES;
|
|
2416
|
+
}
|
|
2417
|
+
get colSpan() {
|
|
2418
|
+
return Math.max(this.columns.length, 1);
|
|
2419
|
+
}
|
|
2420
|
+
headerCellClass(column) {
|
|
2421
|
+
return [
|
|
2422
|
+
HEADER_CELL_BASE_CLASSES,
|
|
2423
|
+
ALIGN_CLASSES[column.align ?? 'left'],
|
|
2424
|
+
column.headerClass ?? ''
|
|
2425
|
+
]
|
|
2426
|
+
.filter(Boolean)
|
|
2427
|
+
.join(' ');
|
|
2428
|
+
}
|
|
2429
|
+
bodyCellClass(column) {
|
|
2430
|
+
return [
|
|
2431
|
+
BODY_CELL_BASE_CLASSES,
|
|
2432
|
+
this.compact ? BODY_CELL_COMPACT_CLASSES : '',
|
|
2433
|
+
ALIGN_CLASSES[column.align ?? 'left'],
|
|
2434
|
+
column.cellClass ?? ''
|
|
2435
|
+
]
|
|
2436
|
+
.filter(Boolean)
|
|
2437
|
+
.join(' ');
|
|
2438
|
+
}
|
|
2439
|
+
cellValue(row, column) {
|
|
2440
|
+
const value = row[column.key];
|
|
2441
|
+
if (value === null || value === undefined || value === '') {
|
|
2442
|
+
return this.emptyCell;
|
|
2443
|
+
}
|
|
2444
|
+
return String(value);
|
|
2445
|
+
}
|
|
2446
|
+
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 });
|
|
2447
|
+
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 });
|
|
2448
|
+
}
|
|
2449
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTableComponent, decorators: [{
|
|
2450
|
+
type: Component,
|
|
2451
|
+
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" }]
|
|
2452
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2453
|
+
type: Attribute,
|
|
2454
|
+
args: ['class']
|
|
2455
|
+
}] }], propDecorators: { columns: [{
|
|
2456
|
+
type: Input
|
|
2457
|
+
}], data: [{
|
|
2458
|
+
type: Input
|
|
2459
|
+
}], caption: [{
|
|
2460
|
+
type: Input
|
|
2461
|
+
}], ariaLabel: [{
|
|
2462
|
+
type: Input
|
|
2463
|
+
}], striped: [{
|
|
2464
|
+
type: Input
|
|
2465
|
+
}], bordered: [{
|
|
2466
|
+
type: Input
|
|
2467
|
+
}], compact: [{
|
|
2468
|
+
type: Input
|
|
2469
|
+
}], emptyMessage: [{
|
|
2470
|
+
type: Input
|
|
2471
|
+
}], emptyCell: [{
|
|
2472
|
+
type: Input
|
|
2473
|
+
}] } });
|
|
2474
|
+
|
|
2475
|
+
const WRAPPER_CLASSES$1 = 'inline-flex items-center gap-2';
|
|
2476
|
+
const LABEL_BASE_CLASSES = 'text-sm text-[var(--cxs-color-on-surface)] select-none';
|
|
2477
|
+
const LABEL_DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)]';
|
|
2478
|
+
const TRACK_BASE_CLASSES = 'relative inline-flex items-center rounded-full border transition-colors ' +
|
|
2479
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
2480
|
+
'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-60';
|
|
2481
|
+
const TRACK_SIZE_CLASSES = {
|
|
2482
|
+
sm: 'h-5 w-9 p-0.5',
|
|
2483
|
+
md: 'h-6 w-11 p-0.5',
|
|
2484
|
+
lg: 'h-8 w-14 p-0.5'
|
|
2485
|
+
};
|
|
2486
|
+
const TRACK_STATE_CLASSES = {
|
|
2487
|
+
on: 'bg-[var(--cxs-color-primary)] border-[var(--cxs-color-primary)]',
|
|
2488
|
+
off: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)]'
|
|
2489
|
+
};
|
|
2490
|
+
const THUMB_BASE_CLASSES = 'absolute left-0.5 top-0.5 rounded-full transition-transform duration-200 ease-out';
|
|
2491
|
+
const THUMB_SIZE_CLASSES = {
|
|
2492
|
+
sm: 'h-4 w-4',
|
|
2493
|
+
md: 'h-5 w-5',
|
|
2494
|
+
lg: 'h-7 w-7'
|
|
2495
|
+
};
|
|
2496
|
+
const THUMB_STATE_CLASSES = {
|
|
2497
|
+
on: {
|
|
2498
|
+
sm: 'translate-x-[18px] bg-[var(--cxs-color-on-primary)]',
|
|
2499
|
+
md: 'translate-x-[22px] bg-[var(--cxs-color-on-primary)]',
|
|
2500
|
+
lg: 'translate-x-[26px] bg-[var(--cxs-color-on-primary)]'
|
|
2501
|
+
},
|
|
2502
|
+
off: 'translate-x-0 bg-[var(--cxs-color-surface)]'
|
|
2503
|
+
};
|
|
2504
|
+
class CxsToggleComponent {
|
|
2505
|
+
static nextId = 0;
|
|
2506
|
+
checked = false;
|
|
2507
|
+
disabled = false;
|
|
2508
|
+
size = 'md';
|
|
2509
|
+
label;
|
|
2510
|
+
ariaLabel = 'Toggle';
|
|
2511
|
+
checkedChange = new EventEmitter();
|
|
2512
|
+
labelId = `cxs-toggle-label-${CxsToggleComponent.nextId++}`;
|
|
2513
|
+
get wrapperClass() {
|
|
2514
|
+
return WRAPPER_CLASSES$1;
|
|
2515
|
+
}
|
|
2516
|
+
get labelClass() {
|
|
2517
|
+
return [LABEL_BASE_CLASSES, this.disabled ? LABEL_DISABLED_CLASSES : '']
|
|
2518
|
+
.filter(Boolean)
|
|
2519
|
+
.join(' ');
|
|
2520
|
+
}
|
|
2521
|
+
get trackClass() {
|
|
2522
|
+
return [
|
|
2523
|
+
TRACK_BASE_CLASSES,
|
|
2524
|
+
TRACK_SIZE_CLASSES[this.size],
|
|
2525
|
+
this.checked ? TRACK_STATE_CLASSES.on : TRACK_STATE_CLASSES.off
|
|
2526
|
+
].join(' ');
|
|
2527
|
+
}
|
|
2528
|
+
get thumbClass() {
|
|
2529
|
+
const thumbState = this.checked
|
|
2530
|
+
? THUMB_STATE_CLASSES.on[this.size]
|
|
2531
|
+
: THUMB_STATE_CLASSES.off;
|
|
2532
|
+
return [THUMB_BASE_CLASSES, THUMB_SIZE_CLASSES[this.size], thumbState].join(' ');
|
|
2533
|
+
}
|
|
2534
|
+
get ariaLabelValue() {
|
|
2535
|
+
if (this.label) {
|
|
2536
|
+
return null;
|
|
2537
|
+
}
|
|
2538
|
+
return this.ariaLabel;
|
|
2539
|
+
}
|
|
2540
|
+
toggle() {
|
|
2541
|
+
if (this.disabled) {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
this.checkedChange.emit(!this.checked);
|
|
2545
|
+
}
|
|
2546
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2547
|
+
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 });
|
|
2548
|
+
}
|
|
2549
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToggleComponent, decorators: [{
|
|
2550
|
+
type: Component,
|
|
2551
|
+
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" }]
|
|
2552
|
+
}], propDecorators: { checked: [{
|
|
2553
|
+
type: Input
|
|
2554
|
+
}], disabled: [{
|
|
2555
|
+
type: Input
|
|
2556
|
+
}], size: [{
|
|
2557
|
+
type: Input
|
|
2558
|
+
}], label: [{
|
|
2559
|
+
type: Input
|
|
2560
|
+
}], ariaLabel: [{
|
|
2561
|
+
type: Input
|
|
2562
|
+
}], checkedChange: [{
|
|
2563
|
+
type: Output
|
|
2564
|
+
}] } });
|
|
2565
|
+
|
|
2566
|
+
const HOST_BASE_CLASSES = 'pointer-events-none';
|
|
2567
|
+
const POSITION_CLASSES = {
|
|
2568
|
+
'bottom-right': 'fixed bottom-6 right-6 items-end',
|
|
2569
|
+
bottom: 'fixed bottom-6 left-1/2 -translate-x-1/2 items-end',
|
|
2570
|
+
'bottom-left': 'fixed bottom-6 left-6 items-start',
|
|
2571
|
+
'top-right': 'fixed top-6 right-6 items-end',
|
|
2572
|
+
top: 'fixed top-6 left-1/2 -translate-x-1/2 items-start',
|
|
2573
|
+
'top-left': 'fixed top-6 left-6 items-start',
|
|
2574
|
+
right: 'fixed right-6 top-1/2 -translate-y-1/2 items-end',
|
|
2575
|
+
left: 'fixed left-6 top-1/2 -translate-y-1/2 items-start',
|
|
2576
|
+
center: 'fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 items-center'
|
|
2577
|
+
};
|
|
2578
|
+
const BASE_CLASSES = 'pointer-events-auto flex w-full items-start gap-3 rounded-[var(--cxs-radius-md)] ' +
|
|
2579
|
+
'border px-4 py-3 shadow-[var(--cxs-shadow-sm)]';
|
|
2580
|
+
const WIDTH_CLASSES = {
|
|
2581
|
+
sm: 'max-w-sm',
|
|
2582
|
+
md: 'max-w-md',
|
|
2583
|
+
lg: 'max-w-lg',
|
|
2584
|
+
xl: 'max-w-xl',
|
|
2585
|
+
none: 'max-w-none'
|
|
2586
|
+
};
|
|
2587
|
+
const VARIANT_CLASSES = {
|
|
2588
|
+
info: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
|
|
2589
|
+
'text-[var(--cxs-color-on-surface)]',
|
|
2590
|
+
neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
2591
|
+
'text-[var(--cxs-color-on-surface)]',
|
|
2592
|
+
danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
|
|
2593
|
+
'text-[var(--cxs-color-on-surface)]'
|
|
2594
|
+
};
|
|
2595
|
+
const TITLE_CLASSES = 'text-sm font-semibold';
|
|
2596
|
+
const MESSAGE_CLASSES = 'mt-1 text-sm text-[var(--cxs-color-on-surface-muted)]';
|
|
2597
|
+
const ACTIONS_CLASSES = 'mt-3 flex flex-wrap items-center gap-2 empty:hidden';
|
|
2598
|
+
const CLOSE_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
2599
|
+
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
2600
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
2601
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
2602
|
+
class CxsToastComponent {
|
|
2603
|
+
hostClass;
|
|
2604
|
+
open = false;
|
|
2605
|
+
title;
|
|
2606
|
+
message;
|
|
2607
|
+
ariaLabel = 'Notification';
|
|
2608
|
+
variant = 'info';
|
|
2609
|
+
dismissible = true;
|
|
2610
|
+
duration = 0;
|
|
2611
|
+
position = 'bottom-right';
|
|
2612
|
+
maxWidth = 'sm';
|
|
2613
|
+
openChange = new EventEmitter();
|
|
2614
|
+
dismissed = new EventEmitter();
|
|
2615
|
+
timeoutId = null;
|
|
2616
|
+
constructor(hostClass) {
|
|
2617
|
+
this.hostClass = hostClass;
|
|
2618
|
+
}
|
|
2619
|
+
ngOnChanges(changes) {
|
|
2620
|
+
if (changes['open'] || changes['duration']) {
|
|
2621
|
+
this.resetTimer();
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
ngOnDestroy() {
|
|
2625
|
+
this.clearTimer();
|
|
2626
|
+
}
|
|
2627
|
+
get hostClassName() {
|
|
2628
|
+
return [HOST_BASE_CLASSES, POSITION_CLASSES[this.position]].join(' ');
|
|
2629
|
+
}
|
|
2630
|
+
get toastClass() {
|
|
2631
|
+
return [
|
|
2632
|
+
BASE_CLASSES,
|
|
2633
|
+
WIDTH_CLASSES[this.maxWidth],
|
|
2634
|
+
VARIANT_CLASSES[this.variant],
|
|
2635
|
+
this.hostClass
|
|
2636
|
+
]
|
|
2637
|
+
.filter(Boolean)
|
|
2638
|
+
.join(' ');
|
|
2639
|
+
}
|
|
2640
|
+
get titleClass() {
|
|
2641
|
+
return TITLE_CLASSES;
|
|
2642
|
+
}
|
|
2643
|
+
get messageClass() {
|
|
2644
|
+
return MESSAGE_CLASSES;
|
|
2645
|
+
}
|
|
2646
|
+
get actionsClass() {
|
|
2647
|
+
return ACTIONS_CLASSES;
|
|
2648
|
+
}
|
|
2649
|
+
get closeButtonClass() {
|
|
2650
|
+
return CLOSE_BUTTON_CLASSES;
|
|
2651
|
+
}
|
|
2652
|
+
get role() {
|
|
2653
|
+
return this.variant === 'danger' ? 'alert' : 'status';
|
|
2654
|
+
}
|
|
2655
|
+
get ariaLive() {
|
|
2656
|
+
return this.variant === 'danger' ? 'assertive' : 'polite';
|
|
2657
|
+
}
|
|
2658
|
+
get ariaLabelValue() {
|
|
2659
|
+
if (this.title) {
|
|
2660
|
+
return null;
|
|
2661
|
+
}
|
|
2662
|
+
return this.ariaLabel;
|
|
2663
|
+
}
|
|
2664
|
+
requestClose(reason) {
|
|
2665
|
+
this.openChange.emit(false);
|
|
2666
|
+
this.dismissed.emit(reason);
|
|
2667
|
+
}
|
|
2668
|
+
resetTimer() {
|
|
2669
|
+
this.clearTimer();
|
|
2670
|
+
if (this.open && this.duration > 0) {
|
|
2671
|
+
this.timeoutId = setTimeout(() => {
|
|
2672
|
+
this.requestClose('timeout');
|
|
2673
|
+
}, this.duration);
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
clearTimer() {
|
|
2677
|
+
if (this.timeoutId) {
|
|
2678
|
+
clearTimeout(this.timeoutId);
|
|
2679
|
+
this.timeoutId = null;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
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 });
|
|
2683
|
+
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 });
|
|
2684
|
+
}
|
|
2685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, decorators: [{
|
|
2686
|
+
type: Component,
|
|
2687
|
+
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" }]
|
|
2688
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2689
|
+
type: Attribute,
|
|
2690
|
+
args: ['class']
|
|
2691
|
+
}] }], propDecorators: { open: [{
|
|
2692
|
+
type: Input
|
|
2693
|
+
}], title: [{
|
|
2694
|
+
type: Input
|
|
2695
|
+
}], message: [{
|
|
2696
|
+
type: Input
|
|
2697
|
+
}], ariaLabel: [{
|
|
2698
|
+
type: Input
|
|
2699
|
+
}], variant: [{
|
|
2700
|
+
type: Input
|
|
2701
|
+
}], dismissible: [{
|
|
2702
|
+
type: Input
|
|
2703
|
+
}], duration: [{
|
|
2704
|
+
type: Input
|
|
2705
|
+
}], position: [{
|
|
2706
|
+
type: Input
|
|
2707
|
+
}], maxWidth: [{
|
|
2708
|
+
type: Input
|
|
2709
|
+
}], openChange: [{
|
|
2710
|
+
type: Output
|
|
2711
|
+
}], dismissed: [{
|
|
2712
|
+
type: Output
|
|
2713
|
+
}] } });
|
|
2714
|
+
|
|
2715
|
+
const WRAPPER_CLASSES = 'relative inline-flex';
|
|
2716
|
+
const TOOLTIP_BASE_CLASSES = 'pointer-events-none absolute z-50 max-w-xs rounded-[var(--cxs-radius-md)] px-2 py-1 text-xs ' +
|
|
2717
|
+
'text-[var(--cxs-color-on-primary)] bg-[var(--cxs-color-on-surface)] shadow-[var(--cxs-shadow-sm)]';
|
|
2718
|
+
const TOOLTIP_POSITION_CLASSES = {
|
|
2719
|
+
top: 'bottom-full left-1/2 mb-2 -translate-x-1/2',
|
|
2720
|
+
right: 'left-full top-1/2 ml-2 -translate-y-1/2',
|
|
2721
|
+
bottom: 'top-full left-1/2 mt-2 -translate-x-1/2',
|
|
2722
|
+
left: 'right-full top-1/2 mr-2 -translate-y-1/2'
|
|
2723
|
+
};
|
|
2724
|
+
class CxsTooltipComponent {
|
|
2725
|
+
static nextId = 0;
|
|
2726
|
+
text = '';
|
|
2727
|
+
position = 'top';
|
|
2728
|
+
disabled = false;
|
|
2729
|
+
open = false;
|
|
2730
|
+
tooltipId = `cxs-tooltip-${CxsTooltipComponent.nextId++}`;
|
|
2731
|
+
get wrapperClass() {
|
|
2732
|
+
return WRAPPER_CLASSES;
|
|
2733
|
+
}
|
|
2734
|
+
get tooltipClass() {
|
|
2735
|
+
return [TOOLTIP_BASE_CLASSES, TOOLTIP_POSITION_CLASSES[this.position]].join(' ');
|
|
2736
|
+
}
|
|
2737
|
+
get describedBy() {
|
|
2738
|
+
if (!this.text || this.disabled) {
|
|
2739
|
+
return null;
|
|
2740
|
+
}
|
|
2741
|
+
return this.tooltipId;
|
|
2742
|
+
}
|
|
2743
|
+
show() {
|
|
2744
|
+
if (this.disabled || !this.text) {
|
|
2745
|
+
return;
|
|
2746
|
+
}
|
|
2747
|
+
this.open = true;
|
|
2748
|
+
}
|
|
2749
|
+
hide() {
|
|
2750
|
+
this.open = false;
|
|
2751
|
+
}
|
|
2752
|
+
onMouseEnter() {
|
|
2753
|
+
this.show();
|
|
2754
|
+
}
|
|
2755
|
+
onMouseLeave() {
|
|
2756
|
+
this.hide();
|
|
2757
|
+
}
|
|
2758
|
+
onFocusIn() {
|
|
2759
|
+
this.show();
|
|
2760
|
+
}
|
|
2761
|
+
onFocusOut() {
|
|
2762
|
+
this.hide();
|
|
2763
|
+
}
|
|
2764
|
+
onKeydown(event) {
|
|
2765
|
+
if (event.key === 'Escape') {
|
|
2766
|
+
this.hide();
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2770
|
+
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 });
|
|
2771
|
+
}
|
|
2772
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTooltipComponent, decorators: [{
|
|
2773
|
+
type: Component,
|
|
2774
|
+
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" }]
|
|
2775
|
+
}], propDecorators: { text: [{
|
|
2776
|
+
type: Input
|
|
2777
|
+
}], position: [{
|
|
2778
|
+
type: Input
|
|
2779
|
+
}], disabled: [{
|
|
2780
|
+
type: Input
|
|
2781
|
+
}], onMouseEnter: [{
|
|
2782
|
+
type: HostListener,
|
|
2783
|
+
args: ['mouseenter']
|
|
2784
|
+
}], onMouseLeave: [{
|
|
2785
|
+
type: HostListener,
|
|
2786
|
+
args: ['mouseleave']
|
|
2787
|
+
}], onFocusIn: [{
|
|
2788
|
+
type: HostListener,
|
|
2789
|
+
args: ['focusin']
|
|
2790
|
+
}], onFocusOut: [{
|
|
2791
|
+
type: HostListener,
|
|
2792
|
+
args: ['focusout']
|
|
2793
|
+
}], onKeydown: [{
|
|
2794
|
+
type: HostListener,
|
|
2795
|
+
args: ['keydown', ['$event']]
|
|
2796
|
+
}] } });
|
|
2797
|
+
|
|
2798
|
+
const DEFAULT_DARK_CLASS = 'cxs-theme-dark';
|
|
2799
|
+
class CxsThemeDirective {
|
|
2800
|
+
host;
|
|
2801
|
+
renderer;
|
|
2802
|
+
mode = 'light';
|
|
2803
|
+
darkClass = DEFAULT_DARK_CLASS;
|
|
2804
|
+
mediaQuery = null;
|
|
2805
|
+
mediaListener = null;
|
|
2806
|
+
constructor(host, renderer) {
|
|
2807
|
+
this.host = host;
|
|
2808
|
+
this.renderer = renderer;
|
|
2809
|
+
}
|
|
2810
|
+
set cxsTheme(value) {
|
|
2811
|
+
this.mode = value ?? 'light';
|
|
2812
|
+
this.applyTheme();
|
|
2813
|
+
}
|
|
2814
|
+
set cxsThemeDarkClass(value) {
|
|
2815
|
+
const nextClass = value?.trim() || DEFAULT_DARK_CLASS;
|
|
2816
|
+
if (nextClass === this.darkClass) {
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
const previousClass = this.darkClass;
|
|
2820
|
+
this.darkClass = nextClass;
|
|
2821
|
+
this.renderer.removeClass(this.host.nativeElement, previousClass);
|
|
2822
|
+
this.applyTheme();
|
|
2823
|
+
}
|
|
2824
|
+
ngOnDestroy() {
|
|
2825
|
+
this.detachMediaListener();
|
|
2826
|
+
}
|
|
2827
|
+
applyTheme() {
|
|
2828
|
+
if (this.mode === 'system') {
|
|
2829
|
+
this.attachMediaListener();
|
|
2830
|
+
}
|
|
2831
|
+
else {
|
|
2832
|
+
this.detachMediaListener();
|
|
2833
|
+
}
|
|
2834
|
+
const shouldEnableDark = this.mode === 'dark' || (this.mode === 'system' && this.prefersDark());
|
|
2835
|
+
if (shouldEnableDark) {
|
|
2836
|
+
this.renderer.addClass(this.host.nativeElement, this.darkClass);
|
|
2837
|
+
}
|
|
2838
|
+
else {
|
|
2839
|
+
this.renderer.removeClass(this.host.nativeElement, this.darkClass);
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
prefersDark() {
|
|
2843
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
if (!this.mediaQuery) {
|
|
2847
|
+
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
2848
|
+
}
|
|
2849
|
+
return this.mediaQuery.matches;
|
|
2850
|
+
}
|
|
2851
|
+
attachMediaListener() {
|
|
2852
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
if (!this.mediaQuery) {
|
|
2856
|
+
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
2857
|
+
}
|
|
2858
|
+
if (this.mediaListener) {
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2861
|
+
this.mediaListener = () => this.applyTheme();
|
|
2862
|
+
if (typeof this.mediaQuery.addEventListener === 'function') {
|
|
2863
|
+
this.mediaQuery.addEventListener('change', this.mediaListener);
|
|
2864
|
+
}
|
|
2865
|
+
else if (typeof this.mediaQuery.addListener === 'function') {
|
|
2866
|
+
this.mediaQuery.addListener(this.mediaListener);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
detachMediaListener() {
|
|
2870
|
+
if (!this.mediaQuery || !this.mediaListener) {
|
|
2871
|
+
this.mediaListener = null;
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
if (typeof this.mediaQuery.removeEventListener === 'function') {
|
|
2875
|
+
this.mediaQuery.removeEventListener('change', this.mediaListener);
|
|
2876
|
+
}
|
|
2877
|
+
else if (typeof this.mediaQuery.removeListener === 'function') {
|
|
2878
|
+
this.mediaQuery.removeListener(this.mediaListener);
|
|
2879
|
+
}
|
|
2880
|
+
this.mediaListener = null;
|
|
2881
|
+
}
|
|
2882
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsThemeDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2883
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: CxsThemeDirective, isStandalone: true, selector: "[cxsTheme]", inputs: { cxsTheme: "cxsTheme", cxsThemeDarkClass: "cxsThemeDarkClass" }, ngImport: i0 });
|
|
2884
|
+
}
|
|
2885
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsThemeDirective, decorators: [{
|
|
2886
|
+
type: Directive,
|
|
2887
|
+
args: [{
|
|
2888
|
+
selector: '[cxsTheme]',
|
|
2889
|
+
standalone: true
|
|
2890
|
+
}]
|
|
2891
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { cxsTheme: [{
|
|
2892
|
+
type: Input
|
|
2893
|
+
}], cxsThemeDarkClass: [{
|
|
2894
|
+
type: Input
|
|
2895
|
+
}] } });
|
|
2896
|
+
|
|
468
2897
|
/*
|
|
469
2898
|
* Public API Surface of cerxos-ui
|
|
470
2899
|
*/
|
|
@@ -473,5 +2902,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
473
2902
|
* Generated bundle index. Do not edit.
|
|
474
2903
|
*/
|
|
475
2904
|
|
|
476
|
-
export { CerxosUi, CxsButtonComponent, CxsInputComponent, CxsRadioComponent, CxsSelectComponent };
|
|
2905
|
+
export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsDataTableComponent, CxsDatepickerComponent, CxsDialogComponent, CxsInputComponent, CxsMenubarComponent, CxsRadioComponent, CxsSelectComponent, CxsTableComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
|
|
477
2906
|
//# sourceMappingURL=cerxos-ui.mjs.map
|