@arclux/arc-ui 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/content/accordion.js +3 -0
- package/src/content/avatar.js +35 -4
- package/src/content/badge.js +6 -0
- package/src/content/callout.js +50 -1
- package/src/content/card.js +16 -5
- package/src/content/divider.js +40 -2
- package/src/content/skeleton.js +20 -9
- package/src/content/stat.js +35 -2
- package/src/content/tag.js +6 -0
- package/src/feedback/alert.js +8 -0
- package/src/feedback/modal.js +19 -4
- package/src/feedback/progress.js +23 -1
- package/src/feedback/toast.js +31 -3
- package/src/input/button.js +26 -3
- package/src/input/checkbox.js +10 -0
- package/src/input/input.js +29 -1
- package/src/input/radio-group.js +10 -0
- package/src/input/select.js +31 -1
- package/src/input/textarea.js +28 -6
- package/src/input/toggle.js +11 -0
- package/src/layout/container.js +16 -4
- package/src/navigation/breadcrumb.js +4 -2
- package/src/navigation/footer.js +9 -1
- package/src/navigation/link.js +15 -4
- package/src/navigation/navigation-menu.js +29 -4
- package/src/navigation/pagination.js +35 -24
- package/src/navigation/sidebar.js +19 -1
- package/src/navigation/tabs.js +30 -1
- package/src/navigation/top-bar.js +9 -1
package/package.json
CHANGED
package/src/content/accordion.js
CHANGED
|
@@ -4,6 +4,7 @@ import './accordion-item.js';
|
|
|
4
4
|
|
|
5
5
|
export class ArcAccordion extends LitElement {
|
|
6
6
|
static properties = {
|
|
7
|
+
multiple: { type: Boolean, reflect: true },
|
|
7
8
|
_items: { state: true },
|
|
8
9
|
_openItems: { state: true },
|
|
9
10
|
};
|
|
@@ -98,6 +99,7 @@ export class ArcAccordion extends LitElement {
|
|
|
98
99
|
|
|
99
100
|
constructor() {
|
|
100
101
|
super();
|
|
102
|
+
this.multiple = false;
|
|
101
103
|
this._items = [];
|
|
102
104
|
this._openItems = new Set();
|
|
103
105
|
}
|
|
@@ -112,6 +114,7 @@ export class ArcAccordion extends LitElement {
|
|
|
112
114
|
if (next.has(index)) {
|
|
113
115
|
next.delete(index);
|
|
114
116
|
} else {
|
|
117
|
+
if (!this.multiple) next.clear();
|
|
115
118
|
next.add(index);
|
|
116
119
|
}
|
|
117
120
|
this._openItems = next;
|
package/src/content/avatar.js
CHANGED
|
@@ -3,15 +3,17 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
3
3
|
|
|
4
4
|
export class ArcAvatar extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
|
-
src:
|
|
7
|
-
name:
|
|
8
|
-
size:
|
|
6
|
+
src: { type: String },
|
|
7
|
+
name: { type: String, reflect: true },
|
|
8
|
+
size: { type: String, reflect: true },
|
|
9
|
+
shape: { type: String, reflect: true },
|
|
10
|
+
status: { type: String, reflect: true },
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
static styles = [
|
|
12
14
|
tokenStyles,
|
|
13
15
|
css`
|
|
14
|
-
:host { display: inline-flex; }
|
|
16
|
+
:host { display: inline-flex; position: relative; }
|
|
15
17
|
|
|
16
18
|
.avatar {
|
|
17
19
|
display: inline-flex;
|
|
@@ -48,10 +50,36 @@ export class ArcAvatar extends LitElement {
|
|
|
48
50
|
user-select: none;
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
/* Shape variants */
|
|
54
|
+
:host([shape="square"]) .avatar,
|
|
55
|
+
:host([shape="square"]) .avatar__img { border-radius: var(--radius-md); }
|
|
56
|
+
:host([shape="rounded"]) .avatar,
|
|
57
|
+
:host([shape="rounded"]) .avatar__img { border-radius: var(--radius-lg); }
|
|
58
|
+
|
|
51
59
|
:host([size="sm"]) .avatar__initials { font-size: var(--text-xs); }
|
|
52
60
|
:host([size="md"]) .avatar__initials { font-size: var(--text-sm); }
|
|
53
61
|
:host([size="lg"]) .avatar__initials { font-size: var(--text-lg); }
|
|
54
62
|
|
|
63
|
+
/* Status indicator */
|
|
64
|
+
.avatar__status {
|
|
65
|
+
position: absolute;
|
|
66
|
+
bottom: 0;
|
|
67
|
+
right: 0;
|
|
68
|
+
width: 10px;
|
|
69
|
+
height: 10px;
|
|
70
|
+
border-radius: var(--radius-full);
|
|
71
|
+
border: 2px solid var(--bg-deep);
|
|
72
|
+
box-sizing: border-box;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
:host([size="sm"]) .avatar__status { width: 8px; height: 8px; }
|
|
76
|
+
:host([size="lg"]) .avatar__status { width: 14px; height: 14px; border-width: 3px; }
|
|
77
|
+
|
|
78
|
+
:host([status="online"]) .avatar__status { background: var(--color-success); }
|
|
79
|
+
:host([status="offline"]) .avatar__status { background: var(--text-ghost); }
|
|
80
|
+
:host([status="busy"]) .avatar__status { background: var(--color-error); }
|
|
81
|
+
:host([status="away"]) .avatar__status { background: var(--color-warning); }
|
|
82
|
+
|
|
55
83
|
@media (prefers-reduced-motion: reduce) {
|
|
56
84
|
:host *,
|
|
57
85
|
:host *::before,
|
|
@@ -69,6 +97,8 @@ export class ArcAvatar extends LitElement {
|
|
|
69
97
|
this.src = '';
|
|
70
98
|
this.name = '';
|
|
71
99
|
this.size = 'md';
|
|
100
|
+
this.shape = 'circle';
|
|
101
|
+
this.status = '';
|
|
72
102
|
}
|
|
73
103
|
|
|
74
104
|
/** @private */
|
|
@@ -85,6 +115,7 @@ export class ArcAvatar extends LitElement {
|
|
|
85
115
|
<div class="avatar" part="avatar" role="img" aria-label=${this.name || 'Avatar'}>
|
|
86
116
|
${content}
|
|
87
117
|
</div>
|
|
118
|
+
${this.status ? html`<span class="avatar__status" part="status" aria-label=${this.status}></span>` : ''}
|
|
88
119
|
`;
|
|
89
120
|
}
|
|
90
121
|
}
|
package/src/content/badge.js
CHANGED
|
@@ -4,6 +4,7 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
4
4
|
export class ArcBadge extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
6
|
variant: { type: String, reflect: true },
|
|
7
|
+
size: { type: String, reflect: true },
|
|
7
8
|
color: { type: String },
|
|
8
9
|
};
|
|
9
10
|
|
|
@@ -74,6 +75,10 @@ export class ArcBadge extends LitElement {
|
|
|
74
75
|
:host([variant="error"]:hover) .badge { box-shadow: 0 0 12px rgba(var(--color-error-rgb), 0.15); }
|
|
75
76
|
:host([variant="info"]:hover) .badge { box-shadow: 0 0 12px rgba(var(--color-info-rgb), 0.15); }
|
|
76
77
|
|
|
78
|
+
/* Sizes */
|
|
79
|
+
:host([size="sm"]) .badge { font-size: calc(var(--text-xs) - 1px); padding: 2px var(--space-xs); }
|
|
80
|
+
:host([size="lg"]) .badge { font-size: var(--text-sm); padding: var(--space-sm) var(--space-md); }
|
|
81
|
+
|
|
77
82
|
@media (prefers-reduced-motion: reduce) {
|
|
78
83
|
:host *,
|
|
79
84
|
:host *::before,
|
|
@@ -89,6 +94,7 @@ export class ArcBadge extends LitElement {
|
|
|
89
94
|
constructor() {
|
|
90
95
|
super();
|
|
91
96
|
this.variant = 'default';
|
|
97
|
+
this.size = 'md';
|
|
92
98
|
this.color = '';
|
|
93
99
|
}
|
|
94
100
|
|
package/src/content/callout.js
CHANGED
|
@@ -5,7 +5,9 @@ import './icon.js';
|
|
|
5
5
|
|
|
6
6
|
export class ArcCallout extends LitElement {
|
|
7
7
|
static properties = {
|
|
8
|
-
variant:
|
|
8
|
+
variant: { type: String, reflect: true },
|
|
9
|
+
dismissible: { type: Boolean, reflect: true },
|
|
10
|
+
_dismissed: { state: true },
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
static styles = [
|
|
@@ -54,6 +56,36 @@ export class ArcCallout extends LitElement {
|
|
|
54
56
|
min-width: 0;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
.callout__dismiss {
|
|
60
|
+
margin-left: auto;
|
|
61
|
+
background: none;
|
|
62
|
+
border: none;
|
|
63
|
+
color: var(--text-muted);
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
padding: var(--space-xs);
|
|
66
|
+
border-radius: var(--radius-sm);
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
opacity: 0.6;
|
|
71
|
+
transition: opacity var(--transition-fast), background var(--transition-fast);
|
|
72
|
+
flex-shrink: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.callout__dismiss:hover {
|
|
76
|
+
opacity: 1;
|
|
77
|
+
background: rgba(var(--_status-rgb), 0.08);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.callout__dismiss:focus-visible {
|
|
81
|
+
outline: none;
|
|
82
|
+
box-shadow: var(--focus-glow);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
:host(.dismissed) {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
57
89
|
@media (prefers-reduced-motion: reduce) {
|
|
58
90
|
:host *,
|
|
59
91
|
:host *::before,
|
|
@@ -69,6 +101,8 @@ export class ArcCallout extends LitElement {
|
|
|
69
101
|
constructor() {
|
|
70
102
|
super();
|
|
71
103
|
this.variant = 'info';
|
|
104
|
+
this.dismissible = false;
|
|
105
|
+
this._dismissed = false;
|
|
72
106
|
}
|
|
73
107
|
|
|
74
108
|
/** @private */
|
|
@@ -93,7 +127,15 @@ export class ArcCallout extends LitElement {
|
|
|
93
127
|
return labels[this.variant] || labels.info;
|
|
94
128
|
}
|
|
95
129
|
|
|
130
|
+
_dismiss() {
|
|
131
|
+
this._dismissed = true;
|
|
132
|
+
this.classList.add('dismissed');
|
|
133
|
+
this.dispatchEvent(new CustomEvent('arc-dismiss', { bubbles: true, composed: true }));
|
|
134
|
+
}
|
|
135
|
+
|
|
96
136
|
render() {
|
|
137
|
+
if (this._dismissed) return html``;
|
|
138
|
+
|
|
97
139
|
return html`
|
|
98
140
|
<div class="callout" part="callout" role="note">
|
|
99
141
|
<div class="callout__header" part="header">
|
|
@@ -101,6 +143,13 @@ export class ArcCallout extends LitElement {
|
|
|
101
143
|
<slot name="icon"><arc-icon name=${this._getDefaultIcon()} size="sm"></arc-icon></slot>
|
|
102
144
|
</span>
|
|
103
145
|
<span class="callout__label" part="label">${this._getLabel()}</span>
|
|
146
|
+
${this.dismissible ? html`
|
|
147
|
+
<button class="callout__dismiss" @click=${this._dismiss} aria-label="Dismiss" part="dismiss">
|
|
148
|
+
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
149
|
+
<path d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"/>
|
|
150
|
+
</svg>
|
|
151
|
+
</button>
|
|
152
|
+
` : ''}
|
|
104
153
|
</div>
|
|
105
154
|
<div class="callout__content" part="content">
|
|
106
155
|
<slot></slot>
|
package/src/content/card.js
CHANGED
|
@@ -4,8 +4,10 @@ import { cardHoverStyles } from '../card-styles.js';
|
|
|
4
4
|
|
|
5
5
|
export class ArcCard extends LitElement {
|
|
6
6
|
static properties = {
|
|
7
|
-
href:
|
|
8
|
-
|
|
7
|
+
href: { type: String },
|
|
8
|
+
padding: { type: String, reflect: true },
|
|
9
|
+
interactive: { type: Boolean, reflect: true },
|
|
10
|
+
_hasFooter: { state: true },
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
static styles = [
|
|
@@ -16,18 +18,25 @@ export class ArcCard extends LitElement {
|
|
|
16
18
|
|
|
17
19
|
.card { height: 100%; }
|
|
18
20
|
|
|
19
|
-
/* Suppress hover effect when no href */
|
|
20
|
-
:host(:not([href])) .card:hover {
|
|
21
|
+
/* Suppress hover effect when no href and not interactive */
|
|
22
|
+
:host(:not([href]):not([interactive])) .card:hover {
|
|
21
23
|
background: var(--border-subtle);
|
|
22
24
|
}
|
|
23
|
-
:host(:not([href])) .card:hover .card__inner {
|
|
25
|
+
:host(:not([href]):not([interactive])) .card:hover .card__inner {
|
|
24
26
|
box-shadow: none;
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
:host([interactive]) .card { cursor: pointer; }
|
|
30
|
+
|
|
27
31
|
.card__inner {
|
|
28
32
|
padding: var(--space-xl) var(--space-lg);
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/* Padding variants */
|
|
36
|
+
:host([padding="none"]) .card__inner { padding: 0; }
|
|
37
|
+
:host([padding="sm"]) .card__inner { padding: var(--space-md) var(--space-sm); }
|
|
38
|
+
:host([padding="lg"]) .card__inner { padding: var(--space-2xl) var(--space-xl); }
|
|
39
|
+
|
|
31
40
|
.card__body {
|
|
32
41
|
flex: 1;
|
|
33
42
|
}
|
|
@@ -59,6 +68,8 @@ export class ArcCard extends LitElement {
|
|
|
59
68
|
constructor() {
|
|
60
69
|
super();
|
|
61
70
|
this.href = '';
|
|
71
|
+
this.padding = 'md';
|
|
72
|
+
this.interactive = false;
|
|
62
73
|
this._hasFooter = false;
|
|
63
74
|
}
|
|
64
75
|
|
package/src/content/divider.js
CHANGED
|
@@ -3,9 +3,10 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
3
3
|
|
|
4
4
|
export class ArcDivider extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
|
-
variant:
|
|
7
|
-
align:
|
|
6
|
+
variant: { type: String, reflect: true },
|
|
7
|
+
align: { type: String, reflect: true },
|
|
8
8
|
vertical: { type: Boolean, reflect: true },
|
|
9
|
+
label: { type: String },
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
static styles = [
|
|
@@ -128,6 +129,33 @@ export class ArcDivider extends LitElement {
|
|
|
128
129
|
background: linear-gradient(180deg, transparent, rgba(var(--text-primary-rgb),0.35), transparent);
|
|
129
130
|
}
|
|
130
131
|
|
|
132
|
+
/* Labeled divider */
|
|
133
|
+
.divider--labeled {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: var(--space-md);
|
|
137
|
+
height: auto;
|
|
138
|
+
background: none !important;
|
|
139
|
+
box-shadow: none !important;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.divider__line {
|
|
143
|
+
flex: 1;
|
|
144
|
+
height: 1px;
|
|
145
|
+
background: var(--gradient-divider);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.divider__label {
|
|
149
|
+
font-family: var(--font-accent);
|
|
150
|
+
font-size: var(--text-xs);
|
|
151
|
+
font-weight: 600;
|
|
152
|
+
letter-spacing: 1.5px;
|
|
153
|
+
text-transform: uppercase;
|
|
154
|
+
color: var(--text-muted);
|
|
155
|
+
white-space: nowrap;
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
131
159
|
@keyframes divider-shimmer {
|
|
132
160
|
0%, 100% { background-position: 200% 0; }
|
|
133
161
|
50% { background-position: -100% 0; }
|
|
@@ -143,9 +171,19 @@ export class ArcDivider extends LitElement {
|
|
|
143
171
|
super();
|
|
144
172
|
this.variant = 'subtle';
|
|
145
173
|
this.vertical = false;
|
|
174
|
+
this.label = '';
|
|
146
175
|
}
|
|
147
176
|
|
|
148
177
|
render() {
|
|
178
|
+
if (this.label && !this.vertical) {
|
|
179
|
+
return html`
|
|
180
|
+
<div class="divider divider--labeled" role="separator" part="divider">
|
|
181
|
+
<span class="divider__line" part="line"></span>
|
|
182
|
+
<span class="divider__label" part="label">${this.label}</span>
|
|
183
|
+
<span class="divider__line" part="line"></span>
|
|
184
|
+
</div>
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
149
187
|
return html`<div class="divider" role="separator" aria-orientation=${this.vertical ? 'vertical' : 'horizontal'} part="divider"></div>`;
|
|
150
188
|
}
|
|
151
189
|
}
|
package/src/content/skeleton.js
CHANGED
|
@@ -6,6 +6,7 @@ export class ArcSkeleton extends LitElement {
|
|
|
6
6
|
variant: { type: String, reflect: true },
|
|
7
7
|
width: { type: String },
|
|
8
8
|
height: { type: String },
|
|
9
|
+
count: { type: Number },
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
static styles = [
|
|
@@ -43,6 +44,12 @@ export class ArcSkeleton extends LitElement {
|
|
|
43
44
|
border-radius: var(--radius-md);
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
.skeleton-group {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: var(--space-sm);
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
@media (prefers-reduced-motion: reduce) {
|
|
47
54
|
:host *,
|
|
48
55
|
:host *::before,
|
|
@@ -60,24 +67,28 @@ export class ArcSkeleton extends LitElement {
|
|
|
60
67
|
this.variant = 'text';
|
|
61
68
|
this.width = '';
|
|
62
69
|
this.height = '';
|
|
70
|
+
this.count = 1;
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
_renderOne() {
|
|
66
74
|
const styles = [
|
|
67
75
|
this.width ? `width:${this.width}` : '',
|
|
68
76
|
this.height ? `height:${this.height}` : '',
|
|
69
77
|
this.variant === 'circle' && !this.height && this.width ? `height:${this.width}` : '',
|
|
70
78
|
].filter(Boolean).join(';');
|
|
71
79
|
|
|
80
|
+
return html`<div class="skeleton" part="skeleton" style=${styles}></div>`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
render() {
|
|
84
|
+
const n = Math.max(1, this.count);
|
|
85
|
+
if (n === 1) {
|
|
86
|
+
return html`<div role="status" aria-label="Loading" aria-busy="true">${this._renderOne()}</div>`;
|
|
87
|
+
}
|
|
72
88
|
return html`
|
|
73
|
-
<div
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
role="status"
|
|
77
|
-
aria-label="Loading"
|
|
78
|
-
aria-busy="true"
|
|
79
|
-
style=${styles}
|
|
80
|
-
></div>
|
|
89
|
+
<div class="skeleton-group" role="status" aria-label="Loading" aria-busy="true">
|
|
90
|
+
${Array.from({ length: n }, () => this._renderOne())}
|
|
91
|
+
</div>
|
|
81
92
|
`;
|
|
82
93
|
}
|
|
83
94
|
}
|
package/src/content/stat.js
CHANGED
|
@@ -3,8 +3,10 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
3
3
|
|
|
4
4
|
export class ArcStat extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
|
-
value:
|
|
7
|
-
label:
|
|
6
|
+
value: { type: String },
|
|
7
|
+
label: { type: String },
|
|
8
|
+
trend: { type: String, reflect: true },
|
|
9
|
+
change: { type: String },
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
static styles = [
|
|
@@ -49,6 +51,25 @@ export class ArcStat extends LitElement {
|
|
|
49
51
|
text-transform: uppercase;
|
|
50
52
|
color: var(--text-muted);
|
|
51
53
|
}
|
|
54
|
+
|
|
55
|
+
.stat__trend {
|
|
56
|
+
display: inline-flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 4px;
|
|
59
|
+
font-family: var(--font-mono);
|
|
60
|
+
font-size: var(--text-sm);
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
margin-top: var(--space-xs);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:host([trend="up"]) .stat__trend { color: var(--color-success); }
|
|
66
|
+
:host([trend="down"]) .stat__trend { color: var(--color-error); }
|
|
67
|
+
:host([trend="neutral"]) .stat__trend { color: var(--text-muted); }
|
|
68
|
+
|
|
69
|
+
.stat__trend-arrow {
|
|
70
|
+
width: 12px;
|
|
71
|
+
height: 12px;
|
|
72
|
+
}
|
|
52
73
|
`,
|
|
53
74
|
];
|
|
54
75
|
|
|
@@ -56,14 +77,26 @@ export class ArcStat extends LitElement {
|
|
|
56
77
|
super();
|
|
57
78
|
this.value = '';
|
|
58
79
|
this.label = '';
|
|
80
|
+
this.trend = '';
|
|
81
|
+
this.change = '';
|
|
59
82
|
}
|
|
60
83
|
|
|
61
84
|
render() {
|
|
85
|
+
const arrowUp = html`<svg class="stat__trend-arrow" viewBox="0 0 16 16" fill="currentColor"><path d="M8 3.5l4.5 5H3.5z"/></svg>`;
|
|
86
|
+
const arrowDown = html`<svg class="stat__trend-arrow" viewBox="0 0 16 16" fill="currentColor"><path d="M8 12.5l4.5-5H3.5z"/></svg>`;
|
|
87
|
+
const dash = html`<svg class="stat__trend-arrow" viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="7" width="10" height="2" rx="1"/></svg>`;
|
|
88
|
+
|
|
62
89
|
return html`
|
|
63
90
|
<div class="stat" part="stat">
|
|
64
91
|
<span class="stat__value" part="value">${this.value}</span>
|
|
65
92
|
<span class="stat__rule"></span>
|
|
66
93
|
<span class="stat__label" part="label">${this.label}</span>
|
|
94
|
+
${this.trend ? html`
|
|
95
|
+
<span class="stat__trend" part="trend">
|
|
96
|
+
${this.trend === 'up' ? arrowUp : this.trend === 'down' ? arrowDown : dash}
|
|
97
|
+
${this.change || ''}
|
|
98
|
+
</span>
|
|
99
|
+
` : ''}
|
|
67
100
|
</div>
|
|
68
101
|
`;
|
|
69
102
|
}
|
package/src/content/tag.js
CHANGED
|
@@ -4,6 +4,7 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
4
4
|
export class ArcTag extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
6
|
variant: { type: String, reflect: true },
|
|
7
|
+
size: { type: String, reflect: true },
|
|
7
8
|
removable: { type: Boolean, reflect: true },
|
|
8
9
|
disabled: { type: Boolean, reflect: true },
|
|
9
10
|
color: { type: String },
|
|
@@ -70,6 +71,10 @@ export class ArcTag extends LitElement {
|
|
|
70
71
|
:host([variant="warning"]) .tag:hover { box-shadow: 0 0 12px rgba(var(--color-warning-rgb), 0.15); }
|
|
71
72
|
:host([variant="danger"]) .tag:hover { box-shadow: 0 0 12px rgba(var(--color-error-rgb), 0.15); }
|
|
72
73
|
|
|
74
|
+
/* Sizes */
|
|
75
|
+
:host([size="sm"]) .tag { font-size: calc(var(--text-xs) - 1px); padding: 2px var(--space-sm); letter-spacing: 1.5px; }
|
|
76
|
+
:host([size="lg"]) .tag { font-size: var(--text-sm); padding: var(--space-sm) var(--space-lg); }
|
|
77
|
+
|
|
73
78
|
.tag__label {
|
|
74
79
|
display: inline-flex;
|
|
75
80
|
align-items: center;
|
|
@@ -118,6 +123,7 @@ export class ArcTag extends LitElement {
|
|
|
118
123
|
constructor() {
|
|
119
124
|
super();
|
|
120
125
|
this.variant = 'default';
|
|
126
|
+
this.size = 'md';
|
|
121
127
|
this.removable = false;
|
|
122
128
|
this.disabled = false;
|
|
123
129
|
this.color = '';
|
package/src/feedback/alert.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getStatusIcon } from '../status-utils.js';
|
|
|
6
6
|
export class ArcAlert extends LitElement {
|
|
7
7
|
static properties = {
|
|
8
8
|
variant: { type: String, reflect: true },
|
|
9
|
+
compact: { type: Boolean, reflect: true },
|
|
9
10
|
dismissible: { type: Boolean },
|
|
10
11
|
heading: { type: String },
|
|
11
12
|
};
|
|
@@ -72,6 +73,12 @@ export class ArcAlert extends LitElement {
|
|
|
72
73
|
color: var(--text-secondary);
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
/* Compact variant */
|
|
77
|
+
:host([compact]) .alert { padding: var(--space-sm) var(--space-md); gap: var(--space-sm); }
|
|
78
|
+
:host([compact]) .alert__icon-wrap { width: 24px; height: 24px; font-size: var(--text-sm); }
|
|
79
|
+
:host([compact]) .alert__heading { font-size: var(--text-sm); margin-bottom: 2px; }
|
|
80
|
+
:host([compact]) .alert__content { font-size: var(--text-xs); }
|
|
81
|
+
|
|
75
82
|
.alert__dismiss {
|
|
76
83
|
position: absolute;
|
|
77
84
|
top: var(--space-sm);
|
|
@@ -116,6 +123,7 @@ export class ArcAlert extends LitElement {
|
|
|
116
123
|
constructor() {
|
|
117
124
|
super();
|
|
118
125
|
this.variant = 'info';
|
|
126
|
+
this.compact = false;
|
|
119
127
|
this.dismissible = false;
|
|
120
128
|
this.heading = '';
|
|
121
129
|
}
|
package/src/feedback/modal.js
CHANGED
|
@@ -3,10 +3,11 @@ import { tokenStyles } from '../shared-styles.js';
|
|
|
3
3
|
|
|
4
4
|
export class ArcModal extends LitElement {
|
|
5
5
|
static properties = {
|
|
6
|
-
open:
|
|
7
|
-
heading:
|
|
8
|
-
size:
|
|
9
|
-
|
|
6
|
+
open: { type: Boolean, reflect: true },
|
|
7
|
+
heading: { type: String },
|
|
8
|
+
size: { type: String, reflect: true },
|
|
9
|
+
fullscreen: { type: Boolean, reflect: true },
|
|
10
|
+
closable: { type: Boolean },
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
static styles = [
|
|
@@ -58,6 +59,19 @@ export class ArcModal extends LitElement {
|
|
|
58
59
|
:host([size="md"]) .modal__dialog { max-width: 560px; }
|
|
59
60
|
:host([size="lg"]) .modal__dialog { max-width: 720px; }
|
|
60
61
|
|
|
62
|
+
:host([fullscreen]) .modal__dialog {
|
|
63
|
+
max-width: none;
|
|
64
|
+
max-height: none;
|
|
65
|
+
width: 100%;
|
|
66
|
+
height: 100%;
|
|
67
|
+
border-radius: 0;
|
|
68
|
+
border: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:host([fullscreen]) .modal__backdrop {
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
.modal__header {
|
|
62
76
|
display: flex;
|
|
63
77
|
align-items: center;
|
|
@@ -127,6 +141,7 @@ export class ArcModal extends LitElement {
|
|
|
127
141
|
this.open = false;
|
|
128
142
|
this.heading = '';
|
|
129
143
|
this.size = 'md';
|
|
144
|
+
this.fullscreen = false;
|
|
130
145
|
this.closable = true;
|
|
131
146
|
this._handleKeydown = this._handleKeydown.bind(this);
|
|
132
147
|
}
|
package/src/feedback/progress.js
CHANGED
|
@@ -7,6 +7,7 @@ export class ArcProgress extends LitElement {
|
|
|
7
7
|
variant: { type: String, reflect: true },
|
|
8
8
|
size: { type: String, reflect: true },
|
|
9
9
|
indeterminate: { type: Boolean, reflect: true },
|
|
10
|
+
showValue: { type: Boolean, attribute: 'show-value', reflect: true },
|
|
10
11
|
label: { type: String },
|
|
11
12
|
};
|
|
12
13
|
|
|
@@ -84,6 +85,19 @@ export class ArcProgress extends LitElement {
|
|
|
84
85
|
animation: spinner-dash 1.4s ease-in-out infinite;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
.progress__header {
|
|
89
|
+
display: flex;
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
align-items: baseline;
|
|
92
|
+
margin-bottom: var(--space-xs);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.progress__value {
|
|
96
|
+
font-family: var(--font-mono);
|
|
97
|
+
font-size: var(--text-xs);
|
|
98
|
+
color: var(--text-muted);
|
|
99
|
+
}
|
|
100
|
+
|
|
87
101
|
@keyframes progress-indeterminate {
|
|
88
102
|
0% { transform: translateX(-100%); }
|
|
89
103
|
100% { transform: translateX(400%); }
|
|
@@ -115,6 +129,7 @@ export class ArcProgress extends LitElement {
|
|
|
115
129
|
this.variant = 'bar';
|
|
116
130
|
this.size = 'md';
|
|
117
131
|
this.indeterminate = false;
|
|
132
|
+
this.showValue = false;
|
|
118
133
|
this.label = '';
|
|
119
134
|
}
|
|
120
135
|
|
|
@@ -143,9 +158,16 @@ export class ArcProgress extends LitElement {
|
|
|
143
158
|
`;
|
|
144
159
|
}
|
|
145
160
|
|
|
161
|
+
const hasHeader = this.label || (this.showValue && !this.indeterminate);
|
|
162
|
+
|
|
146
163
|
return html`
|
|
147
164
|
<div part="progress">
|
|
148
|
-
${
|
|
165
|
+
${hasHeader ? html`
|
|
166
|
+
<div class="progress__header">
|
|
167
|
+
${this.label ? html`<span class="progress__label" style="margin-bottom:0" part="label">${this.label}</span>` : html`<span></span>`}
|
|
168
|
+
${this.showValue && !this.indeterminate ? html`<span class="progress__value" part="value">${clampedValue}%</span>` : ''}
|
|
169
|
+
</div>
|
|
170
|
+
` : ''}
|
|
149
171
|
<div
|
|
150
172
|
class="progress__track"
|
|
151
173
|
role="progressbar"
|
package/src/feedback/toast.js
CHANGED
|
@@ -110,6 +110,26 @@ export class ArcToast extends LitElement {
|
|
|
110
110
|
|
|
111
111
|
.toast__dismiss:hover { color: var(--text-primary); }
|
|
112
112
|
|
|
113
|
+
.toast__action {
|
|
114
|
+
background: none;
|
|
115
|
+
border: none;
|
|
116
|
+
color: var(--_status-color);
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
font-family: var(--font-accent);
|
|
119
|
+
font-size: var(--text-xs);
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
letter-spacing: 1px;
|
|
122
|
+
text-transform: uppercase;
|
|
123
|
+
padding: var(--space-xs) var(--space-sm);
|
|
124
|
+
border-radius: var(--radius-sm);
|
|
125
|
+
transition: background var(--transition-fast);
|
|
126
|
+
white-space: nowrap;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.toast__action:hover {
|
|
130
|
+
background: rgba(var(--_status-rgb), 0.1);
|
|
131
|
+
}
|
|
132
|
+
|
|
113
133
|
.toast.is-exiting {
|
|
114
134
|
animation: toast-out 200ms ease-in forwards;
|
|
115
135
|
}
|
|
@@ -145,16 +165,21 @@ export class ArcToast extends LitElement {
|
|
|
145
165
|
this._counter = 0;
|
|
146
166
|
}
|
|
147
167
|
|
|
148
|
-
show({ message, variant = 'info', duration }) {
|
|
168
|
+
show({ message, variant = 'info', duration, action, actionLabel, persistent = false }) {
|
|
149
169
|
const id = ++this._counter;
|
|
150
170
|
const dur = duration ?? this.duration;
|
|
151
|
-
this._toasts = [...this._toasts, { id, message, variant }];
|
|
171
|
+
this._toasts = [...this._toasts, { id, message, variant, action, actionLabel }];
|
|
152
172
|
|
|
153
|
-
if (dur > 0) {
|
|
173
|
+
if (!persistent && dur > 0) {
|
|
154
174
|
setTimeout(() => this._dismiss(id), dur);
|
|
155
175
|
}
|
|
156
176
|
}
|
|
157
177
|
|
|
178
|
+
_handleAction(toast) {
|
|
179
|
+
if (toast.action) toast.action();
|
|
180
|
+
this._dismiss(toast.id);
|
|
181
|
+
}
|
|
182
|
+
|
|
158
183
|
_dismiss(id) {
|
|
159
184
|
if (!this._toasts.some(t => t.id === id)) return;
|
|
160
185
|
const el = this.shadowRoot.querySelector(`[data-toast-id="${id}"]`);
|
|
@@ -183,6 +208,9 @@ export class ArcToast extends LitElement {
|
|
|
183
208
|
<div class="toast" style=${statusStyle(t.variant)} data-toast-id=${t.id} part="toast">
|
|
184
209
|
<span class="toast__icon" aria-hidden="true">${getStatusIcon(t.variant)}</span>
|
|
185
210
|
<span class="toast__message">${t.message}</span>
|
|
211
|
+
${t.actionLabel ? html`
|
|
212
|
+
<button class="toast__action" @click=${() => this._handleAction(t)} part="action">${t.actionLabel}</button>
|
|
213
|
+
` : ''}
|
|
186
214
|
<button class="toast__dismiss" @click=${() => this._dismiss(t.id)} aria-label="Dismiss">×</button>
|
|
187
215
|
</div>
|
|
188
216
|
`)}
|