@redvars/peacock 3.5.0 → 3.5.1
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/BaseButton-DuASuVth.js +219 -0
- package/dist/BaseButton-DuASuVth.js.map +1 -0
- package/dist/BaseHyperlinkMixin-BNuwbiEf.js +65 -0
- package/dist/BaseHyperlinkMixin-BNuwbiEf.js.map +1 -0
- package/dist/assets/components.css +1 -1
- 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/banner.js +12 -27
- package/dist/banner.js.map +1 -1
- package/dist/{button-DMN1dPAg.js → button-DouvOfEU.js} +77 -251
- package/dist/button-DouvOfEU.js.map +1 -0
- package/dist/{button-group-CX9CUUXk.js → button-group-CEdMwvJJ.js} +71 -42
- package/dist/button-group-CEdMwvJJ.js.map +1 -0
- package/dist/button-group.js +5 -5
- package/dist/button.js +3 -3
- package/dist/card.js +18 -73
- package/dist/card.js.map +1 -1
- package/dist/chart-bar.js.map +1 -1
- package/dist/chart-doughnut.js +2 -2
- package/dist/chart-doughnut.js.map +1 -1
- package/dist/chart-pie.js +2 -2
- package/dist/chart-pie.js.map +1 -1
- package/dist/chart-stacked-bar.js.map +1 -1
- package/dist/code-highlighter.js +2 -1
- package/dist/code-highlighter.js.map +1 -1
- package/dist/custom-elements-jsdocs.json +3105 -1494
- package/dist/custom-elements.json +9244 -7829
- package/dist/fab.js +421 -9
- package/dist/fab.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/{select-4pl4XBj7.js → navigation-rail-Lxetd5-Z.js} +2214 -1090
- package/dist/navigation-rail-Lxetd5-Z.js.map +1 -0
- package/dist/notification.js +3 -2
- package/dist/notification.js.map +1 -1
- package/dist/peacock-loader.js +22 -10
- package/dist/peacock-loader.js.map +1 -1
- package/dist/search.js +4 -0
- package/dist/search.js.map +1 -1
- package/dist/src/__mixins/BaseButtonMixin.d.ts +20 -0
- package/dist/src/__mixins/BaseHyperlinkMixin.d.ts +18 -0
- package/dist/src/__mixins/MixinConstructor.d.ts +1 -0
- package/dist/src/banner/banner.d.ts +0 -4
- package/dist/src/button/BaseButton.d.ts +4 -47
- package/dist/src/button/button/button.d.ts +32 -3
- package/dist/src/button/button-group/button-group.d.ts +2 -2
- package/dist/src/button/icon-button/icon-button.d.ts +33 -8
- package/dist/src/card/card.d.ts +4 -15
- package/dist/src/fab/fab.d.ts +4 -35
- package/dist/src/focus-ring/focus-ring.d.ts +11 -5
- package/dist/src/index.d.ts +3 -1
- package/dist/src/link/link.d.ts +1 -1
- package/dist/src/navigation-rail/index.d.ts +2 -0
- package/dist/src/navigation-rail/navigation-rail-item.d.ts +55 -0
- package/dist/src/navigation-rail/navigation-rail.d.ts +71 -0
- package/dist/src/sidebar-menu/index.d.ts +3 -0
- package/dist/src/sidebar-menu/sidebar-menu-item.d.ts +58 -0
- package/dist/src/sidebar-menu/sidebar-menu.d.ts +38 -0
- package/dist/src/sidebar-menu/sidebar-sub-menu.d.ts +35 -0
- package/dist/src/toolbar/toolbar.d.ts +10 -10
- package/dist/src/tooltip/tooltip.d.ts +3 -0
- package/dist/src/url-field/index.d.ts +1 -0
- package/dist/src/url-field/url-field.d.ts +48 -0
- package/dist/test/sidebar-menu.test.d.ts +1 -0
- package/dist/toolbar.js +10 -10
- package/dist/toolbar.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/readme.md +73 -65
- package/scss/mixin.scss +16 -0
- package/src/__mixins/BaseButtonMixin.ts +83 -0
- package/src/__mixins/BaseHyperlinkMixin.ts +68 -0
- package/src/__mixins/MixinConstructor.ts +1 -0
- package/src/{__base_element → __mixins}/README.md +2 -2
- package/src/banner/banner.scss +18 -22
- package/src/banner/banner.ts +1 -7
- package/src/button/BaseButton.ts +11 -100
- package/src/button/button/button-sizes.scss +4 -2
- package/src/button/button/button.ts +76 -23
- package/src/button/button-group/button-group.ts +2 -2
- package/src/button/icon-button/icon-button.ts +75 -33
- package/src/card/card.ts +11 -71
- package/src/chart-bar/chart-bar.ts +9 -14
- package/src/chart-bar/chart-stacked-bar.ts +12 -18
- package/src/chart-doughnut/chart-doughnut.ts +23 -27
- package/src/chart-pie/chart-pie.ts +19 -23
- package/src/checkbox/checkbox.scss +17 -34
- package/src/checkbox/checkbox.ts +3 -1
- package/src/code-highlighter/code-highlighter.scss +1 -0
- package/src/code-highlighter/code-highlighter.ts +1 -1
- package/src/date-picker/date-picker.ts +1 -1
- package/src/elevation/elevation.scss +5 -5
- package/src/fab/fab.ts +29 -100
- package/src/focus-ring/focus-ring.ts +47 -40
- package/src/index.ts +3 -1
- package/src/input/input.ts +3 -1
- package/src/link/link.ts +2 -2
- package/src/menu/menu-item/menu-item.ts +3 -1
- package/src/navigation-rail/index.ts +2 -0
- package/src/navigation-rail/navigation-rail-item.scss +216 -0
- package/src/navigation-rail/navigation-rail-item.ts +223 -0
- package/src/navigation-rail/navigation-rail.scss +72 -0
- package/src/navigation-rail/navigation-rail.ts +149 -0
- package/src/notification/notification.ts +3 -2
- package/src/number-field/number-field.ts +6 -4
- package/src/pagination/pagination.ts +6 -4
- package/src/peacock-loader.ts +22 -5
- package/src/search/search.ts +4 -0
- package/src/sidebar-menu/demo/index.html +68 -0
- package/src/sidebar-menu/index.ts +3 -0
- package/src/sidebar-menu/sidebar-menu-item.scss +102 -0
- package/src/sidebar-menu/sidebar-menu-item.ts +151 -0
- package/src/{tree-view/tree-view.scss → sidebar-menu/sidebar-menu.scss} +1 -1
- package/src/sidebar-menu/sidebar-menu.ts +182 -0
- package/src/sidebar-menu/sidebar-sub-menu.scss +130 -0
- package/src/sidebar-menu/sidebar-sub-menu.ts +160 -0
- package/src/skeleton/skeleton.scss +18 -24
- package/src/snackbar/snackbar.ts +1 -1
- package/src/tabs/tab.ts +4 -3
- package/src/text/text.css-component.scss +7 -1
- package/src/time-picker/time-picker.ts +1 -1
- package/src/toolbar/toolbar.ts +10 -10
- package/src/tooltip/tooltip.ts +24 -0
- package/src/url-field/index.ts +1 -0
- package/src/url-field/url-field.scss +50 -0
- package/src/url-field/url-field.ts +239 -0
- package/dist/button-DMN1dPAg.js.map +0 -1
- package/dist/button-group-CX9CUUXk.js.map +0 -1
- package/dist/fab-C5Nzxk0E.js +0 -497
- package/dist/fab-C5Nzxk0E.js.map +0 -1
- package/dist/select-4pl4XBj7.js.map +0 -1
- package/dist/spread-B5cgadZl.js +0 -32
- package/dist/spread-B5cgadZl.js.map +0 -1
- package/dist/src/__base_element/BaseHyperlink.d.ts +0 -20
- package/dist/src/tree-view/index.d.ts +0 -2
- package/dist/src/tree-view/tree-node.d.ts +0 -69
- package/dist/src/tree-view/tree-view.d.ts +0 -40
- package/dist/src/tree-view/wc-tree-view.d.ts +0 -6
- package/dist/test/tree-view.test.d.ts +0 -1
- package/dist/throttle-C7ZAPqtu.js +0 -24
- package/dist/throttle-C7ZAPqtu.js.map +0 -1
- package/src/__base_element/BaseHyperlink.ts +0 -42
- package/src/tree-view/demo/index.html +0 -57
- package/src/tree-view/index.ts +0 -2
- package/src/tree-view/tree-node.scss +0 -101
- package/src/tree-view/tree-node.ts +0 -268
- package/src/tree-view/tree-view.ts +0 -182
- package/src/tree-view/wc-tree-view.ts +0 -9
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import { property, query } from 'lit/decorators.js';
|
|
3
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
4
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
5
|
+
import styles from './sidebar-sub-menu.scss';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @label Sidebar Sub Menu
|
|
9
|
+
* @tag wc-sidebar-sub-menu
|
|
10
|
+
* @rawTag sidebar-sub-menu
|
|
11
|
+
* @parentRawTag sidebar-menu
|
|
12
|
+
* @summary A sidebar sub menu groups sidebar menu items and handles expand/collapse behavior.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <wc-sidebar-sub-menu label="Parent" expanded>
|
|
17
|
+
* <wc-sidebar-menu-item label="Child"></wc-sidebar-menu-item>
|
|
18
|
+
* </wc-sidebar-sub-menu>
|
|
19
|
+
* ```
|
|
20
|
+
* @tags navigation
|
|
21
|
+
*/
|
|
22
|
+
export class SidebarSubMenu extends LitElement {
|
|
23
|
+
static styles = [styles];
|
|
24
|
+
|
|
25
|
+
@property({ type: String, reflect: true })
|
|
26
|
+
value: string = '';
|
|
27
|
+
|
|
28
|
+
@property({ type: String, reflect: true })
|
|
29
|
+
label: string = '';
|
|
30
|
+
|
|
31
|
+
@property({ type: String, reflect: true })
|
|
32
|
+
icon: string = '';
|
|
33
|
+
|
|
34
|
+
@property({ type: Boolean, reflect: true })
|
|
35
|
+
disabled: boolean = false;
|
|
36
|
+
|
|
37
|
+
@property({ type: Boolean, reflect: true })
|
|
38
|
+
selected: boolean = false;
|
|
39
|
+
|
|
40
|
+
@property({ type: Boolean, reflect: true })
|
|
41
|
+
expanded: boolean = false;
|
|
42
|
+
|
|
43
|
+
@property({ type: Number, reflect: true })
|
|
44
|
+
level: number = 0;
|
|
45
|
+
|
|
46
|
+
@query('.sidebar-sub-menu-inner')
|
|
47
|
+
private readonly _nativeElement!: HTMLElement | null;
|
|
48
|
+
|
|
49
|
+
override focus() {
|
|
50
|
+
this._nativeElement?.focus();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override blur() {
|
|
54
|
+
this._nativeElement?.blur();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
connectedCallback() {
|
|
58
|
+
super.connectedCallback();
|
|
59
|
+
this._updateChildLevels();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
updated(changedProps: Map<string, unknown>) {
|
|
63
|
+
super.updated(changedProps);
|
|
64
|
+
|
|
65
|
+
if (changedProps.has('expanded')) {
|
|
66
|
+
this.setAttribute('aria-expanded', String(this.expanded));
|
|
67
|
+
if (this.expanded) {
|
|
68
|
+
this.setAttribute('data-expanded', '');
|
|
69
|
+
} else {
|
|
70
|
+
this.removeAttribute('data-expanded');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private _getChildNodes(): Element[] {
|
|
76
|
+
return Array.from(this.children).filter(el => {
|
|
77
|
+
const tag = el.tagName.toLowerCase();
|
|
78
|
+
return tag === 'wc-sidebar-menu-item' || tag === 'wc-sidebar-sub-menu';
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private _updateChildLevels = () => {
|
|
83
|
+
this._getChildNodes().forEach(child => {
|
|
84
|
+
if ('level' in child) {
|
|
85
|
+
// eslint-disable-next-line no-param-reassign
|
|
86
|
+
(child as { level: number }).level = this.level + 1;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
private _onClick = () => {
|
|
92
|
+
if (this.disabled) return;
|
|
93
|
+
|
|
94
|
+
if (this._getChildNodes().length > 0) {
|
|
95
|
+
this.expanded = !this.expanded;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.dispatchEvent(
|
|
99
|
+
new CustomEvent('sidebar-menu-item:click', {
|
|
100
|
+
bubbles: true,
|
|
101
|
+
composed: true,
|
|
102
|
+
detail: { value: this.value, label: this.label },
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
override render() {
|
|
108
|
+
const hasChildren = this._getChildNodes().length > 0;
|
|
109
|
+
const wrapperClasses = classMap({
|
|
110
|
+
'sidebar-sub-menu': true,
|
|
111
|
+
});
|
|
112
|
+
const innerClasses = classMap({
|
|
113
|
+
'sidebar-sub-menu-inner': true,
|
|
114
|
+
disabled: this.disabled,
|
|
115
|
+
selected: this.selected,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const inlineStyles = styleMap({
|
|
119
|
+
paddingLeft: `calc(var(--sidebar-menu-item-height, 2.5rem) * ${this.level})`,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return html`
|
|
123
|
+
<div class="${wrapperClasses}" style="${inlineStyles}">
|
|
124
|
+
<div
|
|
125
|
+
id="item"
|
|
126
|
+
class="${innerClasses}"
|
|
127
|
+
role="treeitem"
|
|
128
|
+
aria-label="${this.label}"
|
|
129
|
+
aria-selected="${String(this.selected)}"
|
|
130
|
+
aria-disabled="${this.disabled}"
|
|
131
|
+
aria-expanded="${this.expanded}"
|
|
132
|
+
@click="${this._onClick}"
|
|
133
|
+
@keydown="${(e: KeyboardEvent) => {
|
|
134
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
this._onClick();
|
|
137
|
+
}
|
|
138
|
+
}}"
|
|
139
|
+
tabindex="${this.disabled ? -1 : 0}"
|
|
140
|
+
>
|
|
141
|
+
<wc-focus-ring class="focus-ring" for="item"></wc-focus-ring>
|
|
142
|
+
<div class="background"></div>
|
|
143
|
+
<wc-ripple class="ripple"></wc-ripple>
|
|
144
|
+
<div class="sidebar-sub-menu-content">
|
|
145
|
+
${this.icon ? html`<wc-icon name="${this.icon}"></wc-icon>` : ''}
|
|
146
|
+
<span class="sidebar-sub-menu-label">${this.label}</span>
|
|
147
|
+
</div>
|
|
148
|
+
${hasChildren
|
|
149
|
+
? html`
|
|
150
|
+
<wc-icon class="expand-icon" name="arrow_drop_down" aria-hidden="true"></wc-icon>
|
|
151
|
+
`
|
|
152
|
+
: ''}
|
|
153
|
+
</div>
|
|
154
|
+
<div class="sidebar-sub-menu-children ${(!hasChildren || !this.expanded) ? 'hidden' : ''}">
|
|
155
|
+
<slot @slotchange="${this._updateChildLevels}"></slot>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,43 +1,37 @@
|
|
|
1
|
+
@use '../../scss/mixin';
|
|
2
|
+
|
|
3
|
+
@include mixin.base-styles;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
:host {
|
|
9
|
+
position: relative;
|
|
10
|
+
inset: 0;
|
|
2
11
|
--skeleton-container-color: var(--color-surface-container);
|
|
3
12
|
--skeleton-element: var(--color-on-surface);
|
|
4
|
-
display:
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
display: flex;
|
|
14
|
+
pointer-events: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.skeleton,
|
|
18
|
+
.skeleton::before {
|
|
19
|
+
inset: 0;
|
|
20
|
+
position: absolute;
|
|
21
|
+
@include mixin.apply-container-shape(skeleton);
|
|
7
22
|
}
|
|
8
23
|
|
|
9
24
|
.skeleton {
|
|
10
|
-
position: relative;
|
|
11
|
-
padding: 0;
|
|
12
|
-
border: none;
|
|
13
25
|
background: var(--skeleton-container-color);
|
|
14
|
-
box-shadow: none;
|
|
15
26
|
overflow: hidden;
|
|
16
|
-
pointer-events: none;
|
|
17
|
-
width: 100%;
|
|
18
|
-
height: 100%;
|
|
19
|
-
border-start-start-radius: var(--skeleton-container-shape-start-start);
|
|
20
|
-
border-start-end-radius: var(--skeleton-container-shape-start-end);
|
|
21
|
-
border-end-start-radius: var(--skeleton-container-shape-end-start);
|
|
22
|
-
border-end-end-radius: var(--skeleton-container-shape-end-end);
|
|
23
|
-
corner-shape: var(--skeleton-container-shape-variant);
|
|
24
27
|
|
|
25
28
|
&::before {
|
|
26
|
-
position: absolute;
|
|
27
|
-
left: 0;
|
|
28
|
-
top: 0;
|
|
29
29
|
animation: 3s ease-in-out skeleton infinite;
|
|
30
30
|
background: var(--skeleton-element);
|
|
31
31
|
block-size: 100%;
|
|
32
32
|
content: "";
|
|
33
33
|
inline-size: 100%;
|
|
34
34
|
will-change: transform-origin, transform, opacity;
|
|
35
|
-
|
|
36
|
-
border-start-start-radius: var(--skeleton-container-shape-start-start);
|
|
37
|
-
border-start-end-radius: var(--skeleton-container-shape-start-end);
|
|
38
|
-
border-end-start-radius: var(--skeleton-container-shape-end-start);
|
|
39
|
-
border-end-end-radius: var(--skeleton-container-shape-end-end);
|
|
40
|
-
corner-shape: var(--skeleton-container-shape-variant);
|
|
41
35
|
}
|
|
42
36
|
}
|
|
43
37
|
|
package/src/snackbar/snackbar.ts
CHANGED
package/src/tabs/tab.ts
CHANGED
|
@@ -193,6 +193,7 @@ export class Tab extends LitElement {
|
|
|
193
193
|
|
|
194
194
|
if (!isLink) {
|
|
195
195
|
return html`<button
|
|
196
|
+
id="button"
|
|
196
197
|
class=${classMap(cssClasses)}
|
|
197
198
|
tabindex="0"
|
|
198
199
|
@mousedown=${this.__handlePress}
|
|
@@ -241,7 +242,7 @@ export class Tab extends LitElement {
|
|
|
241
242
|
|
|
242
243
|
renderPrimaryTabContent() {
|
|
243
244
|
return html`
|
|
244
|
-
<wc-focus-ring class="focus-ring"
|
|
245
|
+
<wc-focus-ring class="focus-ring" for='button'></wc-focus-ring>
|
|
245
246
|
<wc-elevation class="elevation"></wc-elevation>
|
|
246
247
|
<div class="background"></div>
|
|
247
248
|
<div class="outline"></div>
|
|
@@ -267,7 +268,7 @@ export class Tab extends LitElement {
|
|
|
267
268
|
|
|
268
269
|
renderSecondaryTabContent() {
|
|
269
270
|
return html`
|
|
270
|
-
<wc-focus-ring class="focus-ring"
|
|
271
|
+
<wc-focus-ring class="focus-ring" for='button'></wc-focus-ring>
|
|
271
272
|
<wc-elevation class="elevation"></wc-elevation>
|
|
272
273
|
<div class="background"></div>
|
|
273
274
|
<div class="outline"></div>
|
|
@@ -300,7 +301,7 @@ export class Tab extends LitElement {
|
|
|
300
301
|
|
|
301
302
|
renderSegmentedTabContent() {
|
|
302
303
|
return html`
|
|
303
|
-
<wc-focus-ring class="focus-ring"
|
|
304
|
+
<wc-focus-ring class="focus-ring" for='button'></wc-focus-ring>
|
|
304
305
|
<wc-elevation class="elevation"></wc-elevation>
|
|
305
306
|
<div class="background"></div>
|
|
306
307
|
<div class="outline"></div>
|
|
@@ -49,11 +49,17 @@ $sizes: "large", "medium", 'small';
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
.text-code-block {
|
|
52
|
-
display: inline-flex;
|
|
53
52
|
background-color: var(--color-surface-variant);
|
|
54
53
|
text-shadow: 0 1px 1px var(--color-surface-variant);
|
|
55
54
|
color: var(--color-on-surface);
|
|
56
55
|
border-radius: var(--shape-corner-extra-small);
|
|
57
56
|
padding: var(--spacing-050);
|
|
58
57
|
font-family: var(--font-family-monospace);
|
|
58
|
+
|
|
59
|
+
display: inline-block;
|
|
60
|
+
max-width: 100%;
|
|
61
|
+
white-space: pre-wrap;
|
|
62
|
+
word-break: break-word;
|
|
63
|
+
overflow-wrap: anywhere;
|
|
64
|
+
vertical-align: middle;
|
|
59
65
|
}
|
|
@@ -167,7 +167,6 @@ export class TimePicker extends BaseInput {
|
|
|
167
167
|
slot="field-end"
|
|
168
168
|
color="secondary"
|
|
169
169
|
variant="text"
|
|
170
|
-
name="calendar_today"
|
|
171
170
|
?disabled=${this.disabled}
|
|
172
171
|
@click=${() => {
|
|
173
172
|
setTimeout(() => {
|
|
@@ -176,6 +175,7 @@ export class TimePicker extends BaseInput {
|
|
|
176
175
|
});
|
|
177
176
|
}}
|
|
178
177
|
>
|
|
178
|
+
<wc-icon name="calendar_today"></wc-icon>
|
|
179
179
|
</wc-icon-button>
|
|
180
180
|
</wc-field>
|
|
181
181
|
`;
|
package/src/toolbar/toolbar.ts
CHANGED
|
@@ -33,10 +33,10 @@ import colorStyles from './toolbar-colors.scss';
|
|
|
33
33
|
* ```html
|
|
34
34
|
* <!-- Docked toolbar -->
|
|
35
35
|
* <wc-toolbar>
|
|
36
|
-
* <wc-icon-button variant="text" name="home"></wc-icon-button>
|
|
37
|
-
* <wc-icon-button variant="tonal" name="search"></wc-icon-button>
|
|
38
|
-
* <wc-icon-button variant="text" name="favorite"></wc-icon-button>
|
|
39
|
-
* <wc-icon-button variant="text" name="account_circle"></wc-icon-button>
|
|
36
|
+
* <wc-icon-button variant="text"><wc-icon name="home"></wc-icon></wc-icon-button>
|
|
37
|
+
* <wc-icon-button variant="tonal"><wc-icon name="search"></wc-icon></wc-icon-button>
|
|
38
|
+
* <wc-icon-button variant="text"><wc-icon name="favorite"></wc-icon></wc-icon-button>
|
|
39
|
+
* <wc-icon-button variant="text"><wc-icon name="account_circle"></wc-icon></wc-icon-button>
|
|
40
40
|
* </wc-toolbar>
|
|
41
41
|
* ```
|
|
42
42
|
*
|
|
@@ -44,9 +44,9 @@ import colorStyles from './toolbar-colors.scss';
|
|
|
44
44
|
* ```html
|
|
45
45
|
* <!-- Floating horizontal toolbar -->
|
|
46
46
|
* <wc-toolbar variant="floating" orientation="horizontal">
|
|
47
|
-
* <wc-icon-button variant="tonal" name="home"></wc-icon-button>
|
|
48
|
-
* <wc-icon-button variant="text" name="search"></wc-icon-button>
|
|
49
|
-
* <wc-icon-button variant="text" name="favorite"></wc-icon-button>
|
|
47
|
+
* <wc-icon-button variant="tonal"><wc-icon name="home"></wc-icon></wc-icon-button>
|
|
48
|
+
* <wc-icon-button variant="text"><wc-icon name="search"></wc-icon></wc-icon-button>
|
|
49
|
+
* <wc-icon-button variant="text"><wc-icon name="favorite"></wc-icon></wc-icon-button>
|
|
50
50
|
* </wc-toolbar>
|
|
51
51
|
* ```
|
|
52
52
|
*
|
|
@@ -54,9 +54,9 @@ import colorStyles from './toolbar-colors.scss';
|
|
|
54
54
|
* ```html
|
|
55
55
|
* <!-- Floating vertical toolbar -->
|
|
56
56
|
* <wc-toolbar variant="floating" orientation="vertical">
|
|
57
|
-
* <wc-icon-button variant="tonal" name="home"></wc-icon-button>
|
|
58
|
-
* <wc-icon-button variant="text" name="search"></wc-icon-button>
|
|
59
|
-
* <wc-icon-button variant="text" name="favorite"></wc-icon-button>
|
|
57
|
+
* <wc-icon-button variant="tonal"><wc-icon name="home"></wc-icon></wc-icon-button>
|
|
58
|
+
* <wc-icon-button variant="text"><wc-icon name="search"></wc-icon></wc-icon-button>
|
|
59
|
+
* <wc-icon-button variant="text"><wc-icon name="favorite"></wc-icon></wc-icon-button>
|
|
60
60
|
* </wc-toolbar>
|
|
61
61
|
* ```
|
|
62
62
|
* @tags display navigation
|
package/src/tooltip/tooltip.ts
CHANGED
|
@@ -133,6 +133,30 @@ export class Tooltip extends LitElement {
|
|
|
133
133
|
this._target = null;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
_focusTarget?: HTMLElement;
|
|
137
|
+
|
|
138
|
+
set forElement(value: HTMLElement | null) {
|
|
139
|
+
if (value) {
|
|
140
|
+
this._focusTarget = value;
|
|
141
|
+
} else {
|
|
142
|
+
this._focusTarget = undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
__getFocusTarget(): HTMLElement | null {
|
|
147
|
+
|
|
148
|
+
if (this._focusTarget) {
|
|
149
|
+
return this._focusTarget;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const focusTarget = document.getElementById(this.for);
|
|
153
|
+
if (focusTarget) {
|
|
154
|
+
return focusTarget
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return this.parentElement;
|
|
158
|
+
}
|
|
159
|
+
|
|
136
160
|
private attachListeners() {
|
|
137
161
|
this.detachListeners(); // Cleanup old target if it exists
|
|
138
162
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { UrlField } from './url-field.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@use '../../scss/mixin';
|
|
2
|
+
|
|
3
|
+
@include mixin.base-styles;
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
display: block;
|
|
7
|
+
width: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.url-input {
|
|
11
|
+
flex: 1;
|
|
12
|
+
width: 100%;
|
|
13
|
+
border: none;
|
|
14
|
+
outline: none;
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
background: none;
|
|
18
|
+
cursor: inherit;
|
|
19
|
+
font: inherit;
|
|
20
|
+
color: inherit;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.url-display {
|
|
24
|
+
flex: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.url-link {
|
|
31
|
+
flex: 1;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
text-overflow: ellipsis;
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
color: var(--color-primary);
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
|
|
38
|
+
&:hover {
|
|
39
|
+
text-decoration: underline;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.url-placeholder {
|
|
44
|
+
color: var(--color-on-surface-variant);
|
|
45
|
+
opacity: 0.6;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.edit-button {
|
|
49
|
+
--button-container-shape: var(--shape-corner-full);
|
|
50
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { html, nothing } from 'lit';
|
|
2
|
+
import { property, query, state } from 'lit/decorators.js';
|
|
3
|
+
|
|
4
|
+
import { redispatchEvent } from '@/__utils/dispatch-event-utils.js';
|
|
5
|
+
|
|
6
|
+
import BaseInput from '../input/BaseInput.js';
|
|
7
|
+
import styles from './url-field.scss';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @label URL Field
|
|
11
|
+
* @tag wc-url-field
|
|
12
|
+
* @rawTag url-field
|
|
13
|
+
*
|
|
14
|
+
* @summary A field for entering and displaying URLs with validation.
|
|
15
|
+
* @overview
|
|
16
|
+
* <p>URL Field wraps an input with URL validation, showing a clickable link preview when not in edit mode.</p>
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```html
|
|
20
|
+
* <wc-url-field label="Website" value="https://example.com"></wc-url-field>
|
|
21
|
+
* ```
|
|
22
|
+
* @tags form
|
|
23
|
+
*/
|
|
24
|
+
export class UrlField extends BaseInput {
|
|
25
|
+
static styles = [styles];
|
|
26
|
+
|
|
27
|
+
@property({ type: String })
|
|
28
|
+
value: string = '';
|
|
29
|
+
|
|
30
|
+
@property({ type: String })
|
|
31
|
+
name: string = '';
|
|
32
|
+
|
|
33
|
+
@property({ type: String })
|
|
34
|
+
placeholder: string = '';
|
|
35
|
+
|
|
36
|
+
@property({ type: String })
|
|
37
|
+
label: string = '';
|
|
38
|
+
|
|
39
|
+
@property({ type: Boolean, reflect: true })
|
|
40
|
+
editing: boolean = false;
|
|
41
|
+
|
|
42
|
+
@property({ type: Number })
|
|
43
|
+
debounce: number = 300;
|
|
44
|
+
|
|
45
|
+
@property({ type: String, reflect: true })
|
|
46
|
+
size: 'sm' | 'md' | 'lg' = 'md';
|
|
47
|
+
|
|
48
|
+
@property({ type: String })
|
|
49
|
+
variant: 'filled' | 'outlined' | 'default' = 'default';
|
|
50
|
+
|
|
51
|
+
@property({ type: String, attribute: 'helper-text' })
|
|
52
|
+
helperText: string = '';
|
|
53
|
+
|
|
54
|
+
@property({ type: Boolean })
|
|
55
|
+
error: boolean = false;
|
|
56
|
+
|
|
57
|
+
@property({ type: String, attribute: 'error-text' })
|
|
58
|
+
errorText: string = '';
|
|
59
|
+
|
|
60
|
+
@property({ type: Boolean })
|
|
61
|
+
warning: boolean = false;
|
|
62
|
+
|
|
63
|
+
@property({ type: String, attribute: 'warning-text' })
|
|
64
|
+
warningText: string = '';
|
|
65
|
+
|
|
66
|
+
@state()
|
|
67
|
+
private focused: boolean = false;
|
|
68
|
+
|
|
69
|
+
@state()
|
|
70
|
+
private isValid: boolean = true;
|
|
71
|
+
|
|
72
|
+
@query('.url-input')
|
|
73
|
+
private inputElement?: HTMLInputElement;
|
|
74
|
+
|
|
75
|
+
private debounceTimer?: ReturnType<typeof setTimeout>;
|
|
76
|
+
|
|
77
|
+
override disconnectedCallback(): void {
|
|
78
|
+
super.disconnectedCallback();
|
|
79
|
+
if (this.debounceTimer) {
|
|
80
|
+
clearTimeout(this.debounceTimer);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override focus() {
|
|
85
|
+
if (!this.editing && !this.disabled && !this.readonly) {
|
|
86
|
+
this.startEditing();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.inputElement?.focus();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override blur() {
|
|
93
|
+
this.inputElement?.blur();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private startEditing() {
|
|
97
|
+
if (this.disabled || this.readonly) return;
|
|
98
|
+
this.editing = true;
|
|
99
|
+
setTimeout(() => this.inputElement?.focus(), 80);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private closeEditing() {
|
|
103
|
+
this.isValid = this.validateUrl(this.value);
|
|
104
|
+
this.dispatchEvent(
|
|
105
|
+
new CustomEvent('input-invalid', {
|
|
106
|
+
detail: !this.isValid,
|
|
107
|
+
bubbles: true,
|
|
108
|
+
composed: true,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (this.isValid) {
|
|
113
|
+
this.editing = false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private validateUrl(url: string): boolean {
|
|
118
|
+
if (!url) return true;
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
new URL(url);
|
|
122
|
+
return true;
|
|
123
|
+
} catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private handleInput(event: InputEvent) {
|
|
129
|
+
this.value = (event.target as HTMLInputElement).value;
|
|
130
|
+
this.isValid = true;
|
|
131
|
+
|
|
132
|
+
if (this.debounceTimer) {
|
|
133
|
+
clearTimeout(this.debounceTimer);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.debounceTimer = setTimeout(() => {
|
|
137
|
+
this.dispatchEvent(
|
|
138
|
+
new CustomEvent('value-change', {
|
|
139
|
+
detail: this.value,
|
|
140
|
+
bubbles: true,
|
|
141
|
+
composed: true,
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
}, this.debounce);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private handleFocusChange() {
|
|
148
|
+
this.focused = this.inputElement?.matches(':focus') ?? false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private handleBlur() {
|
|
152
|
+
this.focused = false;
|
|
153
|
+
this.closeEditing();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private handleChange(event: Event) {
|
|
157
|
+
redispatchEvent(this, event);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private renderDisplayValue() {
|
|
161
|
+
if (!this.value) {
|
|
162
|
+
return html`<span class="url-placeholder">${this.placeholder}</span>`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return html`
|
|
166
|
+
<a
|
|
167
|
+
class="url-link"
|
|
168
|
+
href=${this.value}
|
|
169
|
+
target="_blank"
|
|
170
|
+
rel="noopener noreferrer"
|
|
171
|
+
>
|
|
172
|
+
${this.value}
|
|
173
|
+
</a>
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
render() {
|
|
178
|
+
const hasValue = !!this.value;
|
|
179
|
+
const showInvalidState = this.error || !this.isValid;
|
|
180
|
+
const resolvedErrorText = !this.isValid
|
|
181
|
+
? 'Please enter a valid URL'
|
|
182
|
+
: this.errorText;
|
|
183
|
+
|
|
184
|
+
return html`
|
|
185
|
+
<wc-field
|
|
186
|
+
label=${this.label}
|
|
187
|
+
?required=${this.required}
|
|
188
|
+
?disabled=${this.disabled}
|
|
189
|
+
?readonly=${this.readonly}
|
|
190
|
+
?skeleton=${this.skeleton}
|
|
191
|
+
helper-text=${this.helperText}
|
|
192
|
+
?error=${showInvalidState}
|
|
193
|
+
error-text=${resolvedErrorText}
|
|
194
|
+
?warning=${this.warning}
|
|
195
|
+
warning-text=${this.warningText}
|
|
196
|
+
variant=${this.variant}
|
|
197
|
+
?populated=${hasValue || this.editing}
|
|
198
|
+
?focused=${this.focused}
|
|
199
|
+
.host=${this}
|
|
200
|
+
class="url-field-wrapper"
|
|
201
|
+
>
|
|
202
|
+
${this.editing
|
|
203
|
+
? html`
|
|
204
|
+
<input
|
|
205
|
+
class="url-input"
|
|
206
|
+
name=${this.name}
|
|
207
|
+
type="url"
|
|
208
|
+
placeholder=${this.placeholder}
|
|
209
|
+
.value=${this.value}
|
|
210
|
+
?readonly=${this.readonly}
|
|
211
|
+
?required=${this.required}
|
|
212
|
+
?disabled=${this.disabled}
|
|
213
|
+
@input=${this.handleInput}
|
|
214
|
+
@change=${this.handleChange}
|
|
215
|
+
@focus=${this.handleFocusChange}
|
|
216
|
+
@blur=${this.handleBlur}
|
|
217
|
+
/>
|
|
218
|
+
`
|
|
219
|
+
: html`<div class="url-display">${this.renderDisplayValue()}</div>`}
|
|
220
|
+
|
|
221
|
+
${!this.editing && !this.disabled && !this.readonly
|
|
222
|
+
? html`
|
|
223
|
+
<wc-icon-button
|
|
224
|
+
class="edit-button"
|
|
225
|
+
slot="field-end"
|
|
226
|
+
variant="text"
|
|
227
|
+
@click=${(event: MouseEvent) => {
|
|
228
|
+
event.stopPropagation();
|
|
229
|
+
this.startEditing();
|
|
230
|
+
}}
|
|
231
|
+
>
|
|
232
|
+
<wc-icon name="edit"></wc-icon>
|
|
233
|
+
</wc-icon-button>
|
|
234
|
+
`
|
|
235
|
+
: nothing}
|
|
236
|
+
</wc-field>
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
}
|