@redvars/peacock 3.6.1 → 3.6.3
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/dist/assets/components.css.map +1 -1
- package/dist/assets/styles.css +1 -1
- package/dist/assets/styles.css.map +1 -1
- package/dist/assets/tokens.css +1 -1
- package/dist/assets/tokens.css.map +1 -1
- package/dist/{button-colors-Ccys3hvS.js → button-colors-Cg6oxiz-.js} +126 -116
- package/dist/{button-colors-Ccys3hvS.js.map → button-colors-Cg6oxiz-.js.map} +1 -1
- package/dist/button-group.js +2 -2
- package/dist/button.js +18 -16
- package/dist/button.js.map +1 -1
- package/dist/canvas.js +126 -107
- package/dist/canvas.js.map +1 -1
- package/dist/card.js +1 -1
- package/dist/card.js.map +1 -1
- package/dist/code-highlighter.js +34 -9
- package/dist/code-highlighter.js.map +1 -1
- package/dist/custom-elements-jsdocs.json +4306 -3215
- package/dist/custom-elements.json +8344 -7173
- package/dist/{flow-designer-node-BWrPuxAR.js → flow-designer-node-9Bqyn6qx.js} +2 -1
- package/dist/flow-designer-node-9Bqyn6qx.js.map +1 -0
- package/dist/flow-designer-node.js +1 -1
- package/dist/flow-designer.js +1402 -8
- package/dist/flow-designer.js.map +1 -1
- package/dist/icon-CueRR7wx.js +260 -0
- package/dist/icon-CueRR7wx.js.map +1 -0
- package/dist/{icon-button-CK1ZuE-2.js → icon-button-AdJBEoNy.js} +34 -30
- package/dist/icon-button-AdJBEoNy.js.map +1 -0
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/modal.js +11 -11
- package/dist/modal.js.map +1 -1
- package/dist/{navigation-rail-DTTkqohi.js → navigation-rail-DAUuJ_Yp.js} +975 -486
- package/dist/navigation-rail-DAUuJ_Yp.js.map +1 -0
- package/dist/peacock-loader.js +33 -30
- package/dist/peacock-loader.js.map +1 -1
- package/dist/{popover-NC7b1lTq.js → popover-DUPmMVWS.js} +9 -4
- package/dist/{popover-NC7b1lTq.js.map → popover-DUPmMVWS.js.map} +1 -1
- package/dist/popover-content.js +1 -1
- package/dist/popover-content.js.map +1 -1
- package/dist/popover.js +1 -1
- package/dist/search.js +11 -14
- package/dist/search.js.map +1 -1
- package/dist/src/__controllers/floating-controller.d.ts +1 -0
- package/dist/src/avatar/avatar.d.ts +1 -1
- package/dist/src/breadcrumb/breadcrumb/breadcrumb.d.ts +0 -1
- package/dist/src/canvas/canvas.d.ts +3 -3
- package/dist/src/chip/chip/chip.d.ts +14 -11
- package/dist/src/chip/chip-set/chip-set.d.ts +20 -0
- package/dist/src/chip/chip-set/index.d.ts +1 -0
- package/dist/src/code-highlighter/code-highlighter.d.ts +4 -0
- package/dist/src/field/field.d.ts +1 -0
- package/dist/src/flow-designer/flow-designer-node.d.ts +1 -0
- package/dist/src/image/image.d.ts +2 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/input/input.d.ts +1 -3
- package/dist/src/item/index.d.ts +1 -0
- package/dist/src/item/item.d.ts +48 -0
- package/dist/src/menu/menu/menu.d.ts +1 -0
- package/dist/src/menu/menu-item/menu-item.d.ts +8 -9
- package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -0
- package/dist/src/modal/modal.d.ts +1 -1
- package/dist/src/navigation-rail/navigation-rail.d.ts +2 -6
- package/dist/src/popover/popover-content.d.ts +1 -1
- package/dist/src/search/search.d.ts +2 -6
- package/dist/test/chip.test.d.ts +1 -0
- package/dist/test/item.test.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/readme.md +2 -2
- package/scss/mixin.scss +23 -0
- package/scss/styles.scss +3 -3
- package/scss/tokens.css +1 -1
- package/src/__controllers/floating-controller.ts +9 -3
- package/src/avatar/avatar.scss +4 -4
- package/src/avatar/avatar.ts +1 -1
- package/src/breadcrumb/breadcrumb/breadcrumb.ts +0 -1
- package/src/button/button/button-sizes.scss +11 -11
- package/src/button/button/button.scss +96 -122
- package/src/button/button/button.ts +38 -36
- package/src/button/icon-button/icon-button-sizes.scss +8 -8
- package/src/button/icon-button/icon-button.ts +23 -20
- package/src/canvas/canvas.scss +18 -6
- package/src/canvas/canvas.ts +125 -103
- package/src/card/card.ts +1 -1
- package/src/chip/chip/chip.scss +120 -46
- package/src/chip/chip/chip.ts +97 -38
- package/src/chip/chip-set/chip-set.scss +13 -0
- package/src/chip/chip-set/chip-set.ts +25 -0
- package/src/chip/chip-set/index.ts +1 -0
- package/src/code-highlighter/code-highlighter.ts +33 -6
- package/src/empty-state/empty-state.scss +1 -0
- package/src/field/field.scss +1 -1
- package/src/field/field.ts +6 -0
- package/src/flow-designer/flow-designer-node.ts +1 -0
- package/src/image/image.scss +21 -16
- package/src/image/image.ts +13 -14
- package/src/index.ts +2 -0
- package/src/input/input.ts +16 -25
- package/src/item/index.ts +1 -0
- package/src/item/item.scss +184 -0
- package/src/item/item.ts +340 -0
- package/src/menu/menu/menu.ts +16 -9
- package/src/menu/menu-item/menu-item.scss +30 -108
- package/src/menu/menu-item/menu-item.ts +89 -129
- package/src/menu/sub-menu/sub-menu.ts +6 -2
- package/src/modal/modal.scss +10 -10
- package/src/modal/modal.ts +1 -1
- package/src/navigation-rail/navigation-rail.ts +2 -6
- package/src/peacock-loader.ts +28 -22
- package/src/popover/popover-content.ts +1 -1
- package/src/search/search.ts +11 -16
- package/src/select/option.ts +1 -1
- package/src/select/select.scss +1 -10
- package/src/select/select.ts +2 -0
- package/dist/flow-designer-DvTUrDp5.js +0 -1656
- package/dist/flow-designer-DvTUrDp5.js.map +0 -1
- package/dist/flow-designer-node-BWrPuxAR.js.map +0 -1
- package/dist/icon-button-CK1ZuE-2.js.map +0 -1
- package/dist/navigation-rail-DTTkqohi.js.map +0 -1
- package/src/chip/chip/chip-colors.scss +0 -31
package/src/image/image.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, html } from 'lit';
|
|
2
|
-
import { property, state } from 'lit/decorators.js';
|
|
2
|
+
import { property, query, state } from 'lit/decorators.js';
|
|
3
3
|
|
|
4
4
|
import { isDarkMode } from '@/__utils/is-dark-mode.js';
|
|
5
5
|
import { observeThemeChange } from '@/__utils/observe-theme-change.js';
|
|
@@ -37,7 +37,7 @@ export class Image extends LitElement {
|
|
|
37
37
|
|
|
38
38
|
@state() private _loaded = false;
|
|
39
39
|
|
|
40
|
-
@
|
|
40
|
+
@query('.preview-dialog') private _dialog?: HTMLDialogElement;
|
|
41
41
|
|
|
42
42
|
private _intersectionObserver: IntersectionObserver | null = null;
|
|
43
43
|
|
|
@@ -90,13 +90,15 @@ export class Image extends LitElement {
|
|
|
90
90
|
|
|
91
91
|
private _handleClick() {
|
|
92
92
|
if (this.preview) {
|
|
93
|
-
this.
|
|
93
|
+
this._dialog?.showModal();
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
private
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
private _handleDialogClick(e: MouseEvent) {
|
|
98
|
+
// Close when clicking the backdrop (target is the dialog itself, not the image)
|
|
99
|
+
if (e.target === e.currentTarget) {
|
|
100
|
+
(e.currentTarget as HTMLDialogElement).close();
|
|
101
|
+
}
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
render() {
|
|
@@ -112,17 +114,14 @@ export class Image extends LitElement {
|
|
|
112
114
|
: html`<span class="placeholder" aria-hidden="true"></span>`}
|
|
113
115
|
</div>
|
|
114
116
|
|
|
115
|
-
<!-- Lightbox preview
|
|
116
|
-
<
|
|
117
|
-
class="preview-
|
|
118
|
-
role="dialog"
|
|
119
|
-
aria-modal="true"
|
|
117
|
+
<!-- Lightbox preview dialog — uses native top-layer to avoid stacking context issues -->
|
|
118
|
+
<dialog
|
|
119
|
+
class="preview-dialog"
|
|
120
120
|
aria-label="Image preview"
|
|
121
|
-
@click=${this.
|
|
122
|
-
@keydown=${(e: KeyboardEvent) => e.key === 'Escape' && this._closePreview(e)}
|
|
121
|
+
@click=${this._handleDialogClick}
|
|
123
122
|
>
|
|
124
123
|
<img src=${this._activeSrc} alt=${this.imageTitle} @click=${(e: Event) => e.stopPropagation()} />
|
|
125
|
-
</
|
|
124
|
+
</dialog>
|
|
126
125
|
`;
|
|
127
126
|
}
|
|
128
127
|
}
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { Accordion } from './accordion/index.js';
|
|
|
16
16
|
export { Link } from './link/index.js';
|
|
17
17
|
export { Tag } from './chip/tag/index.js';
|
|
18
18
|
export { Chip } from './chip/chip/index.js';
|
|
19
|
+
export { ChipSet } from './chip/chip-set/index.js';
|
|
19
20
|
export { LinearProgress } from './progress/linear-progress/index.js';
|
|
20
21
|
export { CircularProgress } from './progress/circular-progress/index.js';
|
|
21
22
|
export { Skeleton } from './skeleton/index.js';
|
|
@@ -38,6 +39,7 @@ export { Popover, PopoverContent } from './popover/index.js';
|
|
|
38
39
|
export { Breadcrumb, BreadcrumbItem } from './breadcrumb/index.js';
|
|
39
40
|
export { Menu, MenuItem, SubMenu } from './menu/index.js';
|
|
40
41
|
export { List, ListItem } from './list/index.js';
|
|
42
|
+
export { Item } from './item/index.js';
|
|
41
43
|
|
|
42
44
|
export { CodeHighlighter } from './code-highlighter/index.js';
|
|
43
45
|
export { CodeEditor } from './code-editor/index.js';
|
package/src/input/input.ts
CHANGED
|
@@ -79,7 +79,14 @@ export class Input extends BaseInput {
|
|
|
79
79
|
@query('.input-element')
|
|
80
80
|
private inputElement?: HTMLInputElement;
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
override async focus() {
|
|
83
|
+
await Promise.all([
|
|
84
|
+
customElements.whenDefined('wc-input'),
|
|
85
|
+
customElements.whenDefined('wc-field'),
|
|
86
|
+
]);
|
|
87
|
+
await this.updateComplete;
|
|
88
|
+
this.inputElement?.focus();
|
|
89
|
+
}
|
|
83
90
|
|
|
84
91
|
connectedCallback() {
|
|
85
92
|
super.connectedCallback();
|
|
@@ -87,11 +94,6 @@ export class Input extends BaseInput {
|
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
private handleInitialAttributes() {
|
|
90
|
-
if (this.hasAttribute('tabindex')) {
|
|
91
|
-
this.tabindex = this.getAttribute('tabindex') || undefined;
|
|
92
|
-
this.removeAttribute('tabindex');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
97
|
Array.from(this.attributes).forEach(attr => {
|
|
96
98
|
if (attr.name.startsWith('aria-')) {
|
|
97
99
|
this.configAria[attr.name] = attr.value;
|
|
@@ -105,21 +107,9 @@ export class Input extends BaseInput {
|
|
|
105
107
|
this.value = (event.target as HTMLInputElement).value;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
override blur() {
|
|
113
|
-
this.inputElement?.blur();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private __handleFocusChange() {
|
|
117
|
-
// When calling focus() or reportValidity() during change, it's possible
|
|
118
|
-
// for blur to be called after the new focus event. Rather than set
|
|
119
|
-
// `this.focused` to true/false on focus/blur, we always set it to whether
|
|
120
|
-
// or not the input itself is focused.
|
|
121
|
-
this.focused = this.inputElement?.matches(':focus') ?? false;
|
|
122
|
-
}
|
|
110
|
+
private __handleFocusChange = (event: FocusEvent) => {
|
|
111
|
+
this.focused = event.type === 'focus';
|
|
112
|
+
};
|
|
123
113
|
|
|
124
114
|
private __redispatchEvent(event: Event) {
|
|
125
115
|
redispatchEvent(this, event);
|
|
@@ -156,7 +146,6 @@ export class Input extends BaseInput {
|
|
|
156
146
|
placeholder=${this.placeholder}
|
|
157
147
|
autocomplete=${this.autocomplete}
|
|
158
148
|
.value=${this.value}
|
|
159
|
-
?tabindex=${this.tabindex}
|
|
160
149
|
?readonly=${this.readonly}
|
|
161
150
|
?required=${this.required}
|
|
162
151
|
?disabled=${this.disabled}
|
|
@@ -169,7 +158,7 @@ export class Input extends BaseInput {
|
|
|
169
158
|
|
|
170
159
|
${this.type === 'password'
|
|
171
160
|
? html`
|
|
172
|
-
<
|
|
161
|
+
<wc-tooltip
|
|
173
162
|
slot="field-end"
|
|
174
163
|
content=${this.passwordVisible
|
|
175
164
|
? 'Hide password'
|
|
@@ -183,10 +172,12 @@ export class Input extends BaseInput {
|
|
|
183
172
|
}}
|
|
184
173
|
>
|
|
185
174
|
<wc-icon
|
|
186
|
-
name=${this.passwordVisible
|
|
175
|
+
name=${this.passwordVisible
|
|
176
|
+
? 'visibility_off'
|
|
177
|
+
: 'visibility'}
|
|
187
178
|
></wc-icon>
|
|
188
179
|
</wc-icon-button>
|
|
189
|
-
</
|
|
180
|
+
</wc-tooltip>
|
|
190
181
|
`
|
|
191
182
|
: nothing}
|
|
192
183
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Item } from './item.js';
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
@use "../../scss/mixin";
|
|
2
|
+
|
|
3
|
+
@include mixin.base-styles;
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
display: block;
|
|
7
|
+
padding-inline: var(--spacing-050);
|
|
8
|
+
--item-height: 3.5rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reset native button/link styles
|
|
13
|
+
*/
|
|
14
|
+
.native-button {
|
|
15
|
+
@include mixin.reset-button-styles;
|
|
16
|
+
}
|
|
17
|
+
.native-link {
|
|
18
|
+
@include mixin.reset-link-styles;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.item {
|
|
22
|
+
position: relative;
|
|
23
|
+
min-height: var(--item-height);
|
|
24
|
+
width: 100%;
|
|
25
|
+
background: transparent;
|
|
26
|
+
text-align: initial;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
|
|
29
|
+
--private-item-container-shape-start-start: var(--item-container-shape-start-start, var(--shape-corner-extra-small));
|
|
30
|
+
--private-item-container-shape-start-end: var(--item-container-shape-start-end, var(--shape-corner-extra-small));
|
|
31
|
+
--private-item-container-shape-end-start: var(--item-container-shape-end-start, var(--shape-corner-extra-small));
|
|
32
|
+
--private-item-container-shape-end-end: var(--item-container-shape-end-end, var(--shape-corner-extra-small));
|
|
33
|
+
--private-item-container-shape-variant: var(--item-container-shape-variant, none);
|
|
34
|
+
|
|
35
|
+
font-family: var(--item-label-font-family, var(--typography-body-large-font-family)) !important;
|
|
36
|
+
font-size: var(--item-label-font-size, var(--typography-body-large-font-size)) !important;
|
|
37
|
+
font-weight: var(--item-label-font-weight, var(--typography-body-large-font-weight)) !important;
|
|
38
|
+
line-height: var(--item-label-line-height, var(--typography-body-large-line-height)) !important;
|
|
39
|
+
letter-spacing: var(--item-label-letter-spacing, var(--typography-body-large-letter-spacing)) !important;
|
|
40
|
+
|
|
41
|
+
.item-content {
|
|
42
|
+
position: relative;
|
|
43
|
+
z-index: 1;
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--spacing-200);
|
|
47
|
+
min-height: var(--item-height);
|
|
48
|
+
|
|
49
|
+
padding-inline: var(--spacing-200);
|
|
50
|
+
color: var(--private-item-label-text-color);
|
|
51
|
+
opacity: var(--private-item-label-text-opacity, 1);
|
|
52
|
+
--icon-size: var(--item-icon-size, 1.5rem);
|
|
53
|
+
--icon-color: var(--private-item-leading-trailing-color);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.start,
|
|
57
|
+
.end {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
color: var(--private-item-leading-trailing-color);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.end {
|
|
65
|
+
margin-inline-start: auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.content {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex: 1;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
gap: 0.125rem;
|
|
74
|
+
min-inline-size: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.headline-row {
|
|
78
|
+
display: flex;
|
|
79
|
+
min-inline-size: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.headline,
|
|
83
|
+
.overline,
|
|
84
|
+
.supporting-text,
|
|
85
|
+
.trailing-supporting-text {
|
|
86
|
+
min-inline-size: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.headline {
|
|
90
|
+
flex: 1;
|
|
91
|
+
color: var(--private-item-label-text-color);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.overline,
|
|
95
|
+
.supporting-text,
|
|
96
|
+
.trailing-supporting-text {
|
|
97
|
+
color: var(--private-item-supporting-text-color);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.overline {
|
|
101
|
+
@include mixin.get-typography(label-small);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.supporting-text,
|
|
105
|
+
.trailing-supporting-text {
|
|
106
|
+
@include mixin.get-typography(body-medium);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.trailing-supporting-text {
|
|
110
|
+
display: inline-flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
white-space: nowrap;
|
|
113
|
+
color: var(--private-item-supporting-text-color);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.background {
|
|
117
|
+
position: absolute;
|
|
118
|
+
inset: 0;
|
|
119
|
+
background-color: var(--private-item-container-color);
|
|
120
|
+
opacity: var(--private-item-container-opacity, 1);
|
|
121
|
+
pointer-events: none;
|
|
122
|
+
|
|
123
|
+
@include mixin.apply-container-shape(private-item);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.focus-ring {
|
|
127
|
+
z-index: 2;
|
|
128
|
+
@include mixin.copy-container-shape(private-item, focus-ring);
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.ripple {
|
|
133
|
+
@include mixin.apply-container-shape(private-item);
|
|
134
|
+
--ripple-state-opacity: var(--private-item-container-state-opacity, 0);
|
|
135
|
+
--ripple-pressed-color: var(--private-item-container-state-color);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.item {
|
|
140
|
+
--private-item-container-color: var(--item-container-color);
|
|
141
|
+
--private-item-label-text-color: var(--item-label-text-color);
|
|
142
|
+
--private-item-leading-trailing-color: var(--item-leading-trailing-color);
|
|
143
|
+
--private-item-supporting-text-color: var(--item-supporting-text-color);
|
|
144
|
+
|
|
145
|
+
--private-item-container-state-color: var(--private-item-label-text-color);
|
|
146
|
+
|
|
147
|
+
&:hover:not(:where(.disabled, .selected)) {
|
|
148
|
+
--private-item-container-state-opacity: 0.08;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&.pressed:not(:where(.disabled)) {
|
|
152
|
+
--private-item-container-state-opacity: 0.12;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
&.selected {
|
|
156
|
+
--private-item-container-color: var(--item-container-selected-color);
|
|
157
|
+
--private-item-label-text-color: var(--item-label-text-selected-color);
|
|
158
|
+
--private-item-leading-trailing-color: var(--item-label-text-selected-color);
|
|
159
|
+
--private-item-supporting-text-color: var(--item-label-text-selected-color);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
&.disabled {
|
|
163
|
+
cursor: not-allowed;
|
|
164
|
+
--private-item-label-text-color: var(--color-on-surface);
|
|
165
|
+
--private-item-label-text-opacity: 0.38;
|
|
166
|
+
--private-item-leading-trailing-color: var(--color-on-surface);
|
|
167
|
+
--private-item-supporting-text-color: var(--color-on-surface);
|
|
168
|
+
--private-item-container-opacity: 0.12;
|
|
169
|
+
|
|
170
|
+
.ripple {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:host {
|
|
177
|
+
--item-container-color: transparent;
|
|
178
|
+
--item-label-text-color: var(--color-on-surface);
|
|
179
|
+
--item-leading-trailing-color: var(--color-on-surface-variant);
|
|
180
|
+
--item-supporting-text-color: var(--color-on-surface-variant);
|
|
181
|
+
|
|
182
|
+
--item-container-selected-color: var(--color-tertiary-container);
|
|
183
|
+
--item-label-text-selected-color: var(--color-on-tertiary-container);
|
|
184
|
+
}
|
package/src/item/item.ts
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { html, LitElement, nothing } from 'lit';
|
|
2
|
+
import { property, query, state } from 'lit/decorators.js';
|
|
3
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
4
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
5
|
+
import styles from './item.scss';
|
|
6
|
+
import BaseButtonMixin from '@/__mixins/BaseButtonMixin.js';
|
|
7
|
+
import BaseHyperlinkMixin from '@/__mixins/BaseHyperlinkMixin.js';
|
|
8
|
+
import {
|
|
9
|
+
dispatchActivationClick,
|
|
10
|
+
isActivationClick,
|
|
11
|
+
} from '@/__utils/dispatch-event-utils.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @label Item
|
|
15
|
+
* @tag wc-item
|
|
16
|
+
* @rawTag item
|
|
17
|
+
*
|
|
18
|
+
* @summary A Material 3 item with start, text and end slots.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```html
|
|
22
|
+
* <wc-item selected>
|
|
23
|
+
* <wc-icon slot="start" name="home"></wc-icon>
|
|
24
|
+
* <div slot="overline">Overline</div>
|
|
25
|
+
* <div slot="headline">Headline</div>
|
|
26
|
+
* <div slot="supporting-text">Supporting text</div>
|
|
27
|
+
* <div slot="trailing-supporting-text">Trailing</div>
|
|
28
|
+
* <wc-icon slot="end" name="chevron_right"></wc-icon>
|
|
29
|
+
* </wc-item>
|
|
30
|
+
* ```
|
|
31
|
+
* @tags display
|
|
32
|
+
*/
|
|
33
|
+
export class Item extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
|
|
34
|
+
static styles = [styles];
|
|
35
|
+
|
|
36
|
+
static override get observedAttributes() {
|
|
37
|
+
return [...super.observedAttributes, 'tabindex'];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private readonly __contentObserver = new MutationObserver(() => {
|
|
41
|
+
this.requestUpdate();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
private __capturedTabIndex?: string;
|
|
45
|
+
|
|
46
|
+
private __isCapturingTabIndex = false;
|
|
47
|
+
|
|
48
|
+
@property({ type: Boolean, reflect: true }) selected = false;
|
|
49
|
+
|
|
50
|
+
@query('#item') readonly itemElement!: HTMLElement | null;
|
|
51
|
+
|
|
52
|
+
@state() isPressed = false;
|
|
53
|
+
|
|
54
|
+
private __handleSlotChange = () => {
|
|
55
|
+
this.requestUpdate();
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
private __hasNamedSlot(...names: string[]) {
|
|
59
|
+
return names.some(name =>
|
|
60
|
+
Array.from(this.children).some(child => child.getAttribute('slot') === name),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private __hasDefaultSlot() {
|
|
65
|
+
return Array.from(this.childNodes).some(node => {
|
|
66
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
67
|
+
return Boolean(node.textContent?.trim());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
node.nodeType === Node.ELEMENT_NODE &&
|
|
72
|
+
!(node as Element).hasAttribute('slot')
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
connectedCallback() {
|
|
78
|
+
// eslint-disable-next-line wc/guard-super-call
|
|
79
|
+
super.connectedCallback();
|
|
80
|
+
this.__captureHostTabIndex();
|
|
81
|
+
|
|
82
|
+
this.__contentObserver.observe(this, {
|
|
83
|
+
subtree: true,
|
|
84
|
+
childList: true,
|
|
85
|
+
characterData: true,
|
|
86
|
+
attributes: true,
|
|
87
|
+
attributeFilter: ['slot'],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
disconnectedCallback() {
|
|
92
|
+
this.__contentObserver.disconnect();
|
|
93
|
+
super.disconnectedCallback();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override attributeChangedCallback(
|
|
97
|
+
name: string,
|
|
98
|
+
oldValue: string | null,
|
|
99
|
+
newValue: string | null,
|
|
100
|
+
) {
|
|
101
|
+
if (name === 'tabindex') {
|
|
102
|
+
if (!this.__isCapturingTabIndex && newValue != null) {
|
|
103
|
+
this.__capturedTabIndex = newValue;
|
|
104
|
+
this.__isCapturingTabIndex = true;
|
|
105
|
+
this.removeAttribute('tabindex');
|
|
106
|
+
this.__isCapturingTabIndex = false;
|
|
107
|
+
this.requestUpdate();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override focus() {
|
|
117
|
+
this.itemElement?.focus();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
override blur() {
|
|
121
|
+
this.itemElement?.blur();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
__dispatchClick = (event: MouseEvent | KeyboardEvent) => {
|
|
125
|
+
if (this.softDisabled || (this.disabled && this.href)) {
|
|
126
|
+
event.stopImmediatePropagation();
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!isActivationClick(event) || !this.itemElement) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.focus();
|
|
136
|
+
dispatchActivationClick(this.itemElement);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
__handleKeyDown = (event: KeyboardEvent) => {
|
|
140
|
+
this.__handlePress(event);
|
|
141
|
+
|
|
142
|
+
if (this.disabled || this.softDisabled || !this.itemElement) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (event.key === ' ') {
|
|
147
|
+
event.preventDefault();
|
|
148
|
+
this.itemElement.click();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (event.key === 'Enter' && !this.__isLink()) {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
this.itemElement.click();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
__handlePress = (event: KeyboardEvent | MouseEvent) => {
|
|
159
|
+
if (this.disabled || this.softDisabled) return;
|
|
160
|
+
|
|
161
|
+
if (
|
|
162
|
+
event instanceof KeyboardEvent &&
|
|
163
|
+
event.type === 'keydown' &&
|
|
164
|
+
(event.key === 'Enter' || event.key === ' ')
|
|
165
|
+
) {
|
|
166
|
+
this.isPressed = true;
|
|
167
|
+
} else if (event.type === 'mousedown') {
|
|
168
|
+
this.isPressed = true;
|
|
169
|
+
} else {
|
|
170
|
+
this.isPressed = false;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
private __getForwardedAttribute(name: string) {
|
|
175
|
+
return this.getAttribute(name) ?? undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private __captureHostTabIndex() {
|
|
179
|
+
const tabIndex = this.getAttribute('tabindex');
|
|
180
|
+
|
|
181
|
+
if (tabIndex == null) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.__capturedTabIndex = tabIndex;
|
|
186
|
+
this.__isCapturingTabIndex = true;
|
|
187
|
+
this.removeAttribute('tabindex');
|
|
188
|
+
this.__isCapturingTabIndex = false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
render() {
|
|
192
|
+
const isLink = this.__isLink();
|
|
193
|
+
const role = this.__getForwardedAttribute('role');
|
|
194
|
+
const tabIndex = this.__capturedTabIndex;
|
|
195
|
+
const ariaHasPopup = this.__getForwardedAttribute('aria-haspopup');
|
|
196
|
+
const ariaControls = this.__getForwardedAttribute('aria-controls');
|
|
197
|
+
const ariaExpanded = this.__getForwardedAttribute('aria-expanded');
|
|
198
|
+
|
|
199
|
+
const cssClasses: any = {
|
|
200
|
+
item: true,
|
|
201
|
+
selected: this.selected,
|
|
202
|
+
disabled: this.disabled || this.softDisabled,
|
|
203
|
+
pressed: this.isPressed,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
if (!isLink) {
|
|
207
|
+
cssClasses['native-button'] = true;
|
|
208
|
+
|
|
209
|
+
return html`
|
|
210
|
+
<button
|
|
211
|
+
id="item"
|
|
212
|
+
class=${classMap(cssClasses)}
|
|
213
|
+
type=${this.htmlType}
|
|
214
|
+
role=${ifDefined(role)}
|
|
215
|
+
tabindex=${ifDefined(tabIndex)}
|
|
216
|
+
?disabled=${this.disabled}
|
|
217
|
+
?aria-disabled=${this.softDisabled}
|
|
218
|
+
aria-haspopup=${ifDefined(ariaHasPopup)}
|
|
219
|
+
aria-controls=${ifDefined(ariaControls)}
|
|
220
|
+
aria-expanded=${ifDefined(ariaExpanded)}
|
|
221
|
+
@click=${this.__dispatchClick}
|
|
222
|
+
@mousedown=${this.__handlePress}
|
|
223
|
+
@keydown=${this.__handleKeyDown}
|
|
224
|
+
@keyup=${this.__handlePress}
|
|
225
|
+
>
|
|
226
|
+
${this.renderContent()}
|
|
227
|
+
</button>
|
|
228
|
+
`;
|
|
229
|
+
} else {
|
|
230
|
+
cssClasses['native-link'] = true;
|
|
231
|
+
return html`
|
|
232
|
+
<a
|
|
233
|
+
id="item"
|
|
234
|
+
class=${classMap(cssClasses)}
|
|
235
|
+
href=${this.href}
|
|
236
|
+
target=${this.target}
|
|
237
|
+
rel=${ifDefined(this.rel)}
|
|
238
|
+
download=${ifDefined(this.download)}
|
|
239
|
+
role=${ifDefined(role)}
|
|
240
|
+
tabindex=${ifDefined(tabIndex ?? (this.disabled ? '-1' : '0'))}
|
|
241
|
+
aria-disabled=${String(this.disabled || this.softDisabled)}
|
|
242
|
+
aria-haspopup=${ifDefined(ariaHasPopup)}
|
|
243
|
+
aria-controls=${ifDefined(ariaControls)}
|
|
244
|
+
aria-expanded=${ifDefined(ariaExpanded)}
|
|
245
|
+
@click=${this.__dispatchClick}
|
|
246
|
+
@mousedown=${this.__handlePress}
|
|
247
|
+
@keydown=${this.__handleKeyDown}
|
|
248
|
+
@keyup=${this.__handlePress}
|
|
249
|
+
>
|
|
250
|
+
${this.renderContent()}
|
|
251
|
+
</a>
|
|
252
|
+
`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
renderContent() {
|
|
259
|
+
const hasStart = this.__hasNamedSlot('start');
|
|
260
|
+
const hasEnd = this.__hasNamedSlot('end');
|
|
261
|
+
const hasOverline = this.__hasNamedSlot('overline');
|
|
262
|
+
const hasHeadline = this.__hasNamedSlot('headline');
|
|
263
|
+
const hasDefault = this.__hasDefaultSlot();
|
|
264
|
+
const hasSupportingText = this.__hasNamedSlot('supporting-text');
|
|
265
|
+
const hasTrailingSupportingText = this.__hasNamedSlot(
|
|
266
|
+
'trailing-supporting-text',
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
return html`
|
|
270
|
+
<wc-focus-ring class="focus-ring" for="item"></wc-focus-ring>
|
|
271
|
+
<div class="background"></div>
|
|
272
|
+
<wc-ripple class="ripple"></wc-ripple>
|
|
273
|
+
|
|
274
|
+
<div class="item-content">
|
|
275
|
+
${hasStart
|
|
276
|
+
? html`
|
|
277
|
+
<div class="start">
|
|
278
|
+
<slot name="start" @slotchange=${this.__handleSlotChange}></slot>
|
|
279
|
+
</div>
|
|
280
|
+
`
|
|
281
|
+
: nothing}
|
|
282
|
+
<div class="content">
|
|
283
|
+
|
|
284
|
+
${hasOverline
|
|
285
|
+
? html`
|
|
286
|
+
<div class="overline">
|
|
287
|
+
<slot name="overline" @slotchange=${this.__handleSlotChange}></slot>
|
|
288
|
+
</div>
|
|
289
|
+
`
|
|
290
|
+
: nothing}
|
|
291
|
+
${hasHeadline || hasDefault
|
|
292
|
+
? html`
|
|
293
|
+
<div class="headline-row">
|
|
294
|
+
${hasHeadline || hasDefault
|
|
295
|
+
? html`
|
|
296
|
+
<div class="headline">
|
|
297
|
+
${hasHeadline
|
|
298
|
+
? html`<slot name="headline" @slotchange=${this.__handleSlotChange}></slot>`
|
|
299
|
+
: nothing}
|
|
300
|
+
${hasDefault
|
|
301
|
+
? html`<slot @slotchange=${this.__handleSlotChange}></slot>`
|
|
302
|
+
: nothing}
|
|
303
|
+
</div>
|
|
304
|
+
`
|
|
305
|
+
: nothing}
|
|
306
|
+
</div>
|
|
307
|
+
`
|
|
308
|
+
: nothing}
|
|
309
|
+
${hasSupportingText
|
|
310
|
+
? html`
|
|
311
|
+
<div class="supporting-text">
|
|
312
|
+
<slot
|
|
313
|
+
name="supporting-text"
|
|
314
|
+
@slotchange=${this.__handleSlotChange}
|
|
315
|
+
></slot>
|
|
316
|
+
</div>
|
|
317
|
+
`
|
|
318
|
+
: nothing}
|
|
319
|
+
</div>
|
|
320
|
+
${hasTrailingSupportingText
|
|
321
|
+
? html`
|
|
322
|
+
<div class="trailing-supporting-text">
|
|
323
|
+
<slot
|
|
324
|
+
name="trailing-supporting-text"
|
|
325
|
+
@slotchange=${this.__handleSlotChange}
|
|
326
|
+
></slot>
|
|
327
|
+
</div>
|
|
328
|
+
`
|
|
329
|
+
: nothing}
|
|
330
|
+
${hasEnd
|
|
331
|
+
? html`
|
|
332
|
+
<div class="end">
|
|
333
|
+
<slot name="end" @slotchange=${this.__handleSlotChange}></slot>
|
|
334
|
+
</div>
|
|
335
|
+
`
|
|
336
|
+
: nothing}
|
|
337
|
+
</div>
|
|
338
|
+
`;
|
|
339
|
+
}
|
|
340
|
+
}
|