@waggylabs/yumekit 0.2.0 → 0.2.2
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/components/y-appbar.d.ts +21 -0
- package/dist/components/y-appbar.js +310 -22
- package/dist/components/y-badge.d.ts +5 -0
- package/dist/components/y-badge.js +5 -0
- package/dist/components/y-button.d.ts +6 -1
- package/dist/components/y-button.js +5 -0
- package/dist/components/y-checkbox.d.ts +7 -1
- package/dist/components/y-checkbox.js +6 -0
- package/dist/components/y-dialog.d.ts +11 -0
- package/dist/components/y-dialog.js +44 -25
- package/dist/components/y-drawer.js +1 -2
- package/dist/components/y-icon.d.ts +5 -0
- package/dist/components/y-icon.js +16 -8
- package/dist/components/y-input.d.ts +5 -0
- package/dist/components/y-input.js +6 -0
- package/dist/components/y-menu.d.ts +1 -0
- package/dist/components/y-menu.js +28 -1
- package/dist/components/y-panel.d.ts +10 -1
- package/dist/components/y-panel.js +21 -0
- package/dist/components/y-progress.d.ts +11 -0
- package/dist/components/y-progress.js +14 -0
- package/dist/components/y-radio.d.ts +11 -2
- package/dist/components/y-radio.js +3 -0
- package/dist/components/y-select.d.ts +19 -5
- package/dist/components/y-select.js +19 -0
- package/dist/components/y-slider.d.ts +11 -2
- package/dist/components/y-slider.js +10 -0
- package/dist/components/y-switch.d.ts +3 -0
- package/dist/components/y-switch.js +8 -2
- package/dist/components/y-table.d.ts +3 -0
- package/dist/components/y-table.js +4 -1
- package/dist/components/y-tabs.d.ts +14 -7
- package/dist/components/y-tabs.js +9 -0
- package/dist/components/y-theme.d.ts +6 -1
- package/dist/components/y-theme.js +11 -4
- package/dist/components/y-toast.d.ts +4 -0
- package/dist/components/y-toast.js +7 -0
- package/dist/components/y-tooltip.d.ts +6 -0
- package/dist/components/y-tooltip.js +8 -0
- package/dist/icons/all.js +42 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/index.js +528 -56
- package/dist/styles/variables.css +9 -6
- package/dist/yumekit.min.js +1 -1
- package/package.json +1 -1
|
@@ -5,14 +5,20 @@ export class YumeCheckbox extends HTMLElement {
|
|
|
5
5
|
connectedCallback(): void;
|
|
6
6
|
attributeChangedCallback(name: any): void;
|
|
7
7
|
set checked(val: boolean);
|
|
8
|
+
/** @type {boolean} Whether the checkbox is checked. */
|
|
8
9
|
get checked(): boolean;
|
|
9
10
|
set disabled(val: boolean);
|
|
11
|
+
/** @type {boolean} Whether the checkbox is disabled. */
|
|
10
12
|
get disabled(): boolean;
|
|
11
13
|
set indeterminate(val: boolean);
|
|
14
|
+
/** @type {boolean} Whether the checkbox is in an indeterminate state. */
|
|
12
15
|
get indeterminate(): boolean;
|
|
13
16
|
set value(val: string);
|
|
17
|
+
/** @type {string} The form value submitted when checked. Defaults to "on". */
|
|
14
18
|
get value(): string;
|
|
15
|
-
|
|
19
|
+
/** @type {string|null} The form name of the checkbox. */
|
|
20
|
+
get name(): string | null;
|
|
21
|
+
/** Toggles the checked state and dispatches a "change" event. */
|
|
16
22
|
toggle(): void;
|
|
17
23
|
updateIcon(): void;
|
|
18
24
|
updateState(): void;
|
|
@@ -59,6 +59,7 @@ class YumeCheckbox extends HTMLElement {
|
|
|
59
59
|
this.updateState();
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** @type {boolean} Whether the checkbox is checked. */
|
|
62
63
|
get checked() {
|
|
63
64
|
return this.hasAttribute("checked");
|
|
64
65
|
}
|
|
@@ -68,6 +69,7 @@ class YumeCheckbox extends HTMLElement {
|
|
|
68
69
|
else this.removeAttribute("checked");
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/** @type {boolean} Whether the checkbox is disabled. */
|
|
71
73
|
get disabled() {
|
|
72
74
|
return this.hasAttribute("disabled");
|
|
73
75
|
}
|
|
@@ -77,6 +79,7 @@ class YumeCheckbox extends HTMLElement {
|
|
|
77
79
|
else this.removeAttribute("disabled");
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
/** @type {boolean} Whether the checkbox is in an indeterminate state. */
|
|
80
83
|
get indeterminate() {
|
|
81
84
|
return this.hasAttribute("indeterminate");
|
|
82
85
|
}
|
|
@@ -86,6 +89,7 @@ class YumeCheckbox extends HTMLElement {
|
|
|
86
89
|
else this.removeAttribute("indeterminate");
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/** @type {string} The form value submitted when checked. Defaults to "on". */
|
|
89
93
|
get value() {
|
|
90
94
|
return this.getAttribute("value") || "on";
|
|
91
95
|
}
|
|
@@ -94,10 +98,12 @@ class YumeCheckbox extends HTMLElement {
|
|
|
94
98
|
this.setAttribute("value", val);
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
/** @type {string|null} The form name of the checkbox. */
|
|
97
102
|
get name() {
|
|
98
103
|
return this.getAttribute("name");
|
|
99
104
|
}
|
|
100
105
|
|
|
106
|
+
/** Toggles the checked state and dispatches a "change" event. */
|
|
101
107
|
toggle() {
|
|
102
108
|
if (this.disabled) return;
|
|
103
109
|
if (this.indeterminate) {
|
|
@@ -5,12 +5,23 @@ declare class YumeDialog extends HTMLElement {
|
|
|
5
5
|
connectedCallback(): void;
|
|
6
6
|
attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
|
|
7
7
|
set visible(val: boolean);
|
|
8
|
+
/** Whether the dialog is currently displayed. */
|
|
8
9
|
get visible(): boolean;
|
|
9
10
|
set anchor(id: string);
|
|
11
|
+
/** The id of the element that toggles this dialog on click. */
|
|
10
12
|
get anchor(): string;
|
|
11
13
|
set closable(val: boolean);
|
|
14
|
+
/** Whether the dialog renders a close button in the header. */
|
|
12
15
|
get closable(): boolean;
|
|
16
|
+
set showBackdrop(val: boolean);
|
|
17
|
+
/** Whether to apply a blurred backdrop behind the dialog. */
|
|
18
|
+
get showBackdrop(): boolean;
|
|
19
|
+
set animate(val: boolean);
|
|
20
|
+
/** Whether the dialog uses an entrance animation. */
|
|
21
|
+
get animate(): boolean;
|
|
22
|
+
/** Opens the dialog and focuses it. */
|
|
13
23
|
show(): void;
|
|
24
|
+
/** Closes the dialog. */
|
|
14
25
|
hide(): void;
|
|
15
26
|
setupAnchor(): void;
|
|
16
27
|
_anchorEl: HTMLElement;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class YumeDialog extends HTMLElement {
|
|
2
2
|
static get observedAttributes() {
|
|
3
|
-
return ["visible", "anchor", "closable"];
|
|
3
|
+
return ["visible", "anchor", "closable", "show-backdrop", "animate"];
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
constructor() {
|
|
@@ -29,6 +29,7 @@ class YumeDialog extends HTMLElement {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/** Whether the dialog is currently displayed. */
|
|
32
33
|
get visible() {
|
|
33
34
|
return this.hasAttribute("visible");
|
|
34
35
|
}
|
|
@@ -38,6 +39,7 @@ class YumeDialog extends HTMLElement {
|
|
|
38
39
|
else this.removeAttribute("visible");
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
/** The id of the element that toggles this dialog on click. */
|
|
41
43
|
get anchor() {
|
|
42
44
|
return this.getAttribute("anchor");
|
|
43
45
|
}
|
|
@@ -46,6 +48,7 @@ class YumeDialog extends HTMLElement {
|
|
|
46
48
|
this.setAttribute("anchor", id);
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
/** Whether the dialog renders a close button in the header. */
|
|
49
52
|
get closable() {
|
|
50
53
|
return this.hasAttribute("closable");
|
|
51
54
|
}
|
|
@@ -54,6 +57,25 @@ class YumeDialog extends HTMLElement {
|
|
|
54
57
|
else this.removeAttribute("closable");
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
/** Whether to apply a blurred backdrop behind the dialog. */
|
|
61
|
+
get showBackdrop() {
|
|
62
|
+
return this.hasAttribute("show-backdrop");
|
|
63
|
+
}
|
|
64
|
+
set showBackdrop(val) {
|
|
65
|
+
if (val) this.setAttribute("show-backdrop", "");
|
|
66
|
+
else this.removeAttribute("show-backdrop");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Whether the dialog uses an entrance animation. */
|
|
70
|
+
get animate() {
|
|
71
|
+
return this.hasAttribute("animate");
|
|
72
|
+
}
|
|
73
|
+
set animate(val) {
|
|
74
|
+
if (val) this.setAttribute("animate", "");
|
|
75
|
+
else this.removeAttribute("animate");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Opens the dialog and focuses it. */
|
|
57
79
|
show() {
|
|
58
80
|
if (!this.shadowRoot.querySelector(".dialog")) {
|
|
59
81
|
this.render();
|
|
@@ -67,6 +89,7 @@ class YumeDialog extends HTMLElement {
|
|
|
67
89
|
}
|
|
68
90
|
}
|
|
69
91
|
|
|
92
|
+
/** Closes the dialog. */
|
|
70
93
|
hide() {
|
|
71
94
|
document.removeEventListener("keydown", this.onKeyDown);
|
|
72
95
|
}
|
|
@@ -107,6 +130,16 @@ class YumeDialog extends HTMLElement {
|
|
|
107
130
|
z-index: var(--component-dialog-z-index, 1000);
|
|
108
131
|
}
|
|
109
132
|
:host([visible]) { display: flex; }
|
|
133
|
+
:host([show-backdrop]) {
|
|
134
|
+
backdrop-filter: blur(var(--component-dialog-backdrop-blur, 4px));
|
|
135
|
+
-webkit-backdrop-filter: blur(var(--component-dialog-backdrop-blur, 4px));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@keyframes dialog-fade-in {
|
|
139
|
+
from { opacity: 0; transform: translateY(16px) scale(0.97); }
|
|
140
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
141
|
+
}
|
|
142
|
+
|
|
110
143
|
.dialog {
|
|
111
144
|
background: var(--component-dialog-background);
|
|
112
145
|
border: var(--component-dialog-border-width, 1px) solid var(--component-dialog-border-color);
|
|
@@ -117,6 +150,9 @@ class YumeDialog extends HTMLElement {
|
|
|
117
150
|
flex-direction: column;
|
|
118
151
|
box-shadow: var(--component-dialog-shadow, 0 2px 10px rgba(0,0,0,0.3));
|
|
119
152
|
}
|
|
153
|
+
:host([animate][visible]) .dialog {
|
|
154
|
+
animation: dialog-fade-in var(--component-dialog-animation-duration, 0.2s) ease-out both;
|
|
155
|
+
}
|
|
120
156
|
.header {
|
|
121
157
|
padding: var(--component-dialog-padding, var(--spacing-medium));
|
|
122
158
|
font-weight: bold;
|
|
@@ -129,26 +165,6 @@ class YumeDialog extends HTMLElement {
|
|
|
129
165
|
.header-content {
|
|
130
166
|
flex: 1;
|
|
131
167
|
}
|
|
132
|
-
.close-btn {
|
|
133
|
-
background: none;
|
|
134
|
-
border: none;
|
|
135
|
-
cursor: pointer;
|
|
136
|
-
padding: var(--spacing-x-small, 4px);
|
|
137
|
-
color: var(--component-dialog-color, #f7f7fa);
|
|
138
|
-
font-size: 1.25em;
|
|
139
|
-
line-height: 1;
|
|
140
|
-
border-radius: var(--component-button-border-radius-outer, 4px);
|
|
141
|
-
display: flex;
|
|
142
|
-
align-items: center;
|
|
143
|
-
justify-content: center;
|
|
144
|
-
}
|
|
145
|
-
.close-btn:hover {
|
|
146
|
-
background: var(--component-dialog-hover-background, #292a2b);
|
|
147
|
-
}
|
|
148
|
-
.close-btn:focus-visible {
|
|
149
|
-
outline: 2px solid var(--component-dialog-accent);
|
|
150
|
-
outline-offset: -1px;
|
|
151
|
-
}
|
|
152
168
|
.body {
|
|
153
169
|
padding: var(--component-dialog-padding, var(--spacing-medium));
|
|
154
170
|
overflow: auto;
|
|
@@ -184,10 +200,11 @@ class YumeDialog extends HTMLElement {
|
|
|
184
200
|
header.appendChild(headerContent);
|
|
185
201
|
|
|
186
202
|
if (this.closable) {
|
|
187
|
-
const closeBtn = document.createElement("button");
|
|
188
|
-
closeBtn.
|
|
203
|
+
const closeBtn = document.createElement("y-button");
|
|
204
|
+
closeBtn.setAttribute("size", "small");
|
|
205
|
+
closeBtn.setAttribute("style-type", "flat");
|
|
189
206
|
closeBtn.setAttribute("aria-label", "Close");
|
|
190
|
-
closeBtn.
|
|
207
|
+
closeBtn.textContent = "\u2715";
|
|
191
208
|
closeBtn.addEventListener("click", () => {
|
|
192
209
|
this.visible = false;
|
|
193
210
|
});
|
|
@@ -209,18 +226,20 @@ class YumeDialog extends HTMLElement {
|
|
|
209
226
|
dialog.appendChild(footer);
|
|
210
227
|
this.shadowRoot.appendChild(dialog);
|
|
211
228
|
|
|
212
|
-
// Hide slot containers that have no slotted content
|
|
213
229
|
const hideIfEmpty = (wrapper) => {
|
|
214
230
|
const slot = wrapper.querySelector("slot");
|
|
215
231
|
if (!slot) return;
|
|
232
|
+
|
|
216
233
|
const update = () => {
|
|
217
234
|
const hasContent =
|
|
218
235
|
slot.assignedNodes({ flatten: true }).length > 0;
|
|
219
236
|
wrapper.style.display = hasContent ? "" : "none";
|
|
220
237
|
};
|
|
238
|
+
|
|
221
239
|
slot.addEventListener("slotchange", update);
|
|
222
240
|
update();
|
|
223
241
|
};
|
|
242
|
+
|
|
224
243
|
if (!this.closable) hideIfEmpty(header);
|
|
225
244
|
hideIfEmpty(body);
|
|
226
245
|
hideIfEmpty(footer);
|
|
@@ -130,8 +130,7 @@ class YumeDrawer extends HTMLElement {
|
|
|
130
130
|
|
|
131
131
|
_show() {
|
|
132
132
|
this.style.display = "block";
|
|
133
|
-
|
|
134
|
-
this.offsetHeight; // eslint-disable-line no-unused-expressions
|
|
133
|
+
this.offsetHeight;
|
|
135
134
|
|
|
136
135
|
const overlay = this.shadowRoot.querySelector(".overlay");
|
|
137
136
|
const panel = this.shadowRoot.querySelector(".drawer-panel");
|
|
@@ -3,14 +3,19 @@ export class YumeIcon extends HTMLElement {
|
|
|
3
3
|
connectedCallback(): void;
|
|
4
4
|
attributeChangedCallback(name: any, oldVal: any, newVal: any): void;
|
|
5
5
|
set name(val: string);
|
|
6
|
+
/** The registered icon name to display. */
|
|
6
7
|
get name(): string;
|
|
7
8
|
set size(val: string);
|
|
9
|
+
/** Icon size: "small" | "medium" | "large" (default "medium"). */
|
|
8
10
|
get size(): string;
|
|
9
11
|
set color(val: string);
|
|
12
|
+
/** Color theme: "base" | "primary" | "secondary" | "success" | "warning" | "error" | "help". */
|
|
10
13
|
get color(): string;
|
|
11
14
|
set label(val: string);
|
|
15
|
+
/** Accessible label for the icon. When set, the icon gets role="img". */
|
|
12
16
|
get label(): string;
|
|
13
17
|
set weight(val: string);
|
|
18
|
+
/** Stroke weight: "thin" | "regular" | "thick". */
|
|
14
19
|
get weight(): string;
|
|
15
20
|
_getColor(color: any): any;
|
|
16
21
|
_getSize(size: any): any;
|
|
@@ -108,7 +108,6 @@ function sanitizeSvg(raw) {
|
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
-
// Sanitize the <svg> element's own attributes
|
|
112
111
|
for (const attr of [...svg.attributes]) {
|
|
113
112
|
if (!ALLOWED_ATTRS.has(attr.name.toLowerCase())) {
|
|
114
113
|
svg.removeAttribute(attr.name);
|
|
@@ -150,6 +149,7 @@ class YumeIcon extends HTMLElement {
|
|
|
150
149
|
this.render();
|
|
151
150
|
}
|
|
152
151
|
|
|
152
|
+
/** The registered icon name to display. */
|
|
153
153
|
get name() {
|
|
154
154
|
return this.getAttribute("name") || "";
|
|
155
155
|
}
|
|
@@ -157,6 +157,7 @@ class YumeIcon extends HTMLElement {
|
|
|
157
157
|
this.setAttribute("name", val);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/** Icon size: "small" | "medium" | "large" (default "medium"). */
|
|
160
161
|
get size() {
|
|
161
162
|
return this.getAttribute("size") || "medium";
|
|
162
163
|
}
|
|
@@ -164,6 +165,7 @@ class YumeIcon extends HTMLElement {
|
|
|
164
165
|
this.setAttribute("size", val);
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
/** Color theme: "base" | "primary" | "secondary" | "success" | "warning" | "error" | "help". */
|
|
167
169
|
get color() {
|
|
168
170
|
return this.getAttribute("color") || "";
|
|
169
171
|
}
|
|
@@ -172,6 +174,7 @@ class YumeIcon extends HTMLElement {
|
|
|
172
174
|
else this.removeAttribute("color");
|
|
173
175
|
}
|
|
174
176
|
|
|
177
|
+
/** Accessible label for the icon. When set, the icon gets role="img". */
|
|
175
178
|
get label() {
|
|
176
179
|
return this.getAttribute("label") || "";
|
|
177
180
|
}
|
|
@@ -180,8 +183,9 @@ class YumeIcon extends HTMLElement {
|
|
|
180
183
|
else this.removeAttribute("label");
|
|
181
184
|
}
|
|
182
185
|
|
|
186
|
+
/** Stroke weight: "thin" | "regular" | "thick". */
|
|
183
187
|
get weight() {
|
|
184
|
-
return this.getAttribute("weight") || "";
|
|
188
|
+
return this.getAttribute("weight") || "regular";
|
|
185
189
|
}
|
|
186
190
|
set weight(val) {
|
|
187
191
|
if (val) this.setAttribute("weight", val);
|
|
@@ -203,18 +207,22 @@ class YumeIcon extends HTMLElement {
|
|
|
203
207
|
|
|
204
208
|
_getSize(size) {
|
|
205
209
|
const map = {
|
|
206
|
-
small: "var(--component-icon-size-small,
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
"x-small": "var(--component-icon-size-x-small, 10px)",
|
|
211
|
+
small: "var(--component-icon-size-small, 14px)",
|
|
212
|
+
medium: "var(--component-icon-size-medium, 18px)",
|
|
213
|
+
large: "var(--component-icon-size-large, 22px)",
|
|
214
|
+
"x-large": "var(--component-icon-size-x-large, 28px)",
|
|
209
215
|
};
|
|
210
216
|
return map[size] || map.medium;
|
|
211
217
|
}
|
|
212
218
|
|
|
213
219
|
_getWeight(weight) {
|
|
214
220
|
const map = {
|
|
215
|
-
thin: "1",
|
|
216
|
-
|
|
217
|
-
|
|
221
|
+
"x-thin": "1",
|
|
222
|
+
thin: "1.5",
|
|
223
|
+
regular: "2",
|
|
224
|
+
thick: "2.5",
|
|
225
|
+
"x-thick": "3",
|
|
218
226
|
};
|
|
219
227
|
return map[weight] || "";
|
|
220
228
|
}
|
|
@@ -5,7 +5,12 @@ export class YumeInput extends HTMLElement {
|
|
|
5
5
|
connectedCallback(): void;
|
|
6
6
|
attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
|
|
7
7
|
set value(val: string);
|
|
8
|
+
/** @type {string} The current input value. */
|
|
8
9
|
get value(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Checks the validity of the underlying input element.
|
|
12
|
+
* @returns {boolean} Whether the input is valid.
|
|
13
|
+
*/
|
|
9
14
|
checkValidity(): boolean;
|
|
10
15
|
updateValidationState(): void;
|
|
11
16
|
render(): void;
|
|
@@ -57,6 +57,7 @@ class YumeInput extends HTMLElement {
|
|
|
57
57
|
this.render();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/** @type {string} The current input value. */
|
|
60
61
|
get value() {
|
|
61
62
|
return this.input?.value || "";
|
|
62
63
|
}
|
|
@@ -67,6 +68,10 @@ class YumeInput extends HTMLElement {
|
|
|
67
68
|
this._internals.setFormValue(val, this.getAttribute("name"));
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Checks the validity of the underlying input element.
|
|
73
|
+
* @returns {boolean} Whether the input is valid.
|
|
74
|
+
*/
|
|
70
75
|
checkValidity() {
|
|
71
76
|
return this.input?.checkValidity?.() ?? true;
|
|
72
77
|
}
|
|
@@ -102,6 +107,7 @@ class YumeInput extends HTMLElement {
|
|
|
102
107
|
}[size] || "var(--sizing-medium, 40px)";
|
|
103
108
|
|
|
104
109
|
const sheet = new CSSStyleSheet();
|
|
110
|
+
|
|
105
111
|
sheet.replaceSync(`
|
|
106
112
|
:host {
|
|
107
113
|
display: block;
|
|
@@ -13,11 +13,14 @@ class YumeMenu extends HTMLElement {
|
|
|
13
13
|
|
|
14
14
|
connectedCallback() {
|
|
15
15
|
if (!this.hasAttribute("items")) this.items = [];
|
|
16
|
+
|
|
16
17
|
this._setupAnchor();
|
|
17
18
|
this.render();
|
|
19
|
+
|
|
18
20
|
document.addEventListener("click", this._onDocumentClick);
|
|
19
21
|
window.addEventListener("scroll", this._onScrollOrResize, true);
|
|
20
22
|
window.addEventListener("resize", this._onScrollOrResize);
|
|
23
|
+
|
|
21
24
|
this.style.position = "fixed";
|
|
22
25
|
this.style.zIndex = "1000";
|
|
23
26
|
this.style.display = "none";
|
|
@@ -25,6 +28,7 @@ class YumeMenu extends HTMLElement {
|
|
|
25
28
|
|
|
26
29
|
disconnectedCallback() {
|
|
27
30
|
this._teardownAnchor();
|
|
31
|
+
|
|
28
32
|
document.removeEventListener("click", this._onDocumentClick);
|
|
29
33
|
window.removeEventListener("scroll", this._onScrollOrResize, true);
|
|
30
34
|
window.removeEventListener("resize", this._onScrollOrResize);
|
|
@@ -32,14 +36,18 @@ class YumeMenu extends HTMLElement {
|
|
|
32
36
|
|
|
33
37
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
34
38
|
if (oldVal === newVal) return;
|
|
39
|
+
|
|
35
40
|
if (name === "items" || name === "size") this.render();
|
|
41
|
+
|
|
36
42
|
if (name === "anchor") {
|
|
37
43
|
this._teardownAnchor();
|
|
38
44
|
this._setupAnchor();
|
|
39
45
|
}
|
|
46
|
+
|
|
40
47
|
if (name === "visible") {
|
|
41
48
|
this._updatePosition();
|
|
42
49
|
}
|
|
50
|
+
|
|
43
51
|
if (name === "direction") {
|
|
44
52
|
this._updatePosition();
|
|
45
53
|
}
|
|
@@ -150,9 +158,20 @@ class YumeMenu extends HTMLElement {
|
|
|
150
158
|
|
|
151
159
|
_onAnchorClick(e) {
|
|
152
160
|
e.stopPropagation();
|
|
161
|
+
if (!this.visible) {
|
|
162
|
+
YumeMenu._closeAll(this);
|
|
163
|
+
}
|
|
153
164
|
this.visible = !this.visible;
|
|
154
165
|
}
|
|
155
166
|
|
|
167
|
+
static _closeAll(except) {
|
|
168
|
+
document.querySelectorAll("y-menu").forEach((menu) => {
|
|
169
|
+
if (menu !== except && menu.visible) {
|
|
170
|
+
menu.visible = false;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
_onDocumentClick(e) {
|
|
157
176
|
const path = e.composedPath();
|
|
158
177
|
if (this._anchorEl && path.includes(this._anchorEl)) return;
|
|
@@ -192,7 +211,13 @@ class YumeMenu extends HTMLElement {
|
|
|
192
211
|
}
|
|
193
212
|
|
|
194
213
|
const anchorRect = this._anchorEl.getBoundingClientRect();
|
|
214
|
+
|
|
215
|
+
// Temporarily show off-screen to measure actual dimensions
|
|
216
|
+
this.style.visibility = "hidden";
|
|
217
|
+
this.style.display = "block";
|
|
195
218
|
const menuRect = this.getBoundingClientRect();
|
|
219
|
+
this.style.visibility = "";
|
|
220
|
+
|
|
196
221
|
const vw = window.innerWidth;
|
|
197
222
|
const vh = window.innerHeight;
|
|
198
223
|
|
|
@@ -253,8 +278,8 @@ class YumeMenu extends HTMLElement {
|
|
|
253
278
|
this.shadowRoot.innerHTML = "";
|
|
254
279
|
|
|
255
280
|
const paddingVar = `var(--component-button-padding-${this.size}, 0.5rem)`;
|
|
256
|
-
|
|
257
281
|
const style = document.createElement("style");
|
|
282
|
+
|
|
258
283
|
style.textContent = `
|
|
259
284
|
ul.menu,
|
|
260
285
|
ul.submenu {
|
|
@@ -307,12 +332,14 @@ class YumeMenu extends HTMLElement {
|
|
|
307
332
|
flex: 1;
|
|
308
333
|
}
|
|
309
334
|
`;
|
|
335
|
+
|
|
310
336
|
this.shadowRoot.appendChild(style);
|
|
311
337
|
|
|
312
338
|
const rootUl = this._createMenuList(this.items);
|
|
313
339
|
rootUl.classList.add("menu");
|
|
314
340
|
rootUl.setAttribute("role", "menu");
|
|
315
341
|
rootUl.setAttribute("part", "menu");
|
|
342
|
+
|
|
316
343
|
this.shadowRoot.appendChild(rootUl);
|
|
317
344
|
}
|
|
318
345
|
}
|
|
@@ -6,17 +6,26 @@ export class YumePanel extends HTMLElement {
|
|
|
6
6
|
disconnectedCallback(): void;
|
|
7
7
|
attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
|
|
8
8
|
set selected(val: boolean);
|
|
9
|
+
/** @type {boolean} Whether the panel is in a selected/active state. */
|
|
9
10
|
get selected(): boolean;
|
|
10
11
|
set expanded(val: boolean);
|
|
12
|
+
/** @type {boolean} Whether the panel's children slot is visible. */
|
|
11
13
|
get expanded(): boolean;
|
|
14
|
+
/** Toggles the expanded state (collapses siblings when inside an exclusive panelbar). */
|
|
12
15
|
toggle(): void;
|
|
16
|
+
/** Expands the panel to show its children. */
|
|
13
17
|
expand(): void;
|
|
18
|
+
/** Collapses the panel to hide its children. */
|
|
14
19
|
collapse(): void;
|
|
15
20
|
updateSelectedState(): void;
|
|
16
21
|
updateChildState(): void;
|
|
17
22
|
checkRouteMatch(): void;
|
|
18
23
|
addHeaderListeners(): void;
|
|
19
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether the panel has slotted children content.
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
hasChildren(): boolean;
|
|
20
29
|
checkForChildren(): void;
|
|
21
30
|
updateExpandedState(): void;
|
|
22
31
|
render(): void;
|
|
@@ -18,8 +18,10 @@ class YumePanel extends HTMLElement {
|
|
|
18
18
|
constructor() {
|
|
19
19
|
super();
|
|
20
20
|
this.attachShadow({ mode: "open" });
|
|
21
|
+
|
|
21
22
|
this._expanded = false;
|
|
22
23
|
this._checkRouteMatchBound = this.checkRouteMatch.bind(this);
|
|
24
|
+
|
|
23
25
|
this.render();
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -58,6 +60,7 @@ class YumePanel extends HTMLElement {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
/** @type {boolean} Whether the panel is in a selected/active state. */
|
|
61
64
|
get selected() {
|
|
62
65
|
return this.hasAttribute("selected");
|
|
63
66
|
}
|
|
@@ -67,6 +70,7 @@ class YumePanel extends HTMLElement {
|
|
|
67
70
|
else this.removeAttribute("selected");
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
/** @type {boolean} Whether the panel's children slot is visible. */
|
|
70
74
|
get expanded() {
|
|
71
75
|
return this.hasAttribute("expanded");
|
|
72
76
|
}
|
|
@@ -76,8 +80,10 @@ class YumePanel extends HTMLElement {
|
|
|
76
80
|
else this.removeAttribute("expanded");
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
/** Toggles the expanded state (collapses siblings when inside an exclusive panelbar). */
|
|
79
84
|
toggle() {
|
|
80
85
|
if (!this.hasChildren()) return;
|
|
86
|
+
|
|
81
87
|
if (!this._expanded) {
|
|
82
88
|
const parentBar = this.closest("y-panelbar");
|
|
83
89
|
if (parentBar && parentBar.hasAttribute("exclusive")) {
|
|
@@ -97,6 +103,7 @@ class YumePanel extends HTMLElement {
|
|
|
97
103
|
} else {
|
|
98
104
|
this.collapse();
|
|
99
105
|
}
|
|
106
|
+
|
|
100
107
|
this.dispatchEvent(
|
|
101
108
|
new CustomEvent("toggle", {
|
|
102
109
|
detail: { expanded: this._expanded },
|
|
@@ -106,6 +113,7 @@ class YumePanel extends HTMLElement {
|
|
|
106
113
|
);
|
|
107
114
|
}
|
|
108
115
|
|
|
116
|
+
/** Expands the panel to show its children. */
|
|
109
117
|
expand() {
|
|
110
118
|
if (!this.hasChildren()) return;
|
|
111
119
|
this.expanded = true;
|
|
@@ -120,6 +128,7 @@ class YumePanel extends HTMLElement {
|
|
|
120
128
|
);
|
|
121
129
|
}
|
|
122
130
|
|
|
131
|
+
/** Collapses the panel to hide its children. */
|
|
123
132
|
collapse() {
|
|
124
133
|
this.expanded = false;
|
|
125
134
|
this._expanded = false;
|
|
@@ -149,6 +158,7 @@ class YumePanel extends HTMLElement {
|
|
|
149
158
|
break;
|
|
150
159
|
}
|
|
151
160
|
}
|
|
161
|
+
|
|
152
162
|
this.setAttribute("data-is-child", depth > 0 ? "true" : "false");
|
|
153
163
|
this.style.setProperty("--panel-depth", depth);
|
|
154
164
|
}
|
|
@@ -204,6 +214,7 @@ class YumePanel extends HTMLElement {
|
|
|
204
214
|
const childrenSlot = this.shadowRoot.querySelector(
|
|
205
215
|
'slot[name="children"]',
|
|
206
216
|
);
|
|
217
|
+
|
|
207
218
|
if (childrenSlot) {
|
|
208
219
|
childrenSlot.addEventListener("slotchange", () =>
|
|
209
220
|
this.checkForChildren(),
|
|
@@ -211,11 +222,17 @@ class YumePanel extends HTMLElement {
|
|
|
211
222
|
}
|
|
212
223
|
}
|
|
213
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Checks whether the panel has slotted children content.
|
|
227
|
+
* @returns {boolean}
|
|
228
|
+
*/
|
|
214
229
|
hasChildren() {
|
|
215
230
|
const childrenSlot = this.shadowRoot.querySelector(
|
|
216
231
|
'slot[name="children"]',
|
|
217
232
|
);
|
|
233
|
+
|
|
218
234
|
if (!childrenSlot) return false;
|
|
235
|
+
|
|
219
236
|
const nodes = childrenSlot.assignedNodes({ flatten: true });
|
|
220
237
|
return nodes.some((n) => {
|
|
221
238
|
if (n.nodeType === Node.TEXT_NODE) {
|
|
@@ -227,7 +244,9 @@ class YumePanel extends HTMLElement {
|
|
|
227
244
|
|
|
228
245
|
checkForChildren() {
|
|
229
246
|
const hasChildren = this.hasChildren();
|
|
247
|
+
|
|
230
248
|
this.setAttribute("data-has-children", hasChildren ? "true" : "false");
|
|
249
|
+
|
|
231
250
|
if (!hasChildren && this.expanded) {
|
|
232
251
|
this.expanded = false;
|
|
233
252
|
}
|
|
@@ -237,6 +256,7 @@ class YumePanel extends HTMLElement {
|
|
|
237
256
|
const hasChildren = this.hasChildren();
|
|
238
257
|
const header = this.shadowRoot.querySelector(".header");
|
|
239
258
|
const isExpanded = this.expanded && hasChildren;
|
|
259
|
+
|
|
240
260
|
this._expanded = isExpanded;
|
|
241
261
|
|
|
242
262
|
if (header) {
|
|
@@ -246,6 +266,7 @@ class YumePanel extends HTMLElement {
|
|
|
246
266
|
|
|
247
267
|
render() {
|
|
248
268
|
const sheet = new CSSStyleSheet();
|
|
269
|
+
|
|
249
270
|
sheet.replaceSync(`
|
|
250
271
|
:host {
|
|
251
272
|
display: block;
|