@api-client/ui 0.5.26 → 0.5.28
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/build/src/elements/app-bar/internals/AppBar.d.ts +1 -1
- package/build/src/elements/app-bar/internals/AppBar.d.ts.map +1 -1
- package/build/src/elements/app-bar/internals/AppBar.js +5 -5
- package/build/src/elements/app-bar/internals/AppBar.js.map +1 -1
- package/build/src/elements/currency/internals/Picker.d.ts +2 -2
- package/build/src/elements/currency/internals/Picker.d.ts.map +1 -1
- package/build/src/elements/currency/internals/Picker.js +13 -12
- package/build/src/elements/currency/internals/Picker.js.map +1 -1
- package/build/src/elements/data-table/DataTable.d.ts +1 -3
- package/build/src/elements/data-table/DataTable.d.ts.map +1 -1
- package/build/src/elements/data-table/DataTable.js +2 -4
- package/build/src/elements/data-table/DataTable.js.map +1 -1
- package/build/src/elements/file-system/internals/Breadcrumbs.d.ts +1 -2
- package/build/src/elements/file-system/internals/Breadcrumbs.d.ts.map +1 -1
- package/build/src/elements/file-system/internals/Breadcrumbs.js +2 -3
- package/build/src/elements/file-system/internals/Breadcrumbs.js.map +1 -1
- package/build/src/elements/navigation/internals/NavigationItem.js +1 -1
- package/build/src/elements/navigation/internals/NavigationItem.js.map +1 -1
- package/build/src/md/list/internals/List.d.ts +4 -2
- package/build/src/md/list/internals/List.d.ts.map +1 -1
- package/build/src/md/list/internals/List.js +16 -6
- package/build/src/md/list/internals/List.js.map +1 -1
- package/build/src/md/list/internals/ListItem.d.ts +10 -1
- package/build/src/md/list/internals/ListItem.d.ts.map +1 -1
- package/build/src/md/list/internals/ListItem.js +74 -8
- package/build/src/md/list/internals/ListItem.js.map +1 -1
- package/build/src/md/list/internals/ListItem.styles.d.ts.map +1 -1
- package/build/src/md/list/internals/ListItem.styles.js +38 -28
- package/build/src/md/list/internals/ListItem.styles.js.map +1 -1
- package/build/src/md/menu/internal/MenuItem.js +4 -4
- package/build/src/md/menu/internal/MenuItem.js.map +1 -1
- package/build/src/md/progress/internals/CircularProgress.d.ts +93 -0
- package/build/src/md/progress/internals/CircularProgress.d.ts.map +1 -0
- package/build/src/md/progress/internals/CircularProgress.js +156 -0
- package/build/src/md/progress/internals/CircularProgress.js.map +1 -0
- package/build/src/md/progress/internals/CircularProgress.styles.d.ts +3 -0
- package/build/src/md/progress/internals/CircularProgress.styles.d.ts.map +1 -0
- package/build/src/md/progress/internals/CircularProgress.styles.js +220 -0
- package/build/src/md/progress/internals/CircularProgress.styles.js.map +1 -0
- package/build/src/md/progress/internals/Range.d.ts +6 -0
- package/build/src/md/progress/internals/Range.d.ts.map +1 -1
- package/build/src/md/progress/internals/Range.js +41 -3
- package/build/src/md/progress/internals/Range.js.map +1 -1
- package/build/src/md/progress/internals/UiProgress.d.ts +0 -7
- package/build/src/md/progress/internals/UiProgress.d.ts.map +1 -1
- package/build/src/md/progress/internals/UiProgress.js +2 -36
- package/build/src/md/progress/internals/UiProgress.js.map +1 -1
- package/build/src/md/progress/ui-circular-progress.d.ts +11 -0
- package/build/src/md/progress/ui-circular-progress.d.ts.map +1 -0
- package/build/src/md/progress/ui-circular-progress.js +27 -0
- package/build/src/md/progress/ui-circular-progress.js.map +1 -0
- package/build/src/md/select/internals/Option.js +2 -2
- package/build/src/md/select/internals/Option.js.map +1 -1
- package/build/src/md/select/internals/Option.styles.d.ts.map +1 -1
- package/build/src/md/select/internals/Option.styles.js +0 -127
- package/build/src/md/select/internals/Option.styles.js.map +1 -1
- package/build/src/md/select/internals/Select.d.ts +11 -1
- package/build/src/md/select/internals/Select.d.ts.map +1 -1
- package/build/src/md/select/internals/Select.js +21 -2
- package/build/src/md/select/internals/Select.js.map +1 -1
- package/demo/elements/currency/index.html +2 -2
- package/demo/elements/navigation/navigation-item.html +4 -0
- package/demo/elements/navigation/navigation-item.ts +19 -0
- package/demo/md/list/list.ts +9 -3
- package/demo/md/progress/progress.ts +24 -1
- package/demo/md/select/index.ts +5 -0
- package/demo/md/tabs/tabs.ts +0 -4
- package/package.json +1 -1
- package/src/elements/app-bar/internals/AppBar.ts +5 -5
- package/src/elements/currency/internals/Picker.ts +17 -16
- package/src/elements/data-table/DataTable.ts +2 -4
- package/src/elements/file-system/internals/Breadcrumbs.ts +2 -3
- package/src/elements/navigation/internals/NavigationItem.ts +1 -1
- package/src/md/list/internals/List.ts +19 -8
- package/src/md/list/internals/ListItem.styles.ts +38 -28
- package/src/md/list/internals/ListItem.ts +55 -8
- package/src/md/menu/internal/MenuItem.ts +4 -4
- package/src/md/progress/internals/CircularProgress.styles.ts +220 -0
- package/src/md/progress/internals/CircularProgress.ts +129 -0
- package/src/md/progress/internals/Range.ts +29 -1
- package/src/md/progress/internals/UiProgress.ts +1 -30
- package/src/md/progress/ui-circular-progress.ts +15 -0
- package/src/md/select/internals/Option.styles.ts +0 -127
- package/src/md/select/internals/Option.ts +2 -2
- package/src/md/select/internals/Select.ts +13 -1
- package/test/elements/currency/CurrencyPicker.accessibility.test.ts +14 -14
- package/test/elements/currency/CurrencyPicker.core.test.ts +6 -6
- package/test/elements/currency/CurrencyPicker.integration.test.ts +2 -2
- package/test/elements/currency/CurrencyPicker.test.ts +10 -10
- package/test/elements/data-table/DataTable.browser.test.ts +2 -2
- package/test/md/menu/MenuItem.test.ts +2 -3
- package/test/md/progress/UiCircularProgressElement.test.ts +481 -0
|
@@ -8,10 +8,12 @@ export default css`
|
|
|
8
8
|
cursor: default;
|
|
9
9
|
position: relative;
|
|
10
10
|
|
|
11
|
-
--md-
|
|
12
|
-
|
|
13
|
-
--md-focus-ring-shape-
|
|
14
|
-
--md-focus-ring-shape-
|
|
11
|
+
color: var(--md-sys-color-on-surface);
|
|
12
|
+
|
|
13
|
+
--md-focus-ring-shape-end-end: 8px;
|
|
14
|
+
--md-focus-ring-shape-end-start: 8px;
|
|
15
|
+
--md-focus-ring-shape-start-end: 8px;
|
|
16
|
+
--md-focus-ring-shape-start-start: 8px;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
:host([disabled]) {
|
|
@@ -40,6 +42,8 @@ export default css`
|
|
|
40
42
|
align-items: center;
|
|
41
43
|
overflow: hidden;
|
|
42
44
|
padding: 8px 16px 8px 16px;
|
|
45
|
+
|
|
46
|
+
gap: 16px;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
.ripple {
|
|
@@ -54,8 +58,6 @@ export default css`
|
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
.headline {
|
|
57
|
-
color: var(--md-sys-color-on-surface);
|
|
58
|
-
|
|
59
61
|
font-family: var(--md-sys-typescale-body-large-font);
|
|
60
62
|
font-weight: var(--md-sys-typescale-body-large-weight);
|
|
61
63
|
font-size: var(--md-sys-typescale-body-large-size);
|
|
@@ -92,7 +94,6 @@ export default css`
|
|
|
92
94
|
slot[name='end-text']::slotted(*) {
|
|
93
95
|
/* this is to make up to the 24px right padding defined in the spec. */
|
|
94
96
|
margin-right: 8px;
|
|
95
|
-
margin-left: 16px;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
:host([lines='three']) .supporting-text {
|
|
@@ -124,21 +125,34 @@ export default css`
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
.start {
|
|
128
|
+
display: contents;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.start.has-start {
|
|
127
132
|
align-self: stretch;
|
|
128
133
|
display: flex;
|
|
129
134
|
justify-content: center;
|
|
130
135
|
align-items: center;
|
|
131
136
|
}
|
|
132
137
|
|
|
138
|
+
.end {
|
|
139
|
+
display: contents;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.end.has-end,
|
|
143
|
+
.end.has-end-text {
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 8px;
|
|
147
|
+
}
|
|
148
|
+
|
|
133
149
|
:host slot[name='end']::slotted(*) {
|
|
134
150
|
color: var(--md-sys-color-on-surface-variant);
|
|
135
151
|
fill: var(--md-sys-color-on-surface-variant);
|
|
136
|
-
margin-left: 16px;
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
:host slot[name='start']::slotted(*) {
|
|
140
155
|
display: block;
|
|
141
|
-
margin-right: 16px;
|
|
142
156
|
}
|
|
143
157
|
|
|
144
158
|
:host([image='icon']) slot[name='start']::slotted(*) {
|
|
@@ -168,28 +182,24 @@ export default css`
|
|
|
168
182
|
flex-direction: column;
|
|
169
183
|
}
|
|
170
184
|
|
|
171
|
-
:host(.highlight) .
|
|
172
|
-
background-color: var(--md-sys-color-
|
|
173
|
-
|
|
174
|
-
position: absolute;
|
|
175
|
-
inset: 0;
|
|
176
|
-
z-index: 1;
|
|
185
|
+
:host(.highlight) .surface {
|
|
186
|
+
background-color: var(--md-sys-color-tertiary-container);
|
|
187
|
+
color: var(--md-sys-color-on-tertiary-container);
|
|
177
188
|
}
|
|
178
189
|
|
|
179
|
-
:host(.select) .
|
|
190
|
+
:host(.select) .surface {
|
|
180
191
|
background-color: var(--md-sys-color-secondary-container);
|
|
181
192
|
color: var(--md-sys-color-on-secondary-container);
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
z-index: 1;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
[name='overline'] {
|
|
196
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
197
|
+
font-family: var(--md-sys-typescale-label-small-font, var(--md-ref-typeface-plain, Roboto));
|
|
198
|
+
font-size: var(--md-sys-typescale-label-small-size, 0.6875rem);
|
|
199
|
+
font-weight: var(
|
|
200
|
+
--md-sys-typescale-label-small-weight,
|
|
201
|
+
var(--md-ref-typeface-weight-medium, 500) --md-ref-typeface-weight-medium is not defined
|
|
202
|
+
);
|
|
203
|
+
line-height: var(--md-sys-typescale-label-small-line-height, 1rem);
|
|
194
204
|
}
|
|
195
205
|
`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html, PropertyValues, TemplateResult } from 'lit'
|
|
2
|
-
import { property, query } from 'lit/decorators.js'
|
|
3
|
-
import { classMap } from 'lit/directives/class-map.js'
|
|
2
|
+
import { property, state, query } from 'lit/decorators.js'
|
|
3
|
+
import { classMap, ClassInfo } from 'lit/directives/class-map.js'
|
|
4
4
|
import { UiElement } from '../../UiElement.js'
|
|
5
5
|
import { BeginPressConfig, EndPressConfig } from '../../../controllers/ActionController.js'
|
|
6
6
|
import UiRipple from '../../ripple/internals/ripple.js'
|
|
@@ -25,6 +25,7 @@ export enum ListItemImage {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* @slot
|
|
28
|
+
* @slot overline
|
|
28
29
|
* @slot start
|
|
29
30
|
* @slot end
|
|
30
31
|
* @slot end-text
|
|
@@ -63,6 +64,10 @@ export default class UiListItem extends UiElement {
|
|
|
63
64
|
|
|
64
65
|
@property({ type: Number, reflect: true }) override accessor tabIndex = -1
|
|
65
66
|
|
|
67
|
+
@state() accessor hasStartItem = false
|
|
68
|
+
@state() accessor hasEndItem = false
|
|
69
|
+
@state() accessor hasEndTextItem = false
|
|
70
|
+
|
|
66
71
|
constructor() {
|
|
67
72
|
super()
|
|
68
73
|
|
|
@@ -190,7 +195,33 @@ export default class UiListItem extends UiElement {
|
|
|
190
195
|
this.removeAttribute('tabindex')
|
|
191
196
|
}
|
|
192
197
|
|
|
193
|
-
protected
|
|
198
|
+
protected handleStartSlotChange(): void {
|
|
199
|
+
const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name="start"]')
|
|
200
|
+
if (slot) {
|
|
201
|
+
this.hasStartItem = slot.assignedNodes({ flatten: true }).length > 0
|
|
202
|
+
} else {
|
|
203
|
+
this.hasStartItem = false
|
|
204
|
+
}
|
|
205
|
+
this.requestUpdate()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
protected handleEndSlotChange(): void {
|
|
209
|
+
const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name="end"]')
|
|
210
|
+
if (slot) {
|
|
211
|
+
this.hasEndItem = slot.assignedNodes({ flatten: true }).length > 0
|
|
212
|
+
} else {
|
|
213
|
+
this.hasEndItem = false
|
|
214
|
+
}
|
|
215
|
+
this.requestUpdate()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
protected handleEndTextSlotChange(): void {
|
|
219
|
+
const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name="end-text"]')
|
|
220
|
+
if (slot) {
|
|
221
|
+
this.hasEndTextItem = slot.assignedNodes({ flatten: true }).length > 0
|
|
222
|
+
} else {
|
|
223
|
+
this.hasEndTextItem = false
|
|
224
|
+
}
|
|
194
225
|
this.requestUpdate()
|
|
195
226
|
}
|
|
196
227
|
|
|
@@ -218,16 +249,31 @@ export default class UiListItem extends UiElement {
|
|
|
218
249
|
></md-focus-ring>`
|
|
219
250
|
}
|
|
220
251
|
|
|
252
|
+
protected getStartClasses(): ClassInfo {
|
|
253
|
+
return {
|
|
254
|
+
'start': true,
|
|
255
|
+
'has-start': this.hasStartItem,
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
221
259
|
protected renderStart(): TemplateResult {
|
|
222
|
-
return html`<div class="
|
|
223
|
-
<slot name="start" @slotchange=${this.
|
|
260
|
+
return html`<div class="${classMap(this.getStartClasses())}">
|
|
261
|
+
<slot name="start" @slotchange=${this.handleStartSlotChange}></slot>
|
|
224
262
|
</div>`
|
|
225
263
|
}
|
|
226
264
|
|
|
265
|
+
protected getEndClasses(): ClassInfo {
|
|
266
|
+
return {
|
|
267
|
+
'end': true,
|
|
268
|
+
'has-end': this.hasEndItem,
|
|
269
|
+
'has-end-text': this.hasEndTextItem,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
227
273
|
protected renderEnd(): TemplateResult {
|
|
228
|
-
return html`<div class="
|
|
229
|
-
<slot name="end" @slotchange=${this.
|
|
230
|
-
<
|
|
274
|
+
return html`<div class="${classMap(this.getEndClasses())}">
|
|
275
|
+
<slot name="end" @slotchange=${this.handleEndSlotChange}></slot>
|
|
276
|
+
<slot name="end-text" class="trailing-supporting-text" @slotchange=${this.handleEndTextSlotChange}></slot>
|
|
231
277
|
</div>`
|
|
232
278
|
}
|
|
233
279
|
|
|
@@ -236,6 +282,7 @@ export default class UiListItem extends UiElement {
|
|
|
236
282
|
const hasSupportingText = lines !== ListItemLines.one
|
|
237
283
|
return html`
|
|
238
284
|
<div class="body">
|
|
285
|
+
<slot name="overline"></slot>
|
|
239
286
|
<span class="headline"><slot></slot></span>
|
|
240
287
|
${hasSupportingText ? html`<span class="supporting-text"><slot name="supporting-text"></slot></span>` : ''}
|
|
241
288
|
</div>
|
|
@@ -191,7 +191,7 @@ export default class UiMenuItem extends UiListItem {
|
|
|
191
191
|
this.dispatchEvent(
|
|
192
192
|
new CustomEvent('submenu-open', {
|
|
193
193
|
detail: { subMenu: this.subMenuElement },
|
|
194
|
-
bubbles:
|
|
194
|
+
bubbles: false,
|
|
195
195
|
composed: true,
|
|
196
196
|
})
|
|
197
197
|
)
|
|
@@ -227,7 +227,7 @@ export default class UiMenuItem extends UiListItem {
|
|
|
227
227
|
this.dispatchEvent(
|
|
228
228
|
new CustomEvent('select', {
|
|
229
229
|
detail: e.detail,
|
|
230
|
-
bubbles:
|
|
230
|
+
bubbles: false,
|
|
231
231
|
composed: true,
|
|
232
232
|
})
|
|
233
233
|
)
|
|
@@ -249,7 +249,7 @@ export default class UiMenuItem extends UiListItem {
|
|
|
249
249
|
|
|
250
250
|
protected override renderEnd(): TemplateResult {
|
|
251
251
|
return html`<div class="end">
|
|
252
|
-
<slot name="end" @slotchange=${this.
|
|
252
|
+
<slot name="end" @slotchange=${this.handleEndSlotChange}></slot>
|
|
253
253
|
<span class="trailing-supporting-text"><slot name="end-text"></slot></span>
|
|
254
254
|
${this.hasSubMenu ? html`<ui-icon class="menu-item-arrow">arrow_right</ui-icon>` : ''}
|
|
255
255
|
</div>`
|
|
@@ -260,7 +260,7 @@ export default class UiMenuItem extends UiListItem {
|
|
|
260
260
|
|
|
261
261
|
return html`<div class="start">
|
|
262
262
|
${showCheckIcon ? html`<ui-icon class="selection-check">check</ui-icon>` : ''}
|
|
263
|
-
<slot name="start" @slotchange=${this.
|
|
263
|
+
<slot name="start" @slotchange=${this.handleEndSlotChange}></slot>
|
|
264
264
|
</div>`
|
|
265
265
|
}
|
|
266
266
|
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { css } from 'lit'
|
|
2
|
+
|
|
3
|
+
export default css`
|
|
4
|
+
:host {
|
|
5
|
+
--ui-circular-progress-arc-duration: 1333ms;
|
|
6
|
+
--ui-circular-progress-cycle-duration: calc(4 * var(--ui-circular-progress-arc-duration));
|
|
7
|
+
--ui-circular-progress-linear-rotate-duration: calc(var(--ui-circular-progress-arc-duration) * 360 / 306);
|
|
8
|
+
--ui-circular-progress-indeterminate-easing: cubic-bezier(0.4, 0, 0.2, 1);
|
|
9
|
+
--_container-padding: 4px;
|
|
10
|
+
--_size: var(--ui-circular-progress-size, 48px);
|
|
11
|
+
|
|
12
|
+
--_active-indicator-color: var(--ui-circular-progress-active-indicator-color, var(--md-sys-color-primary));
|
|
13
|
+
--_active-indicator-width: var(--ui-circular-progress-active-indicator-width, 10);
|
|
14
|
+
--_four-color-active-indicator-four-color: var(
|
|
15
|
+
--ui-circular-progress-four-color-active-indicator-four-color,
|
|
16
|
+
var(--md-sys-color-tertiary-container)
|
|
17
|
+
);
|
|
18
|
+
--_four-color-active-indicator-one-color: var(
|
|
19
|
+
--ui-circular-progress-four-color-active-indicator-one-color,
|
|
20
|
+
var(--md-sys-color-primary)
|
|
21
|
+
);
|
|
22
|
+
--_four-color-active-indicator-three-color: var(
|
|
23
|
+
--ui-circular-progress-four-color-active-indicator-three-color,
|
|
24
|
+
var(--md-sys-color-tertiary)
|
|
25
|
+
);
|
|
26
|
+
--_four-color-active-indicator-two-color: var(
|
|
27
|
+
--ui-circular-progress-four-color-active-indicator-two-color,
|
|
28
|
+
var(--md-sys-color-primary-container)
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
vertical-align: middle;
|
|
33
|
+
width: var(--_size);
|
|
34
|
+
height: var(--_size);
|
|
35
|
+
position: relative;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
|
|
39
|
+
contain: strict;
|
|
40
|
+
content-visibility: auto;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.progress,
|
|
44
|
+
.spinner,
|
|
45
|
+
.left,
|
|
46
|
+
.right,
|
|
47
|
+
.circle,
|
|
48
|
+
svg,
|
|
49
|
+
.track,
|
|
50
|
+
.active-track {
|
|
51
|
+
position: absolute;
|
|
52
|
+
inset: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
svg {
|
|
56
|
+
transform: rotate(-90deg);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
circle {
|
|
60
|
+
cx: 50%;
|
|
61
|
+
cy: 50%;
|
|
62
|
+
r: calc(50% * (1 - var(--_active-indicator-width) / 100));
|
|
63
|
+
stroke-width: calc(var(--_active-indicator-width) * 1%);
|
|
64
|
+
stroke-dasharray: 100;
|
|
65
|
+
fill: transparent;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.active-track {
|
|
69
|
+
transition: stroke-dashoffset 500ms cubic-bezier(0, 0, 0.2, 1);
|
|
70
|
+
stroke: var(--_active-indicator-color);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.track {
|
|
74
|
+
stroke: transparent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:host([indeterminate]) {
|
|
78
|
+
animation: linear infinite linear-rotate;
|
|
79
|
+
animation-duration: var(--ui-circular-progress-linear-rotate-duration);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.spinner {
|
|
83
|
+
animation: infinite both rotate-arc;
|
|
84
|
+
animation-duration: var(--ui-circular-progress-cycle-duration);
|
|
85
|
+
animation-timing-function: var(--ui-circular-progress-indeterminate-easing);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.left {
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
inset: 0 50% 0 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.right {
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
inset: 0 0 0 50%;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.circle {
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
border-radius: 50%;
|
|
101
|
+
--_padding-box-width: calc(var(--_size) - 2 * var(--_container-padding));
|
|
102
|
+
--_active-indicator-fraction: calc(var(--_active-indicator-width) / 100);
|
|
103
|
+
border: solid calc(var(--_active-indicator-fraction) * var(--_padding-box-width));
|
|
104
|
+
border-color: var(--_active-indicator-color) var(--_active-indicator-color) transparent transparent;
|
|
105
|
+
animation: expand-arc;
|
|
106
|
+
animation-iteration-count: infinite;
|
|
107
|
+
animation-fill-mode: both;
|
|
108
|
+
animation-duration: var(--ui-circular-progress-arc-duration), var(--ui-circular-progress-cycle-duration);
|
|
109
|
+
animation-timing-function: var(--ui-circular-progress-indeterminate-easing);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.left .circle {
|
|
113
|
+
rotate: 135deg;
|
|
114
|
+
inset: 0 -100% 0 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.right .circle {
|
|
118
|
+
rotate: 100deg;
|
|
119
|
+
inset: 0 0 0 -100%;
|
|
120
|
+
animation-delay: calc(-0.5 * var(--ui-circular-progress-arc-duration)), 0ms;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
:host([fourcolor]) .circle {
|
|
124
|
+
animation-name: expand-arc, four-color;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@keyframes expand-arc {
|
|
128
|
+
0% {
|
|
129
|
+
transform: rotate(265deg);
|
|
130
|
+
}
|
|
131
|
+
50% {
|
|
132
|
+
transform: rotate(130deg);
|
|
133
|
+
}
|
|
134
|
+
100% {
|
|
135
|
+
transform: rotate(265deg);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@keyframes rotate-arc {
|
|
140
|
+
12.5% {
|
|
141
|
+
transform: rotate(135deg);
|
|
142
|
+
}
|
|
143
|
+
25% {
|
|
144
|
+
transform: rotate(270deg);
|
|
145
|
+
}
|
|
146
|
+
37.5% {
|
|
147
|
+
transform: rotate(405deg);
|
|
148
|
+
}
|
|
149
|
+
50% {
|
|
150
|
+
transform: rotate(540deg);
|
|
151
|
+
}
|
|
152
|
+
62.5% {
|
|
153
|
+
transform: rotate(675deg);
|
|
154
|
+
}
|
|
155
|
+
75% {
|
|
156
|
+
transform: rotate(810deg);
|
|
157
|
+
}
|
|
158
|
+
87.5% {
|
|
159
|
+
transform: rotate(945deg);
|
|
160
|
+
}
|
|
161
|
+
100% {
|
|
162
|
+
transform: rotate(1080deg);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@keyframes linear-rotate {
|
|
167
|
+
to {
|
|
168
|
+
transform: rotate(360deg);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@keyframes four-color {
|
|
173
|
+
0% {
|
|
174
|
+
border-top-color: var(--_four-color-active-indicator-one-color);
|
|
175
|
+
border-right-color: var(--_four-color-active-indicator-one-color);
|
|
176
|
+
}
|
|
177
|
+
15% {
|
|
178
|
+
border-top-color: var(--_four-color-active-indicator-one-color);
|
|
179
|
+
border-right-color: var(--_four-color-active-indicator-one-color);
|
|
180
|
+
}
|
|
181
|
+
25% {
|
|
182
|
+
border-top-color: var(--_four-color-active-indicator-two-color);
|
|
183
|
+
border-right-color: var(--_four-color-active-indicator-two-color);
|
|
184
|
+
}
|
|
185
|
+
40% {
|
|
186
|
+
border-top-color: var(--_four-color-active-indicator-two-color);
|
|
187
|
+
border-right-color: var(--_four-color-active-indicator-two-color);
|
|
188
|
+
}
|
|
189
|
+
50% {
|
|
190
|
+
border-top-color: var(--_four-color-active-indicator-three-color);
|
|
191
|
+
border-right-color: var(--_four-color-active-indicator-three-color);
|
|
192
|
+
}
|
|
193
|
+
65% {
|
|
194
|
+
border-top-color: var(--_four-color-active-indicator-three-color);
|
|
195
|
+
border-right-color: var(--_four-color-active-indicator-three-color);
|
|
196
|
+
}
|
|
197
|
+
75% {
|
|
198
|
+
border-top-color: var(--_four-color-active-indicator-four-color);
|
|
199
|
+
border-right-color: var(--_four-color-active-indicator-four-color);
|
|
200
|
+
}
|
|
201
|
+
90% {
|
|
202
|
+
border-top-color: var(--_four-color-active-indicator-four-color);
|
|
203
|
+
border-right-color: var(--_four-color-active-indicator-four-color);
|
|
204
|
+
}
|
|
205
|
+
100% {
|
|
206
|
+
border-top-color: var(--_four-color-active-indicator-one-color);
|
|
207
|
+
border-right-color: var(--_four-color-active-indicator-one-color);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@media (forced-colors: active) {
|
|
212
|
+
.active-track {
|
|
213
|
+
stroke: CanvasText;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.circle {
|
|
217
|
+
border-color: CanvasText CanvasText Canvas Canvas;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
`
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { property } from 'lit/decorators.js'
|
|
2
|
+
import { isDisabled, setDisabled } from '../../../lib/disabled.js'
|
|
3
|
+
import { UiRange } from './Range.js'
|
|
4
|
+
import { type TemplateResult, html } from 'lit'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A circular progress indicator component that displays progress in a circular format.
|
|
8
|
+
*
|
|
9
|
+
* This component supports both determinate and indeterminate progress states:
|
|
10
|
+
* - **Determinate**: Shows a specific progress value with a filled arc
|
|
11
|
+
* - **Indeterminate**: Shows continuous animation without a specific value
|
|
12
|
+
*
|
|
13
|
+
* The component inherits from UiRange and provides additional features like:
|
|
14
|
+
* - Four-color animation for indeterminate state
|
|
15
|
+
* - Material Design 3 styling
|
|
16
|
+
* - Accessibility support with proper ARIA attributes
|
|
17
|
+
* - Customizable size and colors via CSS custom properties
|
|
18
|
+
*
|
|
19
|
+
* ## Accessibility
|
|
20
|
+
*
|
|
21
|
+
* For accessibility compliance, you must provide an accessible name for the progress indicator.
|
|
22
|
+
* Use the `aria-label` attribute to describe what the progress represents:
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```html
|
|
26
|
+
* <!-- Basic determinate progress -->
|
|
27
|
+
* <ui-circular-progress value="50" max="100" aria-label="Upload progress"></ui-circular-progress>
|
|
28
|
+
*
|
|
29
|
+
* <!-- Indeterminate progress -->
|
|
30
|
+
* <ui-circular-progress indeterminate aria-label="Loading content"></ui-circular-progress>
|
|
31
|
+
*
|
|
32
|
+
* <!-- Four-color indeterminate progress -->
|
|
33
|
+
* <ui-circular-progress indeterminate fourcolor aria-label="Processing data"></ui-circular-progress>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @fires ratiochange - Inherited from UiRange. Dispatched when the ratio computation changes.
|
|
37
|
+
*/
|
|
38
|
+
export default class CircularProgress extends UiRange {
|
|
39
|
+
/**
|
|
40
|
+
* Gets the disabled state of the progress indicator.
|
|
41
|
+
* @returns True if the component is disabled, false otherwise.
|
|
42
|
+
*/
|
|
43
|
+
get disabled(): boolean {
|
|
44
|
+
return isDisabled(this)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Sets the disabled state of the progress indicator.
|
|
49
|
+
* When disabled, the component may have reduced visual emphasis
|
|
50
|
+
* and should not respond to user interactions.
|
|
51
|
+
* @attribute
|
|
52
|
+
*/
|
|
53
|
+
@property({ reflect: true, type: Boolean })
|
|
54
|
+
set disabled(value: boolean) {
|
|
55
|
+
const old = isDisabled(this)
|
|
56
|
+
setDisabled(this, value)
|
|
57
|
+
this.requestUpdate('disabled', old)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Enables four-color animation for indeterminate progress indicators.
|
|
62
|
+
*
|
|
63
|
+
* When enabled, the indeterminate progress indicator cycles between four colors:
|
|
64
|
+
* - Primary color (--ui-circular-progress-four-color-active-indicator-one-color)
|
|
65
|
+
* - Primary container (--ui-circular-progress-four-color-active-indicator-two-color)
|
|
66
|
+
* - Tertiary color (--ui-circular-progress-four-color-active-indicator-three-color)
|
|
67
|
+
* - Tertiary container (--ui-circular-progress-four-color-active-indicator-four-color)
|
|
68
|
+
*
|
|
69
|
+
* This property only affects the appearance when `indeterminate` is true.
|
|
70
|
+
*
|
|
71
|
+
* @default false
|
|
72
|
+
* @attribute fourcolor
|
|
73
|
+
*/
|
|
74
|
+
@property({ type: Boolean, reflect: true }) accessor fourColor = false
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Renders the circular progress indicator.
|
|
78
|
+
*
|
|
79
|
+
* Chooses between determinate and indeterminate rendering based on the
|
|
80
|
+
* `indeterminate` property inherited from UiRange.
|
|
81
|
+
*
|
|
82
|
+
* @returns The template result for the progress indicator.
|
|
83
|
+
*/
|
|
84
|
+
protected override render(): TemplateResult {
|
|
85
|
+
if (this.indeterminate) {
|
|
86
|
+
return this.renderIndeterminateContainer()
|
|
87
|
+
}
|
|
88
|
+
return this.renderDeterminateContainer()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Renders the determinate progress indicator using SVG.
|
|
93
|
+
*
|
|
94
|
+
* Creates a circular progress bar that shows a specific progress value
|
|
95
|
+
* using stroke-dashoffset to control the visible portion of the circle.
|
|
96
|
+
* The progress is calculated based on the current value, min, and max properties.
|
|
97
|
+
*
|
|
98
|
+
* @returns SVG template with track and active track circles.
|
|
99
|
+
*/
|
|
100
|
+
private renderDeterminateContainer() {
|
|
101
|
+
const dashOffset = (1 - this.value / this.max) * 100
|
|
102
|
+
return html`
|
|
103
|
+
<svg viewBox="0 0 4800 4800">
|
|
104
|
+
<circle class="track" pathLength="100"></circle>
|
|
105
|
+
<circle class="active-track" pathLength="100" stroke-dashoffset=${dashOffset}></circle>
|
|
106
|
+
</svg>
|
|
107
|
+
`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Renders the indeterminate progress indicator using CSS animations.
|
|
112
|
+
*
|
|
113
|
+
* Creates a spinning animation with two half-circles that expand and contract
|
|
114
|
+
* to create a continuous loading animation. The animation can cycle through
|
|
115
|
+
* multiple colors when the `fourColor` property is enabled.
|
|
116
|
+
*
|
|
117
|
+
* @returns HTML template with animated spinner elements.
|
|
118
|
+
*/
|
|
119
|
+
private renderIndeterminateContainer() {
|
|
120
|
+
return html` <div class="spinner">
|
|
121
|
+
<div class="left">
|
|
122
|
+
<div class="circle"></div>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="right">
|
|
125
|
+
<div class="circle"></div>
|
|
126
|
+
</div>
|
|
127
|
+
</div>`
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -44,10 +44,38 @@ export abstract class UiRange extends UiElement {
|
|
|
44
44
|
*/
|
|
45
45
|
@property({ type: Number, converter: floatConverter }) accessor step = 1
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Use an indeterminate progress indicator.
|
|
49
|
+
* @attribute
|
|
50
|
+
*/
|
|
51
|
+
@property({ reflect: true, type: Boolean }) accessor indeterminate: boolean | undefined
|
|
52
|
+
|
|
53
|
+
override connectedCallback(): void {
|
|
54
|
+
super.connectedCallback()
|
|
55
|
+
if (!this.hasAttribute('role')) {
|
|
56
|
+
this.setAttribute('role', 'progressbar')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
protected override willUpdate(cp: PropertyValues<this>): void {
|
|
48
|
-
if (cp.has('value') || cp.has('min') || cp.has('max') || cp.has('step')) {
|
|
61
|
+
if (cp.has('value') || cp.has('min') || cp.has('max') || cp.has('step') || cp.has('indeterminate')) {
|
|
49
62
|
this.rangeChanged()
|
|
50
63
|
}
|
|
64
|
+
|
|
65
|
+
if (cp.has('min')) {
|
|
66
|
+
this.setAttribute('aria-valuemin', String(this.min))
|
|
67
|
+
}
|
|
68
|
+
if (cp.has('max')) {
|
|
69
|
+
this.setAttribute('aria-valuemax', String(this.max))
|
|
70
|
+
}
|
|
71
|
+
if (cp.has('indeterminate') || cp.has('value')) {
|
|
72
|
+
if (this.indeterminate) {
|
|
73
|
+
this.removeAttribute('aria-valuenow')
|
|
74
|
+
} else {
|
|
75
|
+
this.setAttribute('aria-valuenow', String(this.value))
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
super.willUpdate(cp)
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
protected rangeChanged(): void {
|