cerxos-ui 0.0.3 → 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 +1917 -238
- package/fesm2022/cerxos-ui.mjs.map +1 -1
- package/index.d.ts +439 -4
- package/package.json +1 -1
- package/styles/tailwind.css +3 -3
- package/tokens/theme-dark.css +16 -16
- package/tokens/theme-default.css +15 -15
package/fesm2022/cerxos-ui.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, HostListener, Directive } from '@angular/core';
|
|
2
|
+
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, ViewChild, HostListener, ElementRef, ViewChildren, Directive } from '@angular/core';
|
|
3
3
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
4
|
import { NgIf } from '@angular/common';
|
|
5
5
|
|
|
@@ -20,9 +20,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
20
20
|
` }]
|
|
21
21
|
}] });
|
|
22
22
|
|
|
23
|
-
const BASE_CLASSES$
|
|
23
|
+
const BASE_CLASSES$a = 'relative flex w-full gap-3 rounded-[var(--cxs-radius-md)] border border-l-4 px-4 py-3 text-sm ' +
|
|
24
24
|
'text-[var(--cxs-color-on-surface)]';
|
|
25
|
-
const VARIANT_CLASSES$
|
|
25
|
+
const VARIANT_CLASSES$7 = {
|
|
26
26
|
info: 'border-[var(--cxs-color-primary)] border-l-[var(--cxs-color-primary)] ' +
|
|
27
27
|
'bg-[var(--cxs-color-primary-ghost)]',
|
|
28
28
|
neutral: 'border-[var(--cxs-color-border)] border-l-[var(--cxs-color-border)] ' +
|
|
@@ -36,7 +36,7 @@ const TITLE_VARIANT = {
|
|
|
36
36
|
neutral: 'text-[var(--cxs-color-on-surface)]',
|
|
37
37
|
danger: 'text-[var(--cxs-color-danger)]'
|
|
38
38
|
};
|
|
39
|
-
const CLOSE_BUTTON_CLASSES = 'ml-auto inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
39
|
+
const CLOSE_BUTTON_CLASSES$2 = 'ml-auto inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
40
40
|
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
41
41
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
42
42
|
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
@@ -47,24 +47,24 @@ class CxsAlertComponent {
|
|
|
47
47
|
closed = new EventEmitter();
|
|
48
48
|
isVisible = true;
|
|
49
49
|
get alertClass() {
|
|
50
|
-
return [BASE_CLASSES$
|
|
50
|
+
return [BASE_CLASSES$a, VARIANT_CLASSES$7[this.variant]].join(' ');
|
|
51
51
|
}
|
|
52
52
|
get titleClass() {
|
|
53
53
|
return [TITLE_BASE, TITLE_VARIANT[this.variant]].join(' ');
|
|
54
54
|
}
|
|
55
55
|
get closeButtonClass() {
|
|
56
|
-
return CLOSE_BUTTON_CLASSES;
|
|
56
|
+
return CLOSE_BUTTON_CLASSES$2;
|
|
57
57
|
}
|
|
58
58
|
onClose() {
|
|
59
59
|
this.isVisible = false;
|
|
60
60
|
this.closed.emit();
|
|
61
61
|
}
|
|
62
62
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
63
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAlertComponent, isStandalone: true, selector: "cxs-alert", inputs: { variant: "variant", title: "title", dismissible: "dismissible" }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isVisible) {\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\n <div class=\"flex flex-col gap-1\">\n @if (title) {\n <div [class]=\"titleClass\">{{ title }}</div>\n }\n <div class=\"text-[var(--cxs-color-on-surface)]\">\n <ng-content></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss alert\"\n (click)=\"onClose()\"\n >\n x\n </button>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
63
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAlertComponent, isStandalone: true, selector: "cxs-alert", inputs: { variant: "variant", title: "title", dismissible: "dismissible" }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isVisible) {\r\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\r\n <div class=\"flex flex-col gap-1\">\r\n @if (title) {\r\n <div [class]=\"titleClass\">{{ title }}</div>\r\n }\r\n <div class=\"text-[var(--cxs-color-on-surface)]\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n @if (dismissible) {\r\n <button\r\n type=\"button\"\r\n [class]=\"closeButtonClass\"\r\n aria-label=\"Dismiss alert\"\r\n (click)=\"onClose()\"\r\n >\r\n x\r\n </button>\r\n }\r\n </div>\r\n}\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
64
64
|
}
|
|
65
65
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAlertComponent, decorators: [{
|
|
66
66
|
type: Component,
|
|
67
|
-
args: [{ selector: 'cxs-alert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isVisible) {\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\n <div class=\"flex flex-col gap-1\">\n @if (title) {\n <div [class]=\"titleClass\">{{ title }}</div>\n }\n <div class=\"text-[var(--cxs-color-on-surface)]\">\n <ng-content></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss alert\"\n (click)=\"onClose()\"\n >\n x\n </button>\n }\n </div>\n}\n" }]
|
|
67
|
+
args: [{ selector: 'cxs-alert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isVisible) {\r\n <div [class]=\"alertClass\" role=\"status\" aria-live=\"polite\">\r\n <div class=\"flex flex-col gap-1\">\r\n @if (title) {\r\n <div [class]=\"titleClass\">{{ title }}</div>\r\n }\r\n <div class=\"text-[var(--cxs-color-on-surface)]\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n @if (dismissible) {\r\n <button\r\n type=\"button\"\r\n [class]=\"closeButtonClass\"\r\n aria-label=\"Dismiss alert\"\r\n (click)=\"onClose()\"\r\n >\r\n x\r\n </button>\r\n }\r\n </div>\r\n}\r\n" }]
|
|
68
68
|
}], propDecorators: { variant: [{
|
|
69
69
|
type: Input
|
|
70
70
|
}], title: [{
|
|
@@ -75,9 +75,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
75
75
|
type: Output
|
|
76
76
|
}] } });
|
|
77
77
|
|
|
78
|
-
const BASE_CLASSES$
|
|
78
|
+
const BASE_CLASSES$9 = 'grid';
|
|
79
|
+
const SPACING_CLASSES = {
|
|
80
|
+
sm: 'gap-2',
|
|
81
|
+
md: 'gap-3',
|
|
82
|
+
lg: 'gap-4'
|
|
83
|
+
};
|
|
84
|
+
class CxsAccordionComponent {
|
|
85
|
+
spacing = 'md';
|
|
86
|
+
get accordionClass() {
|
|
87
|
+
return [BASE_CLASSES$9, SPACING_CLASSES[this.spacing]].join(' ');
|
|
88
|
+
}
|
|
89
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
90
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsAccordionComponent, isStandalone: true, selector: "cxs-accordion", inputs: { spacing: "spacing" }, ngImport: i0, template: "<div [class]=\"accordionClass\">\n <ng-content></ng-content>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionComponent, decorators: [{
|
|
93
|
+
type: Component,
|
|
94
|
+
args: [{ selector: 'cxs-accordion', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"accordionClass\">\n <ng-content></ng-content>\n</div>\n" }]
|
|
95
|
+
}], propDecorators: { spacing: [{
|
|
96
|
+
type: Input
|
|
97
|
+
}] } });
|
|
98
|
+
|
|
99
|
+
const ITEM_BASE = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
100
|
+
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
|
|
101
|
+
const ITEM_DISABLED = 'opacity-60';
|
|
102
|
+
const HEADER_BASE = 'flex w-full items-center justify-between gap-3 text-left font-medium transition-colors ' +
|
|
103
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
104
|
+
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
105
|
+
const HEADER_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
|
|
106
|
+
const HEADER_DISABLED = 'cursor-not-allowed';
|
|
107
|
+
const CONTENT_BASE = 'text-(--cxs-color-on-surface-muted)';
|
|
108
|
+
const SIZE_HEADER_CLASSES = {
|
|
109
|
+
sm: 'px-3 py-2 text-sm',
|
|
110
|
+
md: 'px-4 py-3 text-sm',
|
|
111
|
+
lg: 'px-5 py-4 text-base'
|
|
112
|
+
};
|
|
113
|
+
const SIZE_CONTENT_CLASSES = {
|
|
114
|
+
sm: 'px-3 pb-3 text-sm',
|
|
115
|
+
md: 'px-4 pb-4 text-sm',
|
|
116
|
+
lg: 'px-5 pb-5 text-base'
|
|
117
|
+
};
|
|
118
|
+
class CxsAccordionItemComponent {
|
|
119
|
+
static nextId = 0;
|
|
120
|
+
title;
|
|
121
|
+
expanded = false;
|
|
122
|
+
disabled = false;
|
|
123
|
+
size = 'md';
|
|
124
|
+
expandedChange = new EventEmitter();
|
|
125
|
+
buttonId = `cxs-accordion-button-${++CxsAccordionItemComponent.nextId}`;
|
|
126
|
+
contentId = `cxs-accordion-panel-${CxsAccordionItemComponent.nextId}`;
|
|
127
|
+
get itemClass() {
|
|
128
|
+
return [ITEM_BASE, this.disabled ? ITEM_DISABLED : ''].filter(Boolean).join(' ');
|
|
129
|
+
}
|
|
130
|
+
get headerClass() {
|
|
131
|
+
return [
|
|
132
|
+
HEADER_BASE,
|
|
133
|
+
SIZE_HEADER_CLASSES[this.size],
|
|
134
|
+
this.disabled ? HEADER_DISABLED : HEADER_HOVER
|
|
135
|
+
]
|
|
136
|
+
.filter(Boolean)
|
|
137
|
+
.join(' ');
|
|
138
|
+
}
|
|
139
|
+
get contentClass() {
|
|
140
|
+
return [CONTENT_BASE, SIZE_CONTENT_CLASSES[this.size]].join(' ');
|
|
141
|
+
}
|
|
142
|
+
get iconClass() {
|
|
143
|
+
return [
|
|
144
|
+
'h-4 w-4 shrink-0 text-(--cxs-color-on-surface-muted) transition-transform',
|
|
145
|
+
this.expanded ? 'rotate-180' : ''
|
|
146
|
+
]
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
.join(' ');
|
|
149
|
+
}
|
|
150
|
+
toggle() {
|
|
151
|
+
if (this.disabled) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.expanded = !this.expanded;
|
|
155
|
+
this.expandedChange.emit(this.expanded);
|
|
156
|
+
}
|
|
157
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
158
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAccordionItemComponent, isStandalone: true, selector: "cxs-accordion-item", inputs: { title: "title", expanded: "expanded", disabled: "disabled", size: "size" }, outputs: { expandedChange: "expandedChange" }, ngImport: i0, template: "<div [class]=\"itemClass\">\n <button\n type=\"button\"\n [class]=\"headerClass\"\n [id]=\"buttonId\"\n [disabled]=\"disabled\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"contentId\"\n (click)=\"toggle()\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n <ng-content select=\"[cxsAccordionTitle]\"></ng-content>\n @if (title) {\n <span class=\"truncate\">{{ title }}</span>\n }\n </span>\n <svg aria-hidden=\"true\" [class]=\"iconClass\" viewBox=\"0 0 20 20\">\n <path\n d=\"M5 7l5 5 5-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n ></path>\n </svg>\n </button>\n\n <div\n [id]=\"contentId\"\n role=\"region\"\n [attr.aria-labelledby]=\"buttonId\"\n [class]=\"contentClass\"\n [hidden]=\"!expanded\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
159
|
+
}
|
|
160
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAccordionItemComponent, decorators: [{
|
|
161
|
+
type: Component,
|
|
162
|
+
args: [{ selector: 'cxs-accordion-item', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"itemClass\">\n <button\n type=\"button\"\n [class]=\"headerClass\"\n [id]=\"buttonId\"\n [disabled]=\"disabled\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"contentId\"\n (click)=\"toggle()\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n <ng-content select=\"[cxsAccordionTitle]\"></ng-content>\n @if (title) {\n <span class=\"truncate\">{{ title }}</span>\n }\n </span>\n <svg aria-hidden=\"true\" [class]=\"iconClass\" viewBox=\"0 0 20 20\">\n <path\n d=\"M5 7l5 5 5-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n ></path>\n </svg>\n </button>\n\n <div\n [id]=\"contentId\"\n role=\"region\"\n [attr.aria-labelledby]=\"buttonId\"\n [class]=\"contentClass\"\n [hidden]=\"!expanded\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n" }]
|
|
163
|
+
}], propDecorators: { title: [{
|
|
164
|
+
type: Input
|
|
165
|
+
}], expanded: [{
|
|
166
|
+
type: Input
|
|
167
|
+
}], disabled: [{
|
|
168
|
+
type: Input
|
|
169
|
+
}], size: [{
|
|
170
|
+
type: Input
|
|
171
|
+
}], expandedChange: [{
|
|
172
|
+
type: Output
|
|
173
|
+
}] } });
|
|
174
|
+
|
|
175
|
+
const BASE_CLASSES$8 = 'inline-flex items-center gap-1 rounded-[var(--cxs-radius-md)] border px-2.5 py-0.5 text-xs font-medium ' +
|
|
79
176
|
'leading-none';
|
|
80
|
-
const VARIANT_CLASSES$
|
|
177
|
+
const VARIANT_CLASSES$6 = {
|
|
81
178
|
primary: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
|
|
82
179
|
'text-[var(--cxs-color-primary)]',
|
|
83
180
|
neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
|
|
@@ -85,7 +182,7 @@ const VARIANT_CLASSES$5 = {
|
|
|
85
182
|
danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
|
|
86
183
|
'text-[var(--cxs-color-danger)]'
|
|
87
184
|
};
|
|
88
|
-
const SIZE_CLASSES$
|
|
185
|
+
const SIZE_CLASSES$7 = {
|
|
89
186
|
sm: 'text-[11px]',
|
|
90
187
|
md: 'text-xs'
|
|
91
188
|
};
|
|
@@ -93,21 +190,124 @@ class CxsBadgeComponent {
|
|
|
93
190
|
variant = 'primary';
|
|
94
191
|
size = 'md';
|
|
95
192
|
get badgeClass() {
|
|
96
|
-
return [BASE_CLASSES$
|
|
193
|
+
return [BASE_CLASSES$8, VARIANT_CLASSES$6[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
|
|
97
194
|
}
|
|
98
195
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
99
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\n <ng-content></ng-content>\n</span>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
196
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\r\n <ng-content></ng-content>\r\n</span>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
100
197
|
}
|
|
101
198
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, decorators: [{
|
|
102
199
|
type: Component,
|
|
103
|
-
args: [{ selector: 'cxs-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<span [class]=\"badgeClass\">\n <ng-content></ng-content>\n</span>\n" }]
|
|
200
|
+
args: [{ selector: 'cxs-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<span [class]=\"badgeClass\">\r\n <ng-content></ng-content>\r\n</span>\r\n" }]
|
|
104
201
|
}], propDecorators: { variant: [{
|
|
105
202
|
type: Input
|
|
106
203
|
}], size: [{
|
|
107
204
|
type: Input
|
|
108
205
|
}] } });
|
|
109
206
|
|
|
110
|
-
const BASE_CLASSES$
|
|
207
|
+
const BASE_CLASSES$7 = 'inline-flex items-center justify-center overflow-hidden border border-[var(--cxs-color-border)] ' +
|
|
208
|
+
'bg-[var(--cxs-color-primary-ghost)] text-[var(--cxs-color-primary)] font-semibold uppercase ' +
|
|
209
|
+
'select-none';
|
|
210
|
+
const SIZE_CLASSES$6 = {
|
|
211
|
+
sm: 'h-8 w-8 text-[11px]',
|
|
212
|
+
md: 'h-10 w-10 text-xs',
|
|
213
|
+
lg: 'h-14 w-14 text-sm'
|
|
214
|
+
};
|
|
215
|
+
const SHAPE_CLASSES = {
|
|
216
|
+
circle: 'rounded-full',
|
|
217
|
+
square: 'rounded-[var(--cxs-radius-md)]'
|
|
218
|
+
};
|
|
219
|
+
const FALLBACK_CLASSES = 'leading-none';
|
|
220
|
+
class CxsAvatarComponent {
|
|
221
|
+
hostClass;
|
|
222
|
+
_src;
|
|
223
|
+
set src(value) {
|
|
224
|
+
if (value !== this._src) {
|
|
225
|
+
this._src = value;
|
|
226
|
+
this.imageError = false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
get src() {
|
|
230
|
+
return this._src;
|
|
231
|
+
}
|
|
232
|
+
name;
|
|
233
|
+
alt;
|
|
234
|
+
size = 'md';
|
|
235
|
+
shape = 'circle';
|
|
236
|
+
imageError = false;
|
|
237
|
+
constructor(hostClass) {
|
|
238
|
+
this.hostClass = hostClass;
|
|
239
|
+
}
|
|
240
|
+
get avatarClass() {
|
|
241
|
+
return [BASE_CLASSES$7, SIZE_CLASSES$6[this.size], SHAPE_CLASSES[this.shape], this.hostClass]
|
|
242
|
+
.filter(Boolean)
|
|
243
|
+
.join(' ');
|
|
244
|
+
}
|
|
245
|
+
get fallbackClass() {
|
|
246
|
+
return FALLBACK_CLASSES;
|
|
247
|
+
}
|
|
248
|
+
get altText() {
|
|
249
|
+
if (this.alt !== undefined) {
|
|
250
|
+
return this.alt;
|
|
251
|
+
}
|
|
252
|
+
if (this.name) {
|
|
253
|
+
return this.name;
|
|
254
|
+
}
|
|
255
|
+
return 'Avatar';
|
|
256
|
+
}
|
|
257
|
+
get fallbackLabel() {
|
|
258
|
+
if (this.name) {
|
|
259
|
+
return this.name;
|
|
260
|
+
}
|
|
261
|
+
if (this.alt && this.alt.trim().length > 0) {
|
|
262
|
+
return this.alt;
|
|
263
|
+
}
|
|
264
|
+
return 'Avatar';
|
|
265
|
+
}
|
|
266
|
+
get fallbackText() {
|
|
267
|
+
if (!this.name) {
|
|
268
|
+
return '?';
|
|
269
|
+
}
|
|
270
|
+
return this.getInitials(this.name);
|
|
271
|
+
}
|
|
272
|
+
get showImage() {
|
|
273
|
+
return !!this.src && !this.imageError;
|
|
274
|
+
}
|
|
275
|
+
onImageError() {
|
|
276
|
+
this.imageError = true;
|
|
277
|
+
}
|
|
278
|
+
getInitials(value) {
|
|
279
|
+
const parts = value
|
|
280
|
+
.trim()
|
|
281
|
+
.split(/\s+/)
|
|
282
|
+
.filter(Boolean);
|
|
283
|
+
if (parts.length >= 2) {
|
|
284
|
+
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
285
|
+
}
|
|
286
|
+
const word = parts[0] ?? '';
|
|
287
|
+
return word.slice(0, 2).toUpperCase() || '?';
|
|
288
|
+
}
|
|
289
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAvatarComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
290
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsAvatarComponent, isStandalone: true, selector: "cxs-avatar", inputs: { src: "src", name: "name", alt: "alt", size: "size", shape: "shape" }, ngImport: i0, template: "<div\n [class]=\"avatarClass\"\n [attr.role]=\"showImage ? null : 'img'\"\n [attr.aria-label]=\"showImage ? null : fallbackLabel\"\n>\n @if (showImage) {\n <img\n [attr.src]=\"src\"\n [attr.alt]=\"altText\"\n class=\"h-full w-full object-cover\"\n (error)=\"onImageError()\"\n />\n } @else {\n <span [class]=\"fallbackClass\" aria-hidden=\"true\">{{ fallbackText }}</span>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
291
|
+
}
|
|
292
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsAvatarComponent, decorators: [{
|
|
293
|
+
type: Component,
|
|
294
|
+
args: [{ selector: 'cxs-avatar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [class]=\"avatarClass\"\n [attr.role]=\"showImage ? null : 'img'\"\n [attr.aria-label]=\"showImage ? null : fallbackLabel\"\n>\n @if (showImage) {\n <img\n [attr.src]=\"src\"\n [attr.alt]=\"altText\"\n class=\"h-full w-full object-cover\"\n (error)=\"onImageError()\"\n />\n } @else {\n <span [class]=\"fallbackClass\" aria-hidden=\"true\">{{ fallbackText }}</span>\n }\n</div>\n" }]
|
|
295
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
296
|
+
type: Attribute,
|
|
297
|
+
args: ['class']
|
|
298
|
+
}] }], propDecorators: { src: [{
|
|
299
|
+
type: Input
|
|
300
|
+
}], name: [{
|
|
301
|
+
type: Input
|
|
302
|
+
}], alt: [{
|
|
303
|
+
type: Input
|
|
304
|
+
}], size: [{
|
|
305
|
+
type: Input
|
|
306
|
+
}], shape: [{
|
|
307
|
+
type: Input
|
|
308
|
+
}] } });
|
|
309
|
+
|
|
310
|
+
const BASE_CLASSES$6 = 'flex flex-wrap items-center gap-x-1 gap-y-1';
|
|
111
311
|
const ITEM_CLASSES = 'flex items-center gap-1';
|
|
112
312
|
const LINK_BASE_CLASSES = 'rounded-[var(--cxs-radius-md)] transition-colors focus-visible:outline focus-visible:outline-2 ' +
|
|
113
313
|
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
@@ -135,7 +335,7 @@ class CxsBreadcrumbComponent {
|
|
|
135
335
|
variant = 'default';
|
|
136
336
|
disabled = false;
|
|
137
337
|
get listClass() {
|
|
138
|
-
return [BASE_CLASSES$
|
|
338
|
+
return [BASE_CLASSES$6, SIZE_CLASSES$5[this.size], this.disabled ? 'opacity-60' : '']
|
|
139
339
|
.filter(Boolean)
|
|
140
340
|
.join(' ');
|
|
141
341
|
}
|
|
@@ -177,11 +377,11 @@ class CxsBreadcrumbComponent {
|
|
|
177
377
|
return item.rel ?? null;
|
|
178
378
|
}
|
|
179
379
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
180
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsBreadcrumbComponent, isStandalone: true, selector: "cxs-breadcrumb", inputs: { items: "items", separator: "separator", ariaLabel: "ariaLabel", size: "size", variant: "variant", disabled: "disabled" }, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ol [class]=\"listClass\">\n @for (item of items; track item; let last = $last) {\n <li [class]=\"itemClass\">\n @if (isLink(item, last)) {\n <a\n [class]=\"getLinkClass(item)\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n [class]=\"getLabelClass(item, last)\"\n [attr.aria-current]=\"last ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n @if (!last && separator) {\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
380
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsBreadcrumbComponent, isStandalone: true, selector: "cxs-breadcrumb", inputs: { items: "items", separator: "separator", ariaLabel: "ariaLabel", size: "size", variant: "variant", disabled: "disabled" }, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel\">\r\n <ol [class]=\"listClass\">\r\n @for (item of items; track item; let last = $last) {\r\n <li [class]=\"itemClass\">\r\n @if (isLink(item, last)) {\r\n <a\r\n [class]=\"getLinkClass(item)\"\r\n [attr.href]=\"item.href\"\r\n [attr.target]=\"item.target ?? null\"\r\n [attr.rel]=\"getItemRel(item)\"\r\n [attr.aria-label]=\"item.ariaLabel ?? null\"\r\n >\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n [class]=\"getLabelClass(item, last)\"\r\n [attr.aria-current]=\"last ? 'page' : null\"\r\n >\r\n {{ item.label }}\r\n </span>\r\n }\r\n @if (!last && separator) {\r\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
181
381
|
}
|
|
182
382
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBreadcrumbComponent, decorators: [{
|
|
183
383
|
type: Component,
|
|
184
|
-
args: [{ selector: 'cxs-breadcrumb', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [attr.aria-label]=\"ariaLabel\">\n <ol [class]=\"listClass\">\n @for (item of items; track item; let last = $last) {\n <li [class]=\"itemClass\">\n @if (isLink(item, last)) {\n <a\n [class]=\"getLinkClass(item)\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target ?? null\"\n [attr.rel]=\"getItemRel(item)\"\n [attr.aria-label]=\"item.ariaLabel ?? null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n [class]=\"getLabelClass(item, last)\"\n [attr.aria-current]=\"last ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n @if (!last && separator) {\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n" }]
|
|
384
|
+
args: [{ selector: 'cxs-breadcrumb', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [attr.aria-label]=\"ariaLabel\">\r\n <ol [class]=\"listClass\">\r\n @for (item of items; track item; let last = $last) {\r\n <li [class]=\"itemClass\">\r\n @if (isLink(item, last)) {\r\n <a\r\n [class]=\"getLinkClass(item)\"\r\n [attr.href]=\"item.href\"\r\n [attr.target]=\"item.target ?? null\"\r\n [attr.rel]=\"getItemRel(item)\"\r\n [attr.aria-label]=\"item.ariaLabel ?? null\"\r\n >\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n [class]=\"getLabelClass(item, last)\"\r\n [attr.aria-current]=\"last ? 'page' : null\"\r\n >\r\n {{ item.label }}\r\n </span>\r\n }\r\n @if (!last && separator) {\r\n <span [class]=\"separatorClass\" aria-hidden=\"true\">{{ separator }}</span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n" }]
|
|
185
385
|
}], propDecorators: { items: [{
|
|
186
386
|
type: Input
|
|
187
387
|
}], separator: [{
|
|
@@ -196,10 +396,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
196
396
|
type: Input
|
|
197
397
|
}] } });
|
|
198
398
|
|
|
199
|
-
const BASE_CLASSES$
|
|
399
|
+
const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
|
|
200
400
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
201
401
|
'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-50';
|
|
202
|
-
const VARIANT_CLASSES$
|
|
402
|
+
const VARIANT_CLASSES$5 = {
|
|
203
403
|
primary: 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)] ' +
|
|
204
404
|
'hover:bg-[var(--cxs-color-primary-hover)] shadow-[var(--cxs-shadow-sm)]',
|
|
205
405
|
secondary: 'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
@@ -225,16 +425,16 @@ class CxsButtonComponent {
|
|
|
225
425
|
return this.disabled || this.loading;
|
|
226
426
|
}
|
|
227
427
|
get buttonClass() {
|
|
228
|
-
return [BASE_CLASSES$
|
|
428
|
+
return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$5[this.variant], this.hostClass]
|
|
229
429
|
.filter(Boolean)
|
|
230
430
|
.join(' ');
|
|
231
431
|
}
|
|
232
432
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
233
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type" }, ngImport: i0, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
433
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type" }, ngImport: i0, template: "<button\r\n [class]=\"buttonClass\"\r\n [attr.type]=\"type\"\r\n [disabled]=\"isDisabled\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n>\r\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
234
434
|
}
|
|
235
435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsButtonComponent, decorators: [{
|
|
236
436
|
type: Component,
|
|
237
|
-
args: [{ selector: 'cxs-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n" }]
|
|
437
|
+
args: [{ selector: 'cxs-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\r\n [class]=\"buttonClass\"\r\n [attr.type]=\"type\"\r\n [disabled]=\"isDisabled\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n>\r\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n" }]
|
|
238
438
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
239
439
|
type: Attribute,
|
|
240
440
|
args: ['class']
|
|
@@ -250,9 +450,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
250
450
|
type: Input
|
|
251
451
|
}] } });
|
|
252
452
|
|
|
253
|
-
const BASE_CLASSES$
|
|
453
|
+
const BASE_CLASSES$4 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
254
454
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
|
|
255
|
-
const VARIANT_CLASSES$
|
|
455
|
+
const VARIANT_CLASSES$4 = {
|
|
256
456
|
surface: 'bg-[var(--cxs-color-surface)]',
|
|
257
457
|
muted: 'bg-[var(--cxs-color-surface-hover)]',
|
|
258
458
|
outline: 'bg-transparent'
|
|
@@ -270,8 +470,8 @@ class CxsCardComponent {
|
|
|
270
470
|
ariaLabelledby;
|
|
271
471
|
get cardClass() {
|
|
272
472
|
return [
|
|
273
|
-
BASE_CLASSES$
|
|
274
|
-
VARIANT_CLASSES$
|
|
473
|
+
BASE_CLASSES$4,
|
|
474
|
+
VARIANT_CLASSES$4[this.variant],
|
|
275
475
|
SIZE_CLASSES$3[this.size],
|
|
276
476
|
this.elevated ? 'shadow-[var(--cxs-shadow-sm)]' : ''
|
|
277
477
|
]
|
|
@@ -279,11 +479,11 @@ class CxsCardComponent {
|
|
|
279
479
|
.join(' ');
|
|
280
480
|
}
|
|
281
481
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
282
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsCardComponent, isStandalone: true, selector: "cxs-card", inputs: { variant: "variant", size: "size", elevated: "elevated", ariaLabel: "ariaLabel", ariaLabelledby: "ariaLabelledby" }, ngImport: i0, template: "<section\n [class]=\"cardClass\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n>\n <ng-content></ng-content>\n</section>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
482
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsCardComponent, isStandalone: true, selector: "cxs-card", inputs: { variant: "variant", size: "size", elevated: "elevated", ariaLabel: "ariaLabel", ariaLabelledby: "ariaLabelledby" }, ngImport: i0, template: "<section\r\n [class]=\"cardClass\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-labelledby]=\"ariaLabelledby\"\r\n>\r\n <ng-content></ng-content>\r\n</section>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
283
483
|
}
|
|
284
484
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCardComponent, decorators: [{
|
|
285
485
|
type: Component,
|
|
286
|
-
args: [{ selector: 'cxs-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n [class]=\"cardClass\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n>\n <ng-content></ng-content>\n</section>\n" }]
|
|
486
|
+
args: [{ selector: 'cxs-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\r\n [class]=\"cardClass\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-labelledby]=\"ariaLabelledby\"\r\n>\r\n <ng-content></ng-content>\r\n</section>\r\n" }]
|
|
287
487
|
}], propDecorators: { variant: [{
|
|
288
488
|
type: Input
|
|
289
489
|
}], size: [{
|
|
@@ -401,7 +601,7 @@ class CxsCheckboxComponent {
|
|
|
401
601
|
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
402
602
|
multi: true
|
|
403
603
|
}
|
|
404
|
-
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-checked]=\"ariaChecked\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"checked\"\n [indeterminate]=\"indeterminate\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onCheckboxChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n @if (label) {\n <span [class]=\"labelClass\">{{ label }}</span>\n } @else {\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n }\n</label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
604
|
+
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"checkbox\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-checked]=\"ariaChecked\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"checked\"\r\n [indeterminate]=\"indeterminate\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onCheckboxChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n @if (label) {\r\n <span [class]=\"labelClass\">{{ label }}</span>\r\n } @else {\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n</label>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
405
605
|
}
|
|
406
606
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCheckboxComponent, decorators: [{
|
|
407
607
|
type: Component,
|
|
@@ -411,7 +611,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
411
611
|
useExisting: forwardRef(() => CxsCheckboxComponent),
|
|
412
612
|
multi: true
|
|
413
613
|
}
|
|
414
|
-
], template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-checked]=\"ariaChecked\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"checked\"\n [indeterminate]=\"indeterminate\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onCheckboxChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n @if (label) {\n <span [class]=\"labelClass\">{{ label }}</span>\n } @else {\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n }\n</label>\n" }]
|
|
614
|
+
], template: "<label [class]=\"wrapperClass\">\r\n <input\r\n class=\"peer sr-only\"\r\n type=\"checkbox\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-checked]=\"ariaChecked\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [checked]=\"checked\"\r\n [indeterminate]=\"indeterminate\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n (change)=\"onCheckboxChange($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\r\n @if (label) {\r\n <span [class]=\"labelClass\">{{ label }}</span>\r\n } @else {\r\n <span [class]=\"labelClass\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n</label>\r\n" }]
|
|
415
615
|
}], propDecorators: { checked: [{
|
|
416
616
|
type: Input
|
|
417
617
|
}], indeterminate: [{
|
|
@@ -438,175 +638,1073 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
438
638
|
type: Output
|
|
439
639
|
}] } });
|
|
440
640
|
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
outline: 'bg-[var(--cxs-color-surface)]',
|
|
449
|
-
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
450
|
-
};
|
|
451
|
-
const SIZE_CLASSES$2 = {
|
|
452
|
-
sm: 'h-8 px-3 text-sm',
|
|
453
|
-
md: 'h-10 px-3 text-sm',
|
|
454
|
-
lg: 'h-12 px-4 text-base'
|
|
455
|
-
};
|
|
456
|
-
const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
|
|
457
|
-
'focus-visible:outline-[var(--cxs-color-danger)]';
|
|
458
|
-
const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
|
|
459
|
-
'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
|
|
460
|
-
const NAV_BUTTON_CLASSES = 'inline-flex h-8 w-8 items-center justify-center rounded-[var(--cxs-radius-md)] ' +
|
|
461
|
-
'text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)] ' +
|
|
641
|
+
const WRAPPER_BASE_CLASSES$2 = 'relative overflow-hidden rounded-[var(--cxs-radius-md)]';
|
|
642
|
+
const TRACK_CLASSES = 'flex transition-transform duration-500 ease-out';
|
|
643
|
+
const SLIDE_BASE_CLASSES = 'w-full flex-shrink-0';
|
|
644
|
+
const IMAGE_CLASSES = 'h-56 w-full object-cover';
|
|
645
|
+
const CONTENT_CLASSES = 'absolute inset-x-0 bottom-0 bg-[rgba(15,23,42,0.6)] px-4 py-3 text-sm text-white';
|
|
646
|
+
const CONTROL_CLASSES = 'absolute top-1/2 -translate-y-1/2 inline-flex h-9 w-9 items-center justify-center rounded-full ' +
|
|
647
|
+
'bg-[rgba(15,23,42,0.7)] text-white transition hover:bg-[rgba(15,23,42,0.85)] ' +
|
|
462
648
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
463
649
|
'focus-visible:outline-[var(--cxs-color-focus)]';
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
id;
|
|
482
|
-
name;
|
|
483
|
-
min;
|
|
484
|
-
max;
|
|
485
|
-
placeholder;
|
|
486
|
-
ariaLabel;
|
|
487
|
-
ariaDescribedby;
|
|
488
|
-
valueChange = new EventEmitter();
|
|
489
|
-
static nextId = 0;
|
|
490
|
-
fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
|
|
491
|
-
disabledFromControl = false;
|
|
492
|
-
onChange = () => { };
|
|
493
|
-
onTouched = () => { };
|
|
494
|
-
isOpen = false;
|
|
495
|
-
displayMonth = new Date();
|
|
496
|
-
calendarDays = [];
|
|
497
|
-
weekDayLabels = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
498
|
-
get isDisabled() {
|
|
499
|
-
return this.disabled || this.disabledFromControl;
|
|
500
|
-
}
|
|
501
|
-
get panelId() {
|
|
502
|
-
return this.id ? `${this.id}-panel` : this.fallbackId;
|
|
503
|
-
}
|
|
504
|
-
get inputClass() {
|
|
505
|
-
return [
|
|
506
|
-
BASE_CLASSES$2,
|
|
507
|
-
SIZE_CLASSES$2[this.size],
|
|
508
|
-
VARIANT_CLASSES$2[this.variant],
|
|
509
|
-
this.invalid ? INVALID_CLASSES$3 : ''
|
|
510
|
-
]
|
|
511
|
-
.filter(Boolean)
|
|
512
|
-
.join(' ');
|
|
650
|
+
const INDICATOR_CONTAINER_CLASSES = 'absolute bottom-3 left-1/2 flex -translate-x-1/2 items-center gap-2';
|
|
651
|
+
const INDICATOR_BASE_CLASSES = 'h-2 w-2 rounded-full bg-white/50 transition-colors';
|
|
652
|
+
const INDICATOR_ACTIVE_CLASSES = 'bg-white';
|
|
653
|
+
class CxsCarouselComponent {
|
|
654
|
+
hostClass;
|
|
655
|
+
items = [];
|
|
656
|
+
activeIndex = 0;
|
|
657
|
+
autoplay = false;
|
|
658
|
+
interval = 4000;
|
|
659
|
+
loop = true;
|
|
660
|
+
showControls = true;
|
|
661
|
+
showIndicators = true;
|
|
662
|
+
ariaLabel = 'Carousel';
|
|
663
|
+
activeIndexChange = new EventEmitter();
|
|
664
|
+
timerId = null;
|
|
665
|
+
constructor(hostClass) {
|
|
666
|
+
this.hostClass = hostClass;
|
|
513
667
|
}
|
|
514
|
-
|
|
515
|
-
|
|
668
|
+
ngOnChanges(changes) {
|
|
669
|
+
if (changes['items'] || changes['autoplay'] || changes['interval']) {
|
|
670
|
+
this.resetAutoplay();
|
|
671
|
+
}
|
|
672
|
+
if (changes['activeIndex']) {
|
|
673
|
+
this.activeIndex = this.clampIndex(this.activeIndex);
|
|
674
|
+
}
|
|
516
675
|
}
|
|
517
|
-
|
|
518
|
-
|
|
676
|
+
ngAfterViewInit() {
|
|
677
|
+
this.resetAutoplay();
|
|
519
678
|
}
|
|
520
|
-
|
|
521
|
-
|
|
679
|
+
ngOnDestroy() {
|
|
680
|
+
this.clearAutoplay();
|
|
522
681
|
}
|
|
523
|
-
|
|
524
|
-
this.
|
|
525
|
-
this.syncDisplayMonthWithValue();
|
|
682
|
+
get wrapperClass() {
|
|
683
|
+
return [WRAPPER_BASE_CLASSES$2, this.hostClass].filter(Boolean).join(' ');
|
|
526
684
|
}
|
|
527
|
-
|
|
528
|
-
this.
|
|
685
|
+
get trackStyle() {
|
|
686
|
+
return `translateX(-${this.activeIndex * 100}%)`;
|
|
529
687
|
}
|
|
530
|
-
|
|
531
|
-
|
|
688
|
+
get trackClass() {
|
|
689
|
+
return TRACK_CLASSES;
|
|
532
690
|
}
|
|
533
|
-
|
|
534
|
-
|
|
691
|
+
get slideClass() {
|
|
692
|
+
return SLIDE_BASE_CLASSES;
|
|
535
693
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const nextValue = target.value;
|
|
539
|
-
this.value = nextValue;
|
|
540
|
-
this.onChange(nextValue);
|
|
541
|
-
this.valueChange.emit(nextValue);
|
|
694
|
+
get imageClass() {
|
|
695
|
+
return IMAGE_CLASSES;
|
|
542
696
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const nextValue = this.formatDate(day.date);
|
|
548
|
-
this.value = nextValue;
|
|
549
|
-
this.onChange(nextValue);
|
|
550
|
-
this.valueChange.emit(nextValue);
|
|
551
|
-
this.isOpen = false;
|
|
697
|
+
get contentClass() {
|
|
698
|
+
return CONTENT_CLASSES;
|
|
552
699
|
}
|
|
553
|
-
|
|
554
|
-
|
|
700
|
+
get controlClass() {
|
|
701
|
+
return CONTROL_CLASSES;
|
|
555
702
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
this.isOpen = true;
|
|
561
|
-
this.syncDisplayMonthWithValue();
|
|
703
|
+
get indicatorContainerClass() {
|
|
704
|
+
return INDICATOR_CONTAINER_CLASSES;
|
|
562
705
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
this.open();
|
|
706
|
+
indicatorClass(isActive) {
|
|
707
|
+
return [INDICATOR_BASE_CLASSES, isActive ? INDICATOR_ACTIVE_CLASSES : '']
|
|
708
|
+
.filter(Boolean)
|
|
709
|
+
.join(' ');
|
|
569
710
|
}
|
|
570
|
-
|
|
571
|
-
this.
|
|
572
|
-
this.updateCalendar();
|
|
711
|
+
previous() {
|
|
712
|
+
this.goTo(this.activeIndex - 1);
|
|
573
713
|
}
|
|
574
|
-
|
|
575
|
-
this.
|
|
576
|
-
this.updateCalendar();
|
|
714
|
+
next() {
|
|
715
|
+
this.goTo(this.activeIndex + 1);
|
|
577
716
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
day.isToday ? DAY_TODAY : '',
|
|
583
|
-
this.isSelected(day.date) ? DAY_SELECTED : DAY_HOVER
|
|
584
|
-
]
|
|
585
|
-
.filter(Boolean)
|
|
586
|
-
.join(' ');
|
|
717
|
+
goTo(index) {
|
|
718
|
+
const nextIndex = this.normalizeIndex(index);
|
|
719
|
+
this.activeIndex = nextIndex;
|
|
720
|
+
this.activeIndexChange.emit(nextIndex);
|
|
587
721
|
}
|
|
588
|
-
|
|
589
|
-
if (
|
|
590
|
-
return;
|
|
722
|
+
normalizeIndex(index) {
|
|
723
|
+
if (!this.items.length) {
|
|
724
|
+
return 0;
|
|
591
725
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
726
|
+
if (this.loop) {
|
|
727
|
+
const total = this.items.length;
|
|
728
|
+
return (index + total) % total;
|
|
595
729
|
}
|
|
730
|
+
return this.clampIndex(index);
|
|
596
731
|
}
|
|
597
|
-
|
|
598
|
-
if (
|
|
599
|
-
return;
|
|
732
|
+
clampIndex(index) {
|
|
733
|
+
if (!this.items.length) {
|
|
734
|
+
return 0;
|
|
600
735
|
}
|
|
601
|
-
this.
|
|
736
|
+
return Math.min(Math.max(0, index), this.items.length - 1);
|
|
602
737
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
this.
|
|
606
|
-
|
|
738
|
+
resetAutoplay() {
|
|
739
|
+
this.clearAutoplay();
|
|
740
|
+
if (!this.autoplay || this.items.length <= 1) {
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
const intervalMs = Math.max(1000, this.interval);
|
|
744
|
+
this.timerId = setInterval(() => {
|
|
745
|
+
this.next();
|
|
746
|
+
}, intervalMs);
|
|
747
|
+
}
|
|
748
|
+
clearAutoplay() {
|
|
749
|
+
if (this.timerId) {
|
|
750
|
+
clearInterval(this.timerId);
|
|
751
|
+
this.timerId = null;
|
|
752
|
+
}
|
|
607
753
|
}
|
|
608
|
-
|
|
609
|
-
|
|
754
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCarouselComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
755
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsCarouselComponent, isStandalone: true, selector: "cxs-carousel", inputs: { items: "items", activeIndex: "activeIndex", autoplay: "autoplay", interval: "interval", loop: "loop", showControls: "showControls", showIndicators: "showIndicators", ariaLabel: "ariaLabel" }, outputs: { activeIndexChange: "activeIndexChange" }, usesOnChanges: true, ngImport: i0, template: "<div [class]=\"wrapperClass\" [attr.aria-label]=\"ariaLabel\">\n <div [class]=\"trackClass\" [style.transform]=\"trackStyle\">\n @for (item of items; track item) {\n <div [class]=\"slideClass\">\n @if (item.image) {\n <img\n [class]=\"imageClass\"\n [attr.src]=\"item.image\"\n [attr.alt]=\"item.alt ?? item.title ?? 'Carousel image'\"\n />\n }\n @if (item.title || item.description) {\n <div [class]=\"contentClass\">\n @if (item.title) {\n <div class=\"text-base font-semibold\">{{ item.title }}</div>\n }\n @if (item.description) {\n <div class=\"text-sm text-white/80\">{{ item.description }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (showControls && items.length > 1) {\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"left: 12px\"\n aria-label=\"Previous slide\"\n (click)=\"previous()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"right: 12px\"\n aria-label=\"Next slide\"\n (click)=\"next()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n\n </button>\n }\n\n @if (showIndicators && items.length > 1) {\n <div [class]=\"indicatorContainerClass\">\n @for (item of items; track item; let index = $index) {\n <button\n type=\"button\"\n [class]=\"indicatorClass(index === activeIndex)\"\n [attr.aria-label]=\"'Go to slide ' + (index + 1)\"\n (click)=\"goTo(index)\"\n ></button>\n }\n </div>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
756
|
+
}
|
|
757
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsCarouselComponent, decorators: [{
|
|
758
|
+
type: Component,
|
|
759
|
+
args: [{ selector: 'cxs-carousel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\" [attr.aria-label]=\"ariaLabel\">\n <div [class]=\"trackClass\" [style.transform]=\"trackStyle\">\n @for (item of items; track item) {\n <div [class]=\"slideClass\">\n @if (item.image) {\n <img\n [class]=\"imageClass\"\n [attr.src]=\"item.image\"\n [attr.alt]=\"item.alt ?? item.title ?? 'Carousel image'\"\n />\n }\n @if (item.title || item.description) {\n <div [class]=\"contentClass\">\n @if (item.title) {\n <div class=\"text-base font-semibold\">{{ item.title }}</div>\n }\n @if (item.description) {\n <div class=\"text-sm text-white/80\">{{ item.description }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (showControls && items.length > 1) {\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"left: 12px\"\n aria-label=\"Previous slide\"\n (click)=\"previous()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n [class]=\"controlClass\"\n style=\"right: 12px\"\n aria-label=\"Next slide\"\n (click)=\"next()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n\n </button>\n }\n\n @if (showIndicators && items.length > 1) {\n <div [class]=\"indicatorContainerClass\">\n @for (item of items; track item; let index = $index) {\n <button\n type=\"button\"\n [class]=\"indicatorClass(index === activeIndex)\"\n [attr.aria-label]=\"'Go to slide ' + (index + 1)\"\n (click)=\"goTo(index)\"\n ></button>\n }\n </div>\n }\n</div>\n" }]
|
|
760
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
761
|
+
type: Attribute,
|
|
762
|
+
args: ['class']
|
|
763
|
+
}] }], propDecorators: { items: [{
|
|
764
|
+
type: Input
|
|
765
|
+
}], activeIndex: [{
|
|
766
|
+
type: Input
|
|
767
|
+
}], autoplay: [{
|
|
768
|
+
type: Input
|
|
769
|
+
}], interval: [{
|
|
770
|
+
type: Input
|
|
771
|
+
}], loop: [{
|
|
772
|
+
type: Input
|
|
773
|
+
}], showControls: [{
|
|
774
|
+
type: Input
|
|
775
|
+
}], showIndicators: [{
|
|
776
|
+
type: Input
|
|
777
|
+
}], ariaLabel: [{
|
|
778
|
+
type: Input
|
|
779
|
+
}], activeIndexChange: [{
|
|
780
|
+
type: Output
|
|
781
|
+
}] } });
|
|
782
|
+
|
|
783
|
+
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();
|
|
610
1708
|
const month = this.displayMonth.getMonth();
|
|
611
1709
|
const startOfMonth = new Date(year, month, 1);
|
|
612
1710
|
const startDay = startOfMonth.getDay();
|
|
@@ -663,7 +1761,7 @@ class CxsDatepickerComponent {
|
|
|
663
1761
|
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
664
1762
|
multi: true
|
|
665
1763
|
}
|
|
666
|
-
], ngImport: i0, template: "@if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n} @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n
|
|
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 });
|
|
667
1765
|
}
|
|
668
1766
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, decorators: [{
|
|
669
1767
|
type: Component,
|
|
@@ -673,7 +1771,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
673
1771
|
useExisting: forwardRef(() => CxsDatepickerComponent),
|
|
674
1772
|
multi: true
|
|
675
1773
|
}
|
|
676
|
-
], template: "@if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n} @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n
|
|
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" }]
|
|
677
1775
|
}], propDecorators: { value: [{
|
|
678
1776
|
type: Input
|
|
679
1777
|
}], variant: [{
|
|
@@ -716,13 +1814,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
716
1814
|
args: ['document:keydown.escape']
|
|
717
1815
|
}] } });
|
|
718
1816
|
|
|
719
|
-
const BASE_CLASSES$
|
|
1817
|
+
const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
|
|
720
1818
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
721
1819
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
722
1820
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
723
1821
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
724
1822
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
725
|
-
const VARIANT_CLASSES$
|
|
1823
|
+
const VARIANT_CLASSES$2 = {
|
|
726
1824
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
727
1825
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
728
1826
|
};
|
|
@@ -760,9 +1858,9 @@ class CxsInputComponent {
|
|
|
760
1858
|
}
|
|
761
1859
|
get inputClass() {
|
|
762
1860
|
return [
|
|
763
|
-
BASE_CLASSES$
|
|
1861
|
+
BASE_CLASSES$2,
|
|
764
1862
|
SIZE_CLASSES$1[this.size],
|
|
765
|
-
VARIANT_CLASSES$
|
|
1863
|
+
VARIANT_CLASSES$2[this.variant],
|
|
766
1864
|
this.invalid ? INVALID_CLASSES$2 : ''
|
|
767
1865
|
]
|
|
768
1866
|
.filter(Boolean)
|
|
@@ -787,63 +1885,204 @@ class CxsInputComponent {
|
|
|
787
1885
|
this.onChange(nextValue);
|
|
788
1886
|
this.valueChange.emit(nextValue);
|
|
789
1887
|
}
|
|
790
|
-
onBlur() {
|
|
791
|
-
this.onTouched();
|
|
1888
|
+
onBlur() {
|
|
1889
|
+
this.onTouched();
|
|
1890
|
+
}
|
|
1891
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1892
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsInputComponent, isStandalone: true, selector: "cxs-input", inputs: { value: "value", type: "type", variant: "variant", size: "size", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", id: "id", name: "name", placeholder: "placeholder", autocomplete: "autocomplete", inputmode: "inputmode", spellcheck: "spellcheck", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
|
|
1893
|
+
{
|
|
1894
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1895
|
+
useExisting: forwardRef(() => CxsInputComponent),
|
|
1896
|
+
multi: true
|
|
1897
|
+
}
|
|
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 });
|
|
1899
|
+
}
|
|
1900
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, decorators: [{
|
|
1901
|
+
type: Component,
|
|
1902
|
+
args: [{ selector: 'cxs-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1903
|
+
{
|
|
1904
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1905
|
+
useExisting: forwardRef(() => CxsInputComponent),
|
|
1906
|
+
multi: true
|
|
1907
|
+
}
|
|
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" }]
|
|
1909
|
+
}], propDecorators: { value: [{
|
|
1910
|
+
type: Input
|
|
1911
|
+
}], type: [{
|
|
1912
|
+
type: Input
|
|
1913
|
+
}], variant: [{
|
|
1914
|
+
type: Input
|
|
1915
|
+
}], size: [{
|
|
1916
|
+
type: Input
|
|
1917
|
+
}], disabled: [{
|
|
1918
|
+
type: Input
|
|
1919
|
+
}], readonly: [{
|
|
1920
|
+
type: Input
|
|
1921
|
+
}], required: [{
|
|
1922
|
+
type: Input
|
|
1923
|
+
}], invalid: [{
|
|
1924
|
+
type: Input
|
|
1925
|
+
}], autofocus: [{
|
|
1926
|
+
type: Input
|
|
1927
|
+
}], id: [{
|
|
1928
|
+
type: Input
|
|
1929
|
+
}], name: [{
|
|
1930
|
+
type: Input
|
|
1931
|
+
}], placeholder: [{
|
|
1932
|
+
type: Input
|
|
1933
|
+
}], autocomplete: [{
|
|
1934
|
+
type: Input
|
|
1935
|
+
}], inputmode: [{
|
|
1936
|
+
type: Input
|
|
1937
|
+
}], spellcheck: [{
|
|
1938
|
+
type: Input
|
|
1939
|
+
}], ariaLabel: [{
|
|
1940
|
+
type: Input
|
|
1941
|
+
}], ariaDescribedby: [{
|
|
1942
|
+
type: Input
|
|
1943
|
+
}], valueChange: [{
|
|
1944
|
+
type: Output
|
|
1945
|
+
}] } });
|
|
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'));
|
|
792
2061
|
}
|
|
793
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
794
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
795
|
-
{
|
|
796
|
-
provide: NG_VALUE_ACCESSOR,
|
|
797
|
-
useExisting: forwardRef(() => CxsInputComponent),
|
|
798
|
-
multi: true
|
|
799
|
-
}
|
|
800
|
-
], ngImport: i0, template: "<input\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n/>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
801
2064
|
}
|
|
802
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
2065
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMenubarComponent, decorators: [{
|
|
803
2066
|
type: Component,
|
|
804
|
-
args: [{ selector: 'cxs-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
810
|
-
], template: "<input\n [class]=\"inputClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n/>\r\n" }]
|
|
811
|
-
}], propDecorators: { value: [{
|
|
812
|
-
type: Input
|
|
813
|
-
}], type: [{
|
|
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: [{
|
|
814
2072
|
type: Input
|
|
815
|
-
}],
|
|
2073
|
+
}], ariaLabel: [{
|
|
816
2074
|
type: Input
|
|
817
2075
|
}], size: [{
|
|
818
2076
|
type: Input
|
|
819
|
-
}],
|
|
820
|
-
type: Input
|
|
821
|
-
}], readonly: [{
|
|
822
|
-
type: Input
|
|
823
|
-
}], required: [{
|
|
824
|
-
type: Input
|
|
825
|
-
}], invalid: [{
|
|
826
|
-
type: Input
|
|
827
|
-
}], autofocus: [{
|
|
828
|
-
type: Input
|
|
829
|
-
}], id: [{
|
|
830
|
-
type: Input
|
|
831
|
-
}], name: [{
|
|
832
|
-
type: Input
|
|
833
|
-
}], placeholder: [{
|
|
834
|
-
type: Input
|
|
835
|
-
}], autocomplete: [{
|
|
836
|
-
type: Input
|
|
837
|
-
}], inputmode: [{
|
|
838
|
-
type: Input
|
|
839
|
-
}], spellcheck: [{
|
|
840
|
-
type: Input
|
|
841
|
-
}], ariaLabel: [{
|
|
2077
|
+
}], variant: [{
|
|
842
2078
|
type: Input
|
|
843
|
-
}],
|
|
2079
|
+
}], disabled: [{
|
|
844
2080
|
type: Input
|
|
845
|
-
}],
|
|
2081
|
+
}], itemSelected: [{
|
|
846
2082
|
type: Output
|
|
2083
|
+
}], menuItems: [{
|
|
2084
|
+
type: ViewChildren,
|
|
2085
|
+
args: ['menuItem', { read: ElementRef }]
|
|
847
2086
|
}] } });
|
|
848
2087
|
|
|
849
2088
|
const WRAPPER_BASE = 'inline-flex items-center gap-2 select-none';
|
|
@@ -958,7 +2197,7 @@ class CxsRadioComponent {
|
|
|
958
2197
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
959
2198
|
multi: true
|
|
960
2199
|
}
|
|
961
|
-
], ngImport: i0, template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"radio\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.value]=\"value\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n</label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
962
2201
|
}
|
|
963
2202
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsRadioComponent, decorators: [{
|
|
964
2203
|
type: Component,
|
|
@@ -968,7 +2207,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
968
2207
|
useExisting: forwardRef(() => CxsRadioComponent),
|
|
969
2208
|
multi: true
|
|
970
2209
|
}
|
|
971
|
-
], template: "<label [class]=\"wrapperClass\">\n <input\n class=\"peer sr-only\"\n type=\"radio\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.value]=\"value\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span [class]=\"controlClass\" aria-hidden=\"true\"></span>\n <span [class]=\"labelClass\">\n <ng-content></ng-content>\n </span>\n</label>\n" }]
|
|
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" }]
|
|
972
2211
|
}], propDecorators: { value: [{
|
|
973
2212
|
type: Input
|
|
974
2213
|
}], name: [{
|
|
@@ -995,13 +2234,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
995
2234
|
type: Output
|
|
996
2235
|
}] } });
|
|
997
2236
|
|
|
998
|
-
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)] ' +
|
|
999
2238
|
'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
|
|
1000
2239
|
'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
|
|
1001
2240
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
|
|
1002
2241
|
'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
|
|
1003
2242
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
1004
|
-
const VARIANT_CLASSES = {
|
|
2243
|
+
const VARIANT_CLASSES$1 = {
|
|
1005
2244
|
outline: 'bg-[var(--cxs-color-surface)]',
|
|
1006
2245
|
filled: 'bg-[var(--cxs-color-surface-hover)]'
|
|
1007
2246
|
};
|
|
@@ -1034,9 +2273,9 @@ class CxsSelectComponent {
|
|
|
1034
2273
|
}
|
|
1035
2274
|
get selectClass() {
|
|
1036
2275
|
return [
|
|
1037
|
-
BASE_CLASSES,
|
|
2276
|
+
BASE_CLASSES$1,
|
|
1038
2277
|
SIZE_CLASSES[this.size],
|
|
1039
|
-
VARIANT_CLASSES[this.variant],
|
|
2278
|
+
VARIANT_CLASSES$1[this.variant],
|
|
1040
2279
|
this.invalid ? INVALID_CLASSES : ''
|
|
1041
2280
|
]
|
|
1042
2281
|
.filter(Boolean)
|
|
@@ -1077,7 +2316,7 @@ class CxsSelectComponent {
|
|
|
1077
2316
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
1078
2317
|
multi: true
|
|
1079
2318
|
}
|
|
1080
|
-
], ngImport: i0, template: "<div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n</div>\r\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
1081
2320
|
}
|
|
1082
2321
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, decorators: [{
|
|
1083
2322
|
type: Component,
|
|
@@ -1087,7 +2326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1087
2326
|
useExisting: forwardRef(() => CxsSelectComponent),
|
|
1088
2327
|
multi: true
|
|
1089
2328
|
}
|
|
1090
|
-
], template: "<div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n</div>\r\n" }]
|
|
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" }]
|
|
1091
2330
|
}], propDecorators: { value: [{
|
|
1092
2331
|
type: Input
|
|
1093
2332
|
}], variant: [{
|
|
@@ -1116,6 +2355,446 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1116
2355
|
type: Output
|
|
1117
2356
|
}] } });
|
|
1118
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
|
+
|
|
1119
2798
|
const DEFAULT_DARK_CLASS = 'cxs-theme-dark';
|
|
1120
2799
|
class CxsThemeDirective {
|
|
1121
2800
|
host;
|
|
@@ -1223,5 +2902,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1223
2902
|
* Generated bundle index. Do not edit.
|
|
1224
2903
|
*/
|
|
1225
2904
|
|
|
1226
|
-
export { CerxosUi, CxsAlertComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCheckboxComponent, CxsDatepickerComponent, CxsInputComponent, CxsRadioComponent, CxsSelectComponent, CxsThemeDirective };
|
|
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 };
|
|
1227
2906
|
//# sourceMappingURL=cerxos-ui.mjs.map
|