@api-client/ui 0.3.3 → 0.3.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/build/src/md/button/internals/base.d.ts.map +1 -1
- package/build/src/md/button/internals/base.js +2 -6
- package/build/src/md/button/internals/base.js.map +1 -1
- package/build/src/md/chip/internals/Chip.d.ts +11 -15
- package/build/src/md/chip/internals/Chip.d.ts.map +1 -1
- package/build/src/md/chip/internals/Chip.js +66 -104
- package/build/src/md/chip/internals/Chip.js.map +1 -1
- package/build/src/md/chip/internals/Chip.styles.d.ts.map +1 -1
- package/build/src/md/chip/internals/Chip.styles.js +114 -101
- package/build/src/md/chip/internals/Chip.styles.js.map +1 -1
- package/build/src/md/chip/internals/ChipSet.d.ts +16 -0
- package/build/src/md/chip/internals/ChipSet.d.ts.map +1 -0
- package/build/src/md/chip/internals/ChipSet.js +138 -0
- package/build/src/md/chip/internals/ChipSet.js.map +1 -0
- package/build/src/md/chip/internals/ChipSet.styles.d.ts +3 -0
- package/build/src/md/chip/internals/ChipSet.styles.d.ts.map +1 -0
- package/build/src/md/chip/internals/ChipSet.styles.js +9 -0
- package/build/src/md/chip/internals/ChipSet.styles.js.map +1 -0
- package/build/src/md/chip/ui-chip-set.d.ts +11 -0
- package/build/src/md/chip/ui-chip-set.d.ts.map +1 -0
- package/build/src/md/chip/ui-chip-set.js +27 -0
- package/build/src/md/chip/ui-chip-set.js.map +1 -0
- package/build/src/md/switch/internals/Switch.styles.js +1 -1
- package/build/src/md/switch/internals/Switch.styles.js.map +1 -1
- package/demo/md/chip/chip.html +33 -6
- package/demo/md/chip/chip.ts +111 -56
- package/package.json +1 -1
- package/src/md/button/internals/base.ts +2 -6
- package/src/md/chip/internals/Chip.styles.ts +114 -101
- package/src/md/chip/internals/Chip.ts +58 -88
- package/src/md/chip/internals/ChipSet.styles.ts +9 -0
- package/src/md/chip/internals/ChipSet.ts +142 -0
- package/src/md/chip/ui-chip-set.ts +15 -0
- package/src/md/switch/internals/Switch.styles.ts +1 -1
- package/test/ui/chip/UiChip.test.ts +18 -67
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { cancelEvent } from '@api-client/core/lib/events/Utils.js'
|
|
2
2
|
import { html, nothing, PropertyValues, TemplateResult } from 'lit'
|
|
3
|
-
import { property,
|
|
3
|
+
import { property, query, state } from 'lit/decorators.js'
|
|
4
4
|
import { classMap } from 'lit/directives/class-map.js'
|
|
5
|
-
import { when } from 'lit/directives/when.js'
|
|
6
5
|
import { UiElement } from '../../UiElement.js'
|
|
7
6
|
import UiRipple from '../../ripple/internals/ripple.js'
|
|
8
|
-
import { ripple } from '../../effects/rippleDirective.js'
|
|
9
7
|
import { close, arrowDropDown, check } from '../../icons/Icons.js'
|
|
10
8
|
import { setDisabled } from '../../../lib/disabled.js'
|
|
11
9
|
import { BeginPressConfig, EndPressConfig } from '../../../controllers/ActionController.js'
|
|
@@ -22,9 +20,9 @@ export enum ChipType {
|
|
|
22
20
|
* @slot The content of the chip.
|
|
23
21
|
* @slot icon - The leading icon, sized 18x18 px
|
|
24
22
|
* @slot avatar - The leading image, sized 24x24 px
|
|
25
|
-
* @fires list - When the user requested to activate the list associated with the element.
|
|
26
23
|
* @fires select - When the checked state changed through a user interaction. This only related to
|
|
27
24
|
* `filter` chips. Note, `select` is dispatched just before the `click` event.
|
|
25
|
+
* @fires remove - When the user clicks the "remove" icon on the chip.
|
|
28
26
|
*/
|
|
29
27
|
export default class UiChip extends UiElement {
|
|
30
28
|
/**
|
|
@@ -51,7 +49,7 @@ export default class UiChip extends UiElement {
|
|
|
51
49
|
* Whether the chip renders the "close" icon at the end.
|
|
52
50
|
* @attribute
|
|
53
51
|
*/
|
|
54
|
-
@property({ type: Boolean, reflect: true }) accessor
|
|
52
|
+
@property({ type: Boolean, reflect: true }) accessor removable: boolean | undefined
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
55
|
* Whether the chip is currently checked.
|
|
@@ -61,17 +59,14 @@ export default class UiChip extends UiElement {
|
|
|
61
59
|
@property({ type: Boolean, reflect: true }) accessor checked: boolean | undefined
|
|
62
60
|
|
|
63
61
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* attributes informing the assistive technology that this chip controls a list.
|
|
62
|
+
* When set, the chip will render a trailing icon that indicates that the chip is associated
|
|
63
|
+
* with a list. It does not do anything.
|
|
67
64
|
*
|
|
68
65
|
* @attribute
|
|
69
66
|
*/
|
|
70
|
-
@property({ type:
|
|
67
|
+
@property({ type: Boolean, reflect: true }) accessor list: boolean | undefined
|
|
71
68
|
|
|
72
|
-
@
|
|
73
|
-
|
|
74
|
-
@state() protected accessor showRipple = false
|
|
69
|
+
@query('ui-ripple') protected accessor ripple!: UiRipple | null
|
|
75
70
|
|
|
76
71
|
/**
|
|
77
72
|
* Determines when the element has an icon in the "icon" slot.
|
|
@@ -93,13 +88,14 @@ export default class UiChip extends UiElement {
|
|
|
93
88
|
|
|
94
89
|
this.actionController.cancelKeyboardEvents = true
|
|
95
90
|
|
|
96
|
-
this.addEventListener('click', this.handleClick.bind(this))
|
|
97
91
|
this.addEventListener('keydown', this.handleKeyDown.bind(this))
|
|
98
92
|
this.addEventListener('keyup', this.handleKeyUp.bind(this))
|
|
93
|
+
this.addEventListener('click', this.handleClick.bind(this))
|
|
99
94
|
this.addEventListener('pointerdown', this.handlePointerDown.bind(this))
|
|
100
95
|
this.addEventListener('pointerup', this.handlePointerUp.bind(this))
|
|
101
96
|
this.addEventListener('pointercancel', this.handlePointerCancel.bind(this))
|
|
102
97
|
this.addEventListener('pointerleave', this.handlePointerLeave.bind(this))
|
|
98
|
+
this.addEventListener('pointerenter', this.handlePointerEnter.bind(this))
|
|
103
99
|
this.addEventListener('contextmenu', this.handleContextMenu.bind(this))
|
|
104
100
|
this.addEventListener('focus', this.handleFocus.bind(this))
|
|
105
101
|
this.addEventListener('blur', this.handleBlur.bind(this))
|
|
@@ -121,52 +117,32 @@ export default class UiChip extends UiElement {
|
|
|
121
117
|
}
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
protected async pressRipple(): Promise<void> {
|
|
125
|
-
const element = await this.getRipple()
|
|
126
|
-
if (element && !element.isPressed) {
|
|
127
|
-
element.beginPress()
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
protected async endRipple(): Promise<void> {
|
|
132
|
-
const element = await this.getRipple()
|
|
133
|
-
element?.endPress()
|
|
134
|
-
}
|
|
135
|
-
|
|
136
120
|
override beginPress(options: BeginPressConfig): void {
|
|
137
121
|
super.beginPress(options)
|
|
138
|
-
this.
|
|
122
|
+
this.classList.add('pressed')
|
|
123
|
+
this.ripple?.beginPress(options.positionEvent)
|
|
139
124
|
}
|
|
140
125
|
|
|
141
126
|
override async handleKeyDown(e: KeyboardEvent): Promise<void> {
|
|
142
127
|
super.handleKeyDown(e)
|
|
143
|
-
if (this.
|
|
128
|
+
if (this.removable && e.code === 'Backspace') {
|
|
144
129
|
e.preventDefault()
|
|
145
|
-
this.
|
|
146
|
-
} else if (this.closable && e.code === 'Backspace') {
|
|
147
|
-
e.preventDefault()
|
|
148
|
-
this.closeAction()
|
|
130
|
+
this.removeAction()
|
|
149
131
|
}
|
|
150
132
|
}
|
|
151
133
|
|
|
152
134
|
protected async handleFocus(): Promise<void> {
|
|
153
|
-
|
|
154
|
-
element?.beginFocus()
|
|
135
|
+
this.ripple?.beginFocus()
|
|
155
136
|
}
|
|
156
137
|
|
|
157
138
|
protected async handleBlur(): Promise<void> {
|
|
158
|
-
|
|
159
|
-
element?.endFocus()
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
protected readonly getRipple = (): Promise<UiRipple | null> => {
|
|
163
|
-
this.showRipple = true
|
|
164
|
-
return this.ripple
|
|
139
|
+
this.ripple?.endFocus()
|
|
165
140
|
}
|
|
166
141
|
|
|
167
142
|
override endPress(info: EndPressConfig): void {
|
|
168
143
|
super.endPress(info)
|
|
169
|
-
this.
|
|
144
|
+
this.classList.remove('pressed')
|
|
145
|
+
this.ripple?.endPress()
|
|
170
146
|
const { cancelled, reason } = info
|
|
171
147
|
if (cancelled) {
|
|
172
148
|
return
|
|
@@ -183,6 +159,16 @@ export default class UiChip extends UiElement {
|
|
|
183
159
|
}
|
|
184
160
|
}
|
|
185
161
|
|
|
162
|
+
override handlePointerEnter(e: PointerEvent): void {
|
|
163
|
+
super.handlePointerEnter(e)
|
|
164
|
+
this.ripple?.beginHover(e)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
override handlePointerLeave(e: PointerEvent): void {
|
|
168
|
+
super.handlePointerLeave(e)
|
|
169
|
+
this.ripple?.endHover()
|
|
170
|
+
}
|
|
171
|
+
|
|
186
172
|
/**
|
|
187
173
|
* Toggles the "filter" type of the chip.
|
|
188
174
|
*/
|
|
@@ -207,47 +193,37 @@ export default class UiChip extends UiElement {
|
|
|
207
193
|
this.hasAvatar = !!slot.assignedNodes().length
|
|
208
194
|
}
|
|
209
195
|
|
|
210
|
-
protected handleListClick(e: Event): void {
|
|
211
|
-
e.preventDefault()
|
|
212
|
-
e.stopPropagation()
|
|
213
|
-
this.listAction()
|
|
214
|
-
}
|
|
215
|
-
|
|
216
196
|
protected handleClose(e: Event): void {
|
|
217
197
|
e.preventDefault()
|
|
218
198
|
e.stopPropagation()
|
|
219
|
-
this.
|
|
199
|
+
this.removeAction()
|
|
220
200
|
}
|
|
221
201
|
|
|
222
|
-
protected async
|
|
223
|
-
this.dispatchEvent(new Event('
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
protected async listAction(): Promise<void> {
|
|
227
|
-
this.dispatchEvent(new Event('list'))
|
|
202
|
+
protected async removeAction(): Promise<void> {
|
|
203
|
+
this.dispatchEvent(new Event('remove'))
|
|
228
204
|
}
|
|
229
205
|
|
|
230
206
|
protected override render(): TemplateResult {
|
|
231
|
-
const { pressed = false } = this
|
|
232
207
|
const containerClasses = classMap({
|
|
233
|
-
surface: true,
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
208
|
+
'surface': true,
|
|
209
|
+
'has-icon': this.hasIcon,
|
|
210
|
+
'has-avatar': this.hasAvatar,
|
|
211
|
+
'has-trailing-icon': this.hasTrailingIcon,
|
|
237
212
|
})
|
|
238
213
|
return html`
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
${
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
<slot></slot>
|
|
245
|
-
${this.renderTrailingIcon()}
|
|
246
|
-
</div>
|
|
214
|
+
${this.renderRipple()}
|
|
215
|
+
<div class="${containerClasses}">
|
|
216
|
+
${this.renderLeadingIcon()} ${this.renderAvatar()}
|
|
217
|
+
<slot></slot>
|
|
218
|
+
${this.renderTrailingIcon()}
|
|
247
219
|
</div>
|
|
248
220
|
`
|
|
249
221
|
}
|
|
250
222
|
|
|
223
|
+
protected renderRipple(): TemplateResult {
|
|
224
|
+
return html`<ui-ripple class="ripple" ?disabled="${this.disabled}"></ui-ripple>`
|
|
225
|
+
}
|
|
226
|
+
|
|
251
227
|
protected renderLeadingIcon(): TemplateResult | typeof nothing {
|
|
252
228
|
const { type } = this
|
|
253
229
|
if (type === ChipType.suggestion) {
|
|
@@ -261,31 +237,19 @@ export default class UiChip extends UiElement {
|
|
|
261
237
|
})
|
|
262
238
|
return html`<span class="${iconClasses}" role="presentation">${check}</span>`
|
|
263
239
|
}
|
|
264
|
-
return html`<slot name="icon" @slotchange="${this.handleIconSlotChange}"></slot>`
|
|
240
|
+
return html`<slot class="leading-icon" name="icon" @slotchange="${this.handleIconSlotChange}"></slot>`
|
|
265
241
|
}
|
|
266
242
|
|
|
267
243
|
protected renderAvatar(): TemplateResult | typeof nothing {
|
|
268
|
-
|
|
269
|
-
if (type === ChipType.input) {
|
|
270
|
-
return html`<slot name="avatar" @slotchange="${this.handleAvatarSlotChange}"></slot>`
|
|
271
|
-
}
|
|
272
|
-
return nothing
|
|
244
|
+
return html`<slot name="avatar" @slotchange="${this.handleAvatarSlotChange}"></slot>`
|
|
273
245
|
}
|
|
274
246
|
|
|
275
247
|
protected renderTrailingIcon(): TemplateResult | typeof nothing {
|
|
276
|
-
const {
|
|
277
|
-
if (type === ChipType.filter) {
|
|
278
|
-
|
|
279
|
-
return html`<span
|
|
280
|
-
class="trailing-icon"
|
|
281
|
-
role="presentation"
|
|
282
|
-
@click="${this.handleListClick}"
|
|
283
|
-
@keypress="${cancelEvent}"
|
|
284
|
-
>${arrowDropDown}</span
|
|
285
|
-
>`
|
|
286
|
-
}
|
|
248
|
+
const { removable = false, list, type } = this
|
|
249
|
+
if (type === ChipType.filter && list) {
|
|
250
|
+
return html`<span class="trailing-icon" role="presentation">${arrowDropDown}</span>`
|
|
287
251
|
}
|
|
288
|
-
if (type === ChipType.input &&
|
|
252
|
+
if (type === ChipType.input && removable) {
|
|
289
253
|
return html`<span
|
|
290
254
|
class="trailing-icon"
|
|
291
255
|
@click="${this.handleClose}"
|
|
@@ -298,8 +262,14 @@ export default class UiChip extends UiElement {
|
|
|
298
262
|
return nothing
|
|
299
263
|
}
|
|
300
264
|
|
|
301
|
-
|
|
302
|
-
const {
|
|
303
|
-
|
|
265
|
+
get hasTrailingIcon(): boolean {
|
|
266
|
+
const { removable = false, list, type } = this
|
|
267
|
+
if (type === ChipType.filter && list) {
|
|
268
|
+
return true
|
|
269
|
+
}
|
|
270
|
+
if (type === ChipType.input && removable) {
|
|
271
|
+
return true
|
|
272
|
+
}
|
|
273
|
+
return false
|
|
304
274
|
}
|
|
305
275
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit'
|
|
2
|
+
import { queryAssignedElements } from 'lit/decorators.js'
|
|
3
|
+
|
|
4
|
+
import Chip from './Chip.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A chip set component.
|
|
8
|
+
*/
|
|
9
|
+
export default class ChipSet extends LitElement {
|
|
10
|
+
get chips() {
|
|
11
|
+
return this.childElements.filter((child): child is Chip => child instanceof Chip)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@queryAssignedElements() private accessor childElements!: HTMLElement[]
|
|
15
|
+
private readonly internals = this.attachInternals()
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
super()
|
|
19
|
+
this.addEventListener('focusin', this.updateTabIndices.bind(this))
|
|
20
|
+
this.addEventListener('update-focus', this.updateTabIndices.bind(this))
|
|
21
|
+
this.addEventListener('keydown', this.handleKeyDown.bind(this))
|
|
22
|
+
this.internals.role = 'toolbar'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override connectedCallback(): void {
|
|
26
|
+
super.connectedCallback()
|
|
27
|
+
if (!this.hasAttribute('role')) {
|
|
28
|
+
this.setAttribute('role', 'toolbar')
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected override render() {
|
|
33
|
+
return html`<slot @slotchange=${this.updateTabIndices}></slot>`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private handleKeyDown(event: KeyboardEvent) {
|
|
37
|
+
const isLeft = event.key === 'ArrowLeft'
|
|
38
|
+
const isRight = event.key === 'ArrowRight'
|
|
39
|
+
const isHome = event.key === 'Home'
|
|
40
|
+
const isEnd = event.key === 'End'
|
|
41
|
+
// Ignore non-navigation keys
|
|
42
|
+
if (!isLeft && !isRight && !isHome && !isEnd) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { chips } = this as { chips: MaybeMultiActionChip[] }
|
|
47
|
+
// Don't try to select another chip if there aren't any.
|
|
48
|
+
if (chips.length < 2) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Prevent default interactions, such as scrolling.
|
|
53
|
+
event.preventDefault()
|
|
54
|
+
|
|
55
|
+
if (isHome || isEnd) {
|
|
56
|
+
const index = isHome ? 0 : chips.length - 1
|
|
57
|
+
chips[index].focus({ trailing: isEnd })
|
|
58
|
+
this.updateTabIndices()
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check if moving forwards or backwards
|
|
63
|
+
const isRtl = getComputedStyle(this).direction === 'rtl'
|
|
64
|
+
const forwards = isRtl ? isLeft : isRight
|
|
65
|
+
const focusedChip = chips.find((chip) => chip.matches(':focus-within'))
|
|
66
|
+
if (!focusedChip) {
|
|
67
|
+
// If there is not already a chip focused, select the first or last chip
|
|
68
|
+
// based on the direction we're traveling.
|
|
69
|
+
const nextChip = forwards ? chips[0] : chips[chips.length - 1]
|
|
70
|
+
nextChip.focus({ trailing: !forwards })
|
|
71
|
+
this.updateTabIndices()
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const currentIndex = chips.indexOf(focusedChip)
|
|
76
|
+
let nextIndex = forwards ? currentIndex + 1 : currentIndex - 1
|
|
77
|
+
// Search for the next sibling that is not disabled to select.
|
|
78
|
+
// If we return to the host index, there is nothing to select.
|
|
79
|
+
while (nextIndex !== currentIndex) {
|
|
80
|
+
if (nextIndex >= chips.length) {
|
|
81
|
+
// Return to start if moving past the last item.
|
|
82
|
+
nextIndex = 0
|
|
83
|
+
} else if (nextIndex < 0) {
|
|
84
|
+
// Go to end if moving before the first item.
|
|
85
|
+
nextIndex = chips.length - 1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check if the next sibling is disabled. If so,
|
|
89
|
+
// move the index and continue searching.
|
|
90
|
+
//
|
|
91
|
+
// Some toolbar items may be focusable when disabled for increased
|
|
92
|
+
// visibility.
|
|
93
|
+
const nextChip = chips[nextIndex]
|
|
94
|
+
if (nextChip.disabled) {
|
|
95
|
+
if (forwards) {
|
|
96
|
+
nextIndex++
|
|
97
|
+
} else {
|
|
98
|
+
nextIndex--
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
nextChip.focus({ trailing: !forwards })
|
|
105
|
+
this.updateTabIndices()
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private updateTabIndices() {
|
|
111
|
+
// The chip that should be focusable is either the chip that currently has
|
|
112
|
+
// focus or the first chip that can be focused.
|
|
113
|
+
const { chips } = this
|
|
114
|
+
let chipToFocus: Chip | undefined
|
|
115
|
+
for (const chip of chips) {
|
|
116
|
+
const isChipFocusable = !chip.disabled
|
|
117
|
+
const chipIsFocused = chip.matches(':focus-within')
|
|
118
|
+
if (chipIsFocused && isChipFocusable) {
|
|
119
|
+
// Found the first chip that is actively focused. This overrides the
|
|
120
|
+
// first focusable chip found.
|
|
121
|
+
chipToFocus = chip
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (isChipFocusable && !chipToFocus) {
|
|
126
|
+
chipToFocus = chip
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Disable non-focused chips. If we disable all of them, we'll grant focus
|
|
130
|
+
// to the first focusable child that was found.
|
|
131
|
+
chip.tabIndex = -1
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (chipToFocus) {
|
|
135
|
+
chipToFocus.tabIndex = 0
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface MaybeMultiActionChip extends Chip {
|
|
141
|
+
focus(options?: FocusOptions & { trailing?: boolean }): void
|
|
142
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CSSResultOrNative } from 'lit'
|
|
2
|
+
import { customElement } from 'lit/decorators.js'
|
|
3
|
+
import Element from './internals/ChipSet.js'
|
|
4
|
+
import styles from './internals/ChipSet.styles.js'
|
|
5
|
+
|
|
6
|
+
@customElement('ui-chip-set')
|
|
7
|
+
export class UiChipSetElement extends Element {
|
|
8
|
+
static override styles: CSSResultOrNative[] = [styles]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare global {
|
|
12
|
+
interface HTMLElementTagNameMap {
|
|
13
|
+
'ui-chip-set': UiChipSetElement
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -35,7 +35,7 @@ export default css`
|
|
|
35
35
|
|
|
36
36
|
border: 2px var(--md-sys-color-outline) solid;
|
|
37
37
|
border-radius: var(--md-sys-shape-corner-extra-large);
|
|
38
|
-
background-color: var(--md-sys-color-surface-
|
|
38
|
+
background-color: var(--md-sys-color-surface-container-highest);
|
|
39
39
|
|
|
40
40
|
transition:
|
|
41
41
|
opacity 90ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
@@ -26,15 +26,6 @@ describe('md', () => {
|
|
|
26
26
|
)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
async function disableIconFixture(): Promise<UiChip> {
|
|
30
|
-
return fixture(
|
|
31
|
-
html`<ui-chip type="assist" disabled>
|
|
32
|
-
<ui-icon slot="icon" icon="add"></ui-icon>
|
|
33
|
-
Disabled with icon
|
|
34
|
-
</ui-chip>`
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
29
|
async function elevatedFixture(): Promise<UiChip> {
|
|
39
30
|
return fixture(html`<ui-chip type="assist" elevated>Elevated</ui-chip>`)
|
|
40
31
|
}
|
|
@@ -45,9 +36,8 @@ describe('md', () => {
|
|
|
45
36
|
|
|
46
37
|
it('renders border around a regular assist chip', async () => {
|
|
47
38
|
const element = await basicFixture()
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const m3Color = styles.getPropertyValue('--md-sys-color-outline')
|
|
39
|
+
const styles = getComputedStyle(element)
|
|
40
|
+
const m3Color = styles.getPropertyValue('--md-sys-color-outline-variant')
|
|
51
41
|
const borderColor = ColorConverter.normalizeColor(styles.borderColor)
|
|
52
42
|
const compareColor = ColorConverter.normalizeColor(m3Color)
|
|
53
43
|
assert.equal(borderColor, compareColor, 'has the m3 color')
|
|
@@ -89,43 +79,28 @@ describe('md', () => {
|
|
|
89
79
|
|
|
90
80
|
it('renders suffix icon', async () => {
|
|
91
81
|
const element = await iconFixture()
|
|
92
|
-
const surface = element.shadowRoot!.querySelector('.surface')
|
|
93
|
-
assert.isTrue(surface.classList.contains('
|
|
94
|
-
const
|
|
95
|
-
const contentStyles = getComputedStyle(content)
|
|
82
|
+
const surface = element.shadowRoot!.querySelector<HTMLDivElement>('.surface')!
|
|
83
|
+
assert.isTrue(surface.classList.contains('has-icon'), 'the surface has the has-icon class')
|
|
84
|
+
const contentStyles = getComputedStyle(surface)
|
|
96
85
|
assert.equal(contentStyles.paddingLeft.trim(), '8px', 'the container has the padding')
|
|
97
86
|
const icon = element.querySelector('ui-icon')!
|
|
98
87
|
const iconStyles = getComputedStyle(icon)
|
|
99
88
|
assert.equal(iconStyles.marginRight.trim(), '8px', 'the icon has the margin')
|
|
100
89
|
})
|
|
101
90
|
|
|
102
|
-
it('has disabled styles when disabled', async () => {
|
|
103
|
-
const element = await disableIconFixture()
|
|
104
|
-
const container = element.shadowRoot!.querySelector('.container') as HTMLDivElement
|
|
105
|
-
const containerStyles = getComputedStyle(container)
|
|
106
|
-
assert.equal(containerStyles.opacity, '0.12', 'container has the opacity')
|
|
107
|
-
const content = element.shadowRoot!.querySelector('.content') as HTMLDivElement
|
|
108
|
-
const contentStyles = getComputedStyle(content)
|
|
109
|
-
assert.equal(contentStyles.opacity, '0.68', 'content has the opacity')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
91
|
it('has elevated styles', async () => {
|
|
113
92
|
const element = await elevatedFixture()
|
|
114
|
-
const
|
|
115
|
-
const containerStyles = getComputedStyle(
|
|
93
|
+
const surface = element.shadowRoot!.querySelector<HTMLDivElement>('.surface')!
|
|
94
|
+
const containerStyles = getComputedStyle(surface)
|
|
116
95
|
assert.equal(containerStyles.borderWidth, '0px', 'has no border')
|
|
117
96
|
assert.isNotEmpty(containerStyles.boxShadow, 'has a box shadow')
|
|
118
97
|
})
|
|
119
98
|
|
|
120
99
|
it('has no elevated styles when disabled', async () => {
|
|
121
100
|
const element = await disabledElevatedFixture()
|
|
122
|
-
const
|
|
123
|
-
const containerStyles = getComputedStyle(
|
|
101
|
+
const surface = element.shadowRoot!.querySelector<HTMLDivElement>('.surface')!
|
|
102
|
+
const containerStyles = getComputedStyle(surface)
|
|
124
103
|
assert.equal(containerStyles.boxShadow, 'none', 'has no box shadow')
|
|
125
|
-
assert.equal(containerStyles.opacity, '0.12', 'container has the opacity')
|
|
126
|
-
const content = element.shadowRoot!.querySelector('.content') as HTMLDivElement
|
|
127
|
-
const contentStyles = getComputedStyle(content)
|
|
128
|
-
assert.equal(contentStyles.opacity, '0.68', 'content has the opacity')
|
|
129
104
|
})
|
|
130
105
|
})
|
|
131
106
|
|
|
@@ -138,19 +113,18 @@ describe('md', () => {
|
|
|
138
113
|
return fixture(html`<ui-chip type="filter" disabled>Disabled</ui-chip>`)
|
|
139
114
|
}
|
|
140
115
|
|
|
141
|
-
async function
|
|
142
|
-
return fixture(html`<ui-chip type="filter"
|
|
116
|
+
async function removableFixture(): Promise<UiChip> {
|
|
117
|
+
return fixture(html`<ui-chip type="filter" removable>removable</ui-chip>`)
|
|
143
118
|
}
|
|
144
119
|
|
|
145
120
|
async function listFixture(): Promise<UiChip> {
|
|
146
|
-
return fixture(html`<ui-chip type="filter" list
|
|
121
|
+
return fixture(html`<ui-chip type="filter" list>List</ui-chip>`)
|
|
147
122
|
}
|
|
148
123
|
|
|
149
|
-
it('renders
|
|
124
|
+
it('renders border around the chip', async () => {
|
|
150
125
|
const element = await basicFixture()
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const m3Color = styles.getPropertyValue('--md-sys-color-outline')
|
|
126
|
+
const styles = getComputedStyle(element)
|
|
127
|
+
const m3Color = styles.getPropertyValue('--md-sys-color-outline-variant')
|
|
154
128
|
const borderColor = ColorConverter.normalizeColor(styles.borderColor)
|
|
155
129
|
const compareColor = ColorConverter.normalizeColor(m3Color)
|
|
156
130
|
assert.equal(borderColor, compareColor, 'has the m3 color')
|
|
@@ -208,7 +182,7 @@ describe('md', () => {
|
|
|
208
182
|
})
|
|
209
183
|
|
|
210
184
|
it('does not render the close icon', async () => {
|
|
211
|
-
const element = await
|
|
185
|
+
const element = await removableFixture()
|
|
212
186
|
const node = element.shadowRoot!.querySelector('.trailing-icon')
|
|
213
187
|
assert.notOk(node)
|
|
214
188
|
})
|
|
@@ -219,36 +193,13 @@ describe('md', () => {
|
|
|
219
193
|
assert.ok(node, 'has the icon')
|
|
220
194
|
})
|
|
221
195
|
|
|
222
|
-
it('dispatches the list event', async () => {
|
|
223
|
-
const element = await listFixture()
|
|
224
|
-
const spy = sinon.spy()
|
|
225
|
-
element.addEventListener('list', spy)
|
|
226
|
-
const node = element.shadowRoot!.querySelector('.trailing-icon') as HTMLElement
|
|
227
|
-
node.click()
|
|
228
|
-
assert.isTrue(spy.calledOnce)
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it('prevents the "click" event when dispatching the "list" event', async () => {
|
|
232
|
-
const element = await listFixture()
|
|
233
|
-
const spy = sinon.spy()
|
|
234
|
-
element.addEventListener('click', spy)
|
|
235
|
-
const node = element.shadowRoot!.querySelector('.trailing-icon') as HTMLElement
|
|
236
|
-
node.click()
|
|
237
|
-
assert.isFalse(spy.called)
|
|
238
|
-
})
|
|
239
|
-
|
|
240
196
|
it('is accessible in a regular state', async () => {
|
|
241
197
|
const element = await basicFixture()
|
|
242
198
|
await assert.isAccessible(element)
|
|
243
199
|
})
|
|
244
200
|
|
|
245
|
-
it('is accessible
|
|
246
|
-
const element = await
|
|
247
|
-
await assert.isAccessible(element)
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
it('is accessible when closable', async () => {
|
|
251
|
-
const element = await closableFixture()
|
|
201
|
+
it('is accessible when removable', async () => {
|
|
202
|
+
const element = await removableFixture()
|
|
252
203
|
await assert.isAccessible(element)
|
|
253
204
|
})
|
|
254
205
|
|