@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.
Files changed (45) hide show
  1. package/dist/components/y-appbar.d.ts +21 -0
  2. package/dist/components/y-appbar.js +310 -22
  3. package/dist/components/y-badge.d.ts +5 -0
  4. package/dist/components/y-badge.js +5 -0
  5. package/dist/components/y-button.d.ts +6 -1
  6. package/dist/components/y-button.js +5 -0
  7. package/dist/components/y-checkbox.d.ts +7 -1
  8. package/dist/components/y-checkbox.js +6 -0
  9. package/dist/components/y-dialog.d.ts +11 -0
  10. package/dist/components/y-dialog.js +44 -25
  11. package/dist/components/y-drawer.js +1 -2
  12. package/dist/components/y-icon.d.ts +5 -0
  13. package/dist/components/y-icon.js +16 -8
  14. package/dist/components/y-input.d.ts +5 -0
  15. package/dist/components/y-input.js +6 -0
  16. package/dist/components/y-menu.d.ts +1 -0
  17. package/dist/components/y-menu.js +28 -1
  18. package/dist/components/y-panel.d.ts +10 -1
  19. package/dist/components/y-panel.js +21 -0
  20. package/dist/components/y-progress.d.ts +11 -0
  21. package/dist/components/y-progress.js +14 -0
  22. package/dist/components/y-radio.d.ts +11 -2
  23. package/dist/components/y-radio.js +3 -0
  24. package/dist/components/y-select.d.ts +19 -5
  25. package/dist/components/y-select.js +19 -0
  26. package/dist/components/y-slider.d.ts +11 -2
  27. package/dist/components/y-slider.js +10 -0
  28. package/dist/components/y-switch.d.ts +3 -0
  29. package/dist/components/y-switch.js +8 -2
  30. package/dist/components/y-table.d.ts +3 -0
  31. package/dist/components/y-table.js +4 -1
  32. package/dist/components/y-tabs.d.ts +14 -7
  33. package/dist/components/y-tabs.js +9 -0
  34. package/dist/components/y-theme.d.ts +6 -1
  35. package/dist/components/y-theme.js +11 -4
  36. package/dist/components/y-toast.d.ts +4 -0
  37. package/dist/components/y-toast.js +7 -0
  38. package/dist/components/y-tooltip.d.ts +6 -0
  39. package/dist/components/y-tooltip.js +8 -0
  40. package/dist/icons/all.js +42 -0
  41. package/dist/icons/index.d.ts +1 -0
  42. package/dist/index.js +528 -56
  43. package/dist/styles/variables.css +9 -6
  44. package/dist/yumekit.min.js +1 -1
  45. 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
- get name(): string;
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.className = "close-btn";
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.innerHTML = "✕";
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
- // Force a reflow so the browser registers the initial state
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, 16px)",
207
- medium: "var(--component-icon-size-medium, 24px)",
208
- large: "var(--component-icon-size-large, 32px)",
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
- regular: "1.5",
217
- thick: "2",
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;
@@ -1,5 +1,6 @@
1
1
  declare class YumeMenu extends HTMLElement {
2
2
  static get observedAttributes(): string[];
3
+ static _closeAll(except: any): void;
3
4
  _onAnchorClick(e: any): void;
4
5
  _onDocumentClick(e: any): void;
5
6
  _onScrollOrResize(): void;
@@ -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
- hasChildren(): any;
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;