@arclux/arc-ui 1.3.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.
@@ -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: { type: String },
7
- label: { type: String },
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
  }
@@ -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 = '';
@@ -1,15 +1,19 @@
1
1
  import { LitElement, html, css } from 'lit';
2
2
  import { tokenStyles } from '../shared-styles.js';
3
+ import { statusVars } from '../status-styles.js';
4
+ import { getStatusIcon } from '../status-utils.js';
3
5
 
4
6
  export class ArcAlert extends LitElement {
5
7
  static properties = {
6
8
  variant: { type: String, reflect: true },
9
+ compact: { type: Boolean, reflect: true },
7
10
  dismissible: { type: Boolean },
8
11
  heading: { type: String },
9
12
  };
10
13
 
11
14
  static styles = [
12
15
  tokenStyles,
16
+ statusVars,
13
17
  css`
14
18
  :host { display: block; }
15
19
 
@@ -32,24 +36,8 @@ export class ArcAlert extends LitElement {
32
36
  left: 0;
33
37
  right: 0;
34
38
  height: 2px;
35
- background: var(--gradient-divider);
36
- }
37
-
38
- :host([variant="info"]) .alert::before {
39
- background: linear-gradient(90deg, transparent, var(--accent-primary), transparent);
40
- box-shadow: 0 0 12px rgba(var(--accent-primary-rgb), 0.15);
41
- }
42
- :host([variant="success"]) .alert::before {
43
- background: linear-gradient(90deg, transparent, var(--color-success), transparent);
44
- box-shadow: 0 0 12px rgba(var(--color-success-rgb), 0.15);
45
- }
46
- :host([variant="warning"]) .alert::before {
47
- background: linear-gradient(90deg, transparent, var(--color-warning), transparent);
48
- box-shadow: 0 0 12px rgba(var(--color-warning-rgb), 0.15);
49
- }
50
- :host([variant="error"]) .alert::before {
51
- background: linear-gradient(90deg, transparent, var(--color-error), transparent);
52
- box-shadow: 0 0 12px rgba(var(--color-error-rgb), 0.15);
39
+ background: linear-gradient(90deg, transparent, var(--_status-color), transparent);
40
+ box-shadow: 0 0 12px rgba(var(--_status-rgb), 0.15);
53
41
  }
54
42
 
55
43
  .alert__icon-wrap {
@@ -62,31 +50,10 @@ export class ArcAlert extends LitElement {
62
50
  border-radius: var(--radius-md);
63
51
  font-size: var(--text-md);
64
52
  transition: box-shadow var(--transition-base);
65
- }
66
-
67
- :host([variant="info"]) .alert__icon-wrap {
68
- background: rgba(var(--accent-primary-rgb), 0.08);
69
- border: 1px solid rgba(var(--accent-primary-rgb), 0.15);
70
- color: var(--accent-primary);
71
- box-shadow: 0 0 16px rgba(var(--accent-primary-rgb), 0.1);
72
- }
73
- :host([variant="success"]) .alert__icon-wrap {
74
- background: rgba(var(--color-success-rgb), 0.08);
75
- border: 1px solid rgba(var(--color-success-rgb), 0.15);
76
- color: var(--color-success);
77
- box-shadow: 0 0 16px rgba(var(--color-success-rgb), 0.1);
78
- }
79
- :host([variant="warning"]) .alert__icon-wrap {
80
- background: rgba(var(--color-warning-rgb), 0.08);
81
- border: 1px solid rgba(var(--color-warning-rgb), 0.15);
82
- color: var(--color-warning);
83
- box-shadow: 0 0 16px rgba(var(--color-warning-rgb), 0.1);
84
- }
85
- :host([variant="error"]) .alert__icon-wrap {
86
- background: rgba(var(--color-error-rgb), 0.08);
87
- border: 1px solid rgba(var(--color-error-rgb), 0.15);
88
- color: var(--color-error);
89
- box-shadow: 0 0 16px rgba(var(--color-error-rgb), 0.1);
53
+ background: rgba(var(--_status-rgb), 0.08);
54
+ border: 1px solid rgba(var(--_status-rgb), 0.15);
55
+ color: var(--_status-color);
56
+ box-shadow: 0 0 16px rgba(var(--_status-rgb), 0.1);
90
57
  }
91
58
 
92
59
  .alert__body { flex: 1; min-width: 0; }
@@ -106,6 +73,12 @@ export class ArcAlert extends LitElement {
106
73
  color: var(--text-secondary);
107
74
  }
108
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
+
109
82
  .alert__dismiss {
110
83
  position: absolute;
111
84
  top: var(--space-sm);
@@ -150,19 +123,11 @@ export class ArcAlert extends LitElement {
150
123
  constructor() {
151
124
  super();
152
125
  this.variant = 'info';
126
+ this.compact = false;
153
127
  this.dismissible = false;
154
128
  this.heading = '';
155
129
  }
156
130
 
157
- _getIcon() {
158
- switch (this.variant) {
159
- case 'success': return '\u2713';
160
- case 'warning': return '\u26A0';
161
- case 'error': return '\u2717';
162
- default: return '\u2139';
163
- }
164
- }
165
-
166
131
  _dismiss() {
167
132
  this.dispatchEvent(new CustomEvent('arc-dismiss', { bubbles: true, composed: true }));
168
133
  this.style.display = 'none';
@@ -171,7 +136,7 @@ export class ArcAlert extends LitElement {
171
136
  render() {
172
137
  return html`
173
138
  <div class="alert" role="alert" part="alert">
174
- <div class="alert__icon-wrap" part="icon">${this._getIcon()}</div>
139
+ <div class="alert__icon-wrap" part="icon">${getStatusIcon(this.variant)}</div>
175
140
  <div class="alert__body">
176
141
  ${this.heading ? html`<p class="alert__heading" part="heading">${this.heading}</p>` : ''}
177
142
  <div class="alert__content" part="content"><slot></slot></div>
@@ -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: { type: Boolean, reflect: true },
7
- heading: { type: String },
8
- size: { type: String, reflect: true },
9
- closable: { type: Boolean },
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
  }
@@ -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
- ${this.label ? html`<span class="progress__label" part="label">${this.label}</span>` : ''}
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"
@@ -1,5 +1,18 @@
1
1
  import { LitElement, html, css } from 'lit';
2
2
  import { tokenStyles } from '../shared-styles.js';
3
+ import { getStatusIcon } from '../status-utils.js';
4
+
5
+ /** Returns inline style string setting --_status-color/rgb for a given variant */
6
+ function statusStyle(variant) {
7
+ const map = {
8
+ info: { color: 'var(--accent-primary)', rgb: 'var(--accent-primary-rgb)' },
9
+ success: { color: 'var(--color-success)', rgb: 'var(--color-success-rgb)' },
10
+ warning: { color: 'var(--color-warning)', rgb: 'var(--color-warning-rgb)' },
11
+ error: { color: 'var(--color-error)', rgb: 'var(--color-error-rgb)' },
12
+ };
13
+ const v = map[variant] || map.info;
14
+ return `--_status-color:${v.color};--_status-rgb:${v.rgb}`;
15
+ }
3
16
 
4
17
  export class ArcToast extends LitElement {
5
18
  static properties = {
@@ -71,33 +84,16 @@ export class ArcToast extends LitElement {
71
84
  left: 0;
72
85
  right: 0;
73
86
  height: 2px;
74
- background: var(--gradient-divider);
75
- }
76
-
77
- .toast--info::after {
78
- background: linear-gradient(90deg, transparent, var(--accent-primary), transparent);
79
- }
80
- .toast--success::after {
81
- background: linear-gradient(90deg, transparent, var(--color-success), transparent);
82
- }
83
- .toast--warning::after {
84
- background: linear-gradient(90deg, transparent, var(--color-warning), transparent);
85
- }
86
- .toast--error::after {
87
- background: linear-gradient(90deg, transparent, var(--color-error), transparent);
87
+ background: linear-gradient(90deg, transparent, var(--_status-color), transparent);
88
88
  }
89
89
 
90
90
  .toast__icon {
91
91
  font-size: var(--text-sm);
92
92
  flex-shrink: 0;
93
93
  line-height: 1;
94
+ color: var(--_status-color);
94
95
  }
95
96
 
96
- .toast--info .toast__icon { color: var(--accent-primary); }
97
- .toast--success .toast__icon { color: var(--color-success); }
98
- .toast--warning .toast__icon { color: var(--color-warning); }
99
- .toast--error .toast__icon { color: var(--color-error); }
100
-
101
97
  .toast__message { flex: 1; }
102
98
 
103
99
  .toast__dismiss {
@@ -114,6 +110,26 @@ export class ArcToast extends LitElement {
114
110
 
115
111
  .toast__dismiss:hover { color: var(--text-primary); }
116
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
+
117
133
  .toast.is-exiting {
118
134
  animation: toast-out 200ms ease-in forwards;
119
135
  }
@@ -149,25 +165,21 @@ export class ArcToast extends LitElement {
149
165
  this._counter = 0;
150
166
  }
151
167
 
152
- _getIcon(variant) {
153
- switch (variant) {
154
- case 'success': return '\u2713';
155
- case 'warning': return '\u26A0';
156
- case 'error': return '\u2717';
157
- default: return '\u2139';
158
- }
159
- }
160
-
161
- show({ message, variant = 'info', duration }) {
168
+ show({ message, variant = 'info', duration, action, actionLabel, persistent = false }) {
162
169
  const id = ++this._counter;
163
170
  const dur = duration ?? this.duration;
164
- this._toasts = [...this._toasts, { id, message, variant }];
171
+ this._toasts = [...this._toasts, { id, message, variant, action, actionLabel }];
165
172
 
166
- if (dur > 0) {
173
+ if (!persistent && dur > 0) {
167
174
  setTimeout(() => this._dismiss(id), dur);
168
175
  }
169
176
  }
170
177
 
178
+ _handleAction(toast) {
179
+ if (toast.action) toast.action();
180
+ this._dismiss(toast.id);
181
+ }
182
+
171
183
  _dismiss(id) {
172
184
  if (!this._toasts.some(t => t.id === id)) return;
173
185
  const el = this.shadowRoot.querySelector(`[data-toast-id="${id}"]`);
@@ -193,9 +205,12 @@ export class ArcToast extends LitElement {
193
205
  return html`
194
206
  <div class="toast-container" role="status" aria-live="polite" aria-atomic="false" part="container">
195
207
  ${this._toasts.map(t => html`
196
- <div class="toast toast--${t.variant}" data-toast-id=${t.id} part="toast">
197
- <span class="toast__icon" aria-hidden="true">${this._getIcon(t.variant)}</span>
208
+ <div class="toast" style=${statusStyle(t.variant)} data-toast-id=${t.id} part="toast">
209
+ <span class="toast__icon" aria-hidden="true">${getStatusIcon(t.variant)}</span>
198
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
+ ` : ''}
199
214
  <button class="toast__dismiss" @click=${() => this._dismiss(t.id)} aria-label="Dismiss">&times;</button>
200
215
  </div>
201
216
  `)}
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from 'lit';
2
2
  import { tokenStyles } from '../shared-styles.js';
3
+ import { buttonVariantStyles } from '../button-styles.js';
3
4
 
4
5
  export class ArcButton extends LitElement {
5
6
  static properties = {
@@ -7,6 +8,7 @@ export class ArcButton extends LitElement {
7
8
  size: { type: String, reflect: true },
8
9
  href: { type: String },
9
10
  disabled: { type: Boolean, reflect: true },
11
+ loading: { type: Boolean, reflect: true },
10
12
  type: { type: String },
11
13
  _hasPrefix: { state: true },
12
14
  _hasSuffix: { state: true },
@@ -14,9 +16,30 @@ export class ArcButton extends LitElement {
14
16
 
15
17
  static styles = [
16
18
  tokenStyles,
19
+ buttonVariantStyles,
17
20
  css`
18
21
  :host { display: inline-flex; }
19
- :host([disabled]) { pointer-events: none; }
22
+ :host([disabled]),
23
+ :host([loading]) { pointer-events: none; }
24
+
25
+ :host([loading]) .btn { opacity: 0.7; }
26
+
27
+ .btn__spinner {
28
+ display: none;
29
+ width: 14px;
30
+ height: 14px;
31
+ border: 2px solid currentColor;
32
+ border-top-color: transparent;
33
+ border-radius: var(--radius-full);
34
+ animation: arc-btn-spin 600ms linear infinite;
35
+ }
36
+
37
+ :host([loading]) .btn__spinner { display: inline-block; }
38
+ :host([loading]) .btn__label { opacity: 0.6; }
39
+
40
+ @keyframes arc-btn-spin {
41
+ to { transform: rotate(360deg); }
42
+ }
20
43
 
21
44
  .btn {
22
45
  display: inline-flex;
@@ -48,55 +71,26 @@ export class ArcButton extends LitElement {
48
71
  :host([size="md"]) .btn { font-size: var(--text-xs); padding: var(--space-sm) var(--space-lg); }
49
72
  :host([size="lg"]) .btn { font-size: var(--text-xs); padding: var(--space-md) var(--space-xl); letter-spacing: 3px; }
50
73
 
51
- /* Primary */
52
- :host(:not([variant])) .btn,
53
- :host([variant="primary"]) .btn {
74
+ /* Default → primary */
75
+ :host(:not([variant])) .btn {
54
76
  background: var(--accent-primary);
55
77
  color: var(--bg-deep);
56
78
  border-color: var(--accent-primary);
57
79
  }
58
- :host(:not([variant])) .btn:hover,
59
- :host([variant="primary"]) .btn:hover { box-shadow: var(--glow-primary); }
80
+ :host(:not([variant])) .btn:hover { box-shadow: var(--glow-primary); }
81
+
82
+ /* :active scale */
60
83
  :host(:not([variant])) .btn:active,
61
84
  :host([variant="primary"]) .btn:active { transform: scale(0.97); box-shadow: 0 0 8px rgba(var(--accent-primary-rgb),0.5); }
62
-
63
- /* Secondary */
64
- :host([variant="secondary"]) .btn {
65
- background: transparent;
66
- color: var(--text-primary);
67
- border-color: var(--border-default);
68
- }
69
- :host([variant="secondary"]) .btn:hover {
70
- border-color: var(--accent-primary);
71
- color: var(--accent-primary);
72
- box-shadow: 0 0 20px var(--accent-primary-ring);
73
- }
74
85
  :host([variant="secondary"]) .btn:active {
75
86
  transform: scale(0.97);
76
87
  background: rgba(var(--accent-primary-rgb),0.05);
77
88
  }
78
-
79
- /* Ghost */
80
- :host([variant="ghost"]) .btn {
81
- background: transparent;
82
- color: var(--text-muted);
83
- border-color: transparent;
84
- }
85
- :host([variant="ghost"]) .btn:hover {
86
- color: var(--text-primary);
87
- background: var(--bg-hover);
88
- }
89
89
  :host([variant="ghost"]) .btn:active {
90
90
  transform: scale(0.97);
91
91
  background: var(--bg-elevated);
92
92
  }
93
93
 
94
- /* Focus */
95
- .btn:focus-visible { outline: none; box-shadow: var(--focus-glow); }
96
-
97
- /* Disabled */
98
- :host([disabled]) .btn { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
99
-
100
94
  /* Prefix / Suffix */
101
95
  .btn__prefix,
102
96
  .btn__suffix {
@@ -130,6 +124,7 @@ export class ArcButton extends LitElement {
130
124
  this.size = 'md';
131
125
  this.href = '';
132
126
  this.disabled = false;
127
+ this.loading = false;
133
128
  this.type = 'button';
134
129
  this._hasPrefix = false;
135
130
  this._hasSuffix = false;
@@ -145,10 +140,11 @@ export class ArcButton extends LitElement {
145
140
 
146
141
  _renderContent() {
147
142
  return html`
143
+ ${this.loading ? html`<span class="btn__spinner" aria-hidden="true"></span>` : ''}
148
144
  <span class="btn__prefix ${this._hasPrefix ? '' : 'btn__prefix--empty'}">
149
145
  <slot name="prefix" @slotchange=${this._onPrefixSlotChange}></slot>
150
146
  </span>
151
- <slot></slot>
147
+ <span class="btn__label"><slot></slot></span>
152
148
  <span class="btn__suffix ${this._hasSuffix ? '' : 'btn__suffix--empty'}">
153
149
  <slot name="suffix" @slotchange=${this._onSuffixSlotChange}></slot>
154
150
  </span>
@@ -159,7 +155,7 @@ export class ArcButton extends LitElement {
159
155
  if (this.href) {
160
156
  return html`<a class="btn" href=${this.href} part="button">${this._renderContent()}</a>`;
161
157
  }
162
- return html`<button class="btn" type=${this.type} ?disabled=${this.disabled} part="button">${this._renderContent()}</button>`;
158
+ return html`<button class="btn" type=${this.type} ?disabled=${this.disabled || this.loading} aria-busy=${this.loading ? 'true' : 'false'} part="button">${this._renderContent()}</button>`;
163
159
  }
164
160
  }
165
161
 
@@ -8,6 +8,7 @@ export class ArcCheckbox extends LitElement {
8
8
  checked: { type: Boolean, reflect: true },
9
9
  indeterminate: { type: Boolean, reflect: true },
10
10
  disabled: { type: Boolean, reflect: true },
11
+ size: { type: String, reflect: true },
11
12
  label: { type: String },
12
13
  name: { type: String },
13
14
  value: { type: String },
@@ -77,6 +78,14 @@ export class ArcCheckbox extends LitElement {
77
78
  user-select: none;
78
79
  }
79
80
 
81
+ /* Sizes */
82
+ :host([size="sm"]) .checkbox__box { width: 14px; height: 14px; }
83
+ :host([size="sm"]) .checkbox__icon { width: 10px; height: 10px; }
84
+ :host([size="sm"]) .checkbox__label { font-size: var(--text-sm); }
85
+ :host([size="lg"]) .checkbox__box { width: 22px; height: 22px; }
86
+ :host([size="lg"]) .checkbox__icon { width: 14px; height: 14px; }
87
+ :host([size="lg"]) .checkbox__label { font-size: var(--text-md); }
88
+
80
89
  .checkbox__box:focus-visible {
81
90
  outline: none;
82
91
  box-shadow: var(--focus-glow);
@@ -100,6 +109,7 @@ export class ArcCheckbox extends LitElement {
100
109
  this.checked = false;
101
110
  this.indeterminate = false;
102
111
  this.disabled = false;
112
+ this.size = 'md';
103
113
  this.label = '';
104
114
  this.name = '';
105
115
  this.value = '';