@waggylabs/yumekit 0.5.1 → 0.5.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/CHANGELOG.md +24 -0
- package/README.md +54 -63
- package/dist/ai/llm.txt +14 -11
- package/dist/ai/skill/examples/nav-layout.html +5 -5
- package/dist/ai/skill/examples/themed-app.html +6 -6
- package/dist/ai/skill/patterns.md +7 -7
- package/dist/ai/skill/reference.md +21 -18
- package/dist/components/y-appbar.js +45 -16
- package/dist/components/y-banner.js +44 -15
- package/dist/components/y-button/y-button.d.ts +11 -4
- package/dist/components/y-button.d.ts +11 -4
- package/dist/components/y-button.js +43 -14
- package/dist/components/y-checkbox.js +7 -1
- package/dist/components/y-code.js +9 -2
- package/dist/components/y-color.js +12 -2
- package/dist/components/y-colorpicker.js +12 -2
- package/dist/components/y-data-grid.js +83 -35
- package/dist/components/y-date.js +72 -30
- package/dist/components/y-datepicker.js +72 -30
- package/dist/components/y-dialog.js +1 -1
- package/dist/components/y-help.js +46 -17
- package/dist/components/y-input.js +11 -1
- package/dist/components/y-paginator.js +46 -17
- package/dist/components/y-select.js +1 -1
- package/dist/components/y-sidebar.js +45 -16
- package/dist/components/y-tabs/y-tabs.d.ts +17 -0
- package/dist/components/y-tabs.d.ts +17 -0
- package/dist/components/y-tabs.js +193 -8
- package/dist/components/y-tag/y-tag.d.ts +9 -2
- package/dist/components/y-tag.d.ts +9 -2
- package/dist/components/y-tag.js +36 -8
- package/dist/components/y-textarea.js +11 -1
- package/dist/index.js +341 -63
- package/dist/react.d.ts +5 -0
- package/dist/yumekit.min.js +1 -1
- package/llm.txt +14 -11
- package/package.json +1 -1
- package/scripts/install-ai-docs.js +93 -72
|
@@ -7,6 +7,7 @@ class YumeButton extends HTMLElement {
|
|
|
7
7
|
"right-icon",
|
|
8
8
|
"color",
|
|
9
9
|
"size",
|
|
10
|
+
"variant",
|
|
10
11
|
"style-type",
|
|
11
12
|
"type",
|
|
12
13
|
"padding-mode",
|
|
@@ -59,9 +60,13 @@ class YumeButton extends HTMLElement {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
if (name === "style-type" && newValue !== null) {
|
|
64
|
+
this._warnStyleTypeDeprecated();
|
|
65
|
+
}
|
|
66
|
+
|
|
62
67
|
this._init();
|
|
63
68
|
|
|
64
|
-
if (["color", "size", "style-type", "disabled"].includes(name)) {
|
|
69
|
+
if (["color", "size", "variant", "style-type", "disabled"].includes(name)) {
|
|
65
70
|
this._updateStyles();
|
|
66
71
|
}
|
|
67
72
|
}
|
|
@@ -143,9 +148,12 @@ class YumeButton extends HTMLElement {
|
|
|
143
148
|
this.setAttribute("size", val);
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
/**
|
|
151
|
+
/**
|
|
152
|
+
* Deprecated alias for `variant`. Use `variant` instead; retained for
|
|
153
|
+
* backward compatibility and removed in a future major version.
|
|
154
|
+
*/
|
|
147
155
|
get styleType() {
|
|
148
|
-
return this.
|
|
156
|
+
return this.variant;
|
|
149
157
|
}
|
|
150
158
|
set styleType(val) {
|
|
151
159
|
this.setAttribute("style-type", val);
|
|
@@ -188,6 +196,18 @@ class YumeButton extends HTMLElement {
|
|
|
188
196
|
this.setAttribute("value", newVal);
|
|
189
197
|
}
|
|
190
198
|
|
|
199
|
+
/** Visual style: "filled" | "outlined" | "flat" (default "outlined"). */
|
|
200
|
+
get variant() {
|
|
201
|
+
return (
|
|
202
|
+
this.getAttribute("variant") ||
|
|
203
|
+
this.getAttribute("style-type") ||
|
|
204
|
+
"outlined"
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
set variant(val) {
|
|
208
|
+
this.setAttribute("variant", val);
|
|
209
|
+
}
|
|
210
|
+
|
|
191
211
|
// -------------------------------------------------------------------------
|
|
192
212
|
// Public
|
|
193
213
|
// -------------------------------------------------------------------------
|
|
@@ -242,7 +262,7 @@ class YumeButton extends HTMLElement {
|
|
|
242
262
|
});
|
|
243
263
|
}
|
|
244
264
|
|
|
245
|
-
_applyCustomColorStyles(color,
|
|
265
|
+
_applyCustomColorStyles(color, variant, size) {
|
|
246
266
|
const text = contrastTextColor(color);
|
|
247
267
|
const hover = `color-mix(in srgb, ${color} 85%, black)`;
|
|
248
268
|
const active = `color-mix(in srgb, ${color} 70%, black)`;
|
|
@@ -298,7 +318,7 @@ class YumeButton extends HTMLElement {
|
|
|
298
318
|
},
|
|
299
319
|
};
|
|
300
320
|
|
|
301
|
-
Object.entries(styles[
|
|
321
|
+
Object.entries(styles[variant] || styles.outlined).forEach(
|
|
302
322
|
([key, val]) => this.button.style.setProperty(key, val),
|
|
303
323
|
);
|
|
304
324
|
|
|
@@ -344,11 +364,11 @@ class YumeButton extends HTMLElement {
|
|
|
344
364
|
);
|
|
345
365
|
}
|
|
346
366
|
|
|
347
|
-
_applyInteractionStyles(vars,
|
|
348
|
-
if (
|
|
367
|
+
_applyInteractionStyles(vars, variant) {
|
|
368
|
+
if (variant === "filled") {
|
|
349
369
|
this._applyFilledInteractionStyles(vars);
|
|
350
370
|
} else {
|
|
351
|
-
this._applyUnfilledInteractionStyles(vars,
|
|
371
|
+
this._applyUnfilledInteractionStyles(vars, variant);
|
|
352
372
|
}
|
|
353
373
|
}
|
|
354
374
|
|
|
@@ -473,7 +493,7 @@ class YumeButton extends HTMLElement {
|
|
|
473
493
|
this.shadowRoot.appendChild(style);
|
|
474
494
|
}
|
|
475
495
|
|
|
476
|
-
_applyUnfilledInteractionStyles(vars,
|
|
496
|
+
_applyUnfilledInteractionStyles(vars, variant) {
|
|
477
497
|
const borderColor = this._outlineBorderColor(
|
|
478
498
|
`var(${vars[7]}, var(${vars[0]}, #f7f7fa))`,
|
|
479
499
|
);
|
|
@@ -503,7 +523,7 @@ class YumeButton extends HTMLElement {
|
|
|
503
523
|
`var(${vars[6]}, #0c0c0d)`,
|
|
504
524
|
);
|
|
505
525
|
|
|
506
|
-
if (
|
|
526
|
+
if (variant === "outlined") {
|
|
507
527
|
// Outlined buttons keep their border color across all states
|
|
508
528
|
this.button.style.setProperty("--hover-border-color", borderColor);
|
|
509
529
|
this.button.style.setProperty("--focus-border-color", borderColor);
|
|
@@ -791,11 +811,11 @@ class YumeButton extends HTMLElement {
|
|
|
791
811
|
}
|
|
792
812
|
|
|
793
813
|
_updateStyles() {
|
|
794
|
-
const { color, size,
|
|
814
|
+
const { color, size, variant } = this;
|
|
795
815
|
const colorVars = this._getColorVarsMap();
|
|
796
816
|
|
|
797
817
|
if (!colorVars[color] && isSafeCssColor(color)) {
|
|
798
|
-
this._applyCustomColorStyles(color,
|
|
818
|
+
this._applyCustomColorStyles(color, variant, size);
|
|
799
819
|
return;
|
|
800
820
|
}
|
|
801
821
|
|
|
@@ -824,14 +844,23 @@ class YumeButton extends HTMLElement {
|
|
|
824
844
|
},
|
|
825
845
|
};
|
|
826
846
|
|
|
827
|
-
const currentStyle = styleVars[
|
|
847
|
+
const currentStyle = styleVars[variant] || styleVars.outlined;
|
|
828
848
|
Object.entries(currentStyle).forEach(([key, value]) => {
|
|
829
849
|
this.button.style.setProperty(key, value);
|
|
830
850
|
});
|
|
831
851
|
|
|
832
|
-
this._applyInteractionStyles(vars,
|
|
852
|
+
this._applyInteractionStyles(vars, variant);
|
|
833
853
|
this._applySizeStyles(size);
|
|
834
854
|
}
|
|
855
|
+
|
|
856
|
+
_warnStyleTypeDeprecated() {
|
|
857
|
+
if (YumeButton._styleTypeDeprecationWarned) return;
|
|
858
|
+
|
|
859
|
+
YumeButton._styleTypeDeprecationWarned = true;
|
|
860
|
+
console.warn(
|
|
861
|
+
'y-button: the "style-type" attribute is deprecated and will be removed in a future major version. Use "variant" instead.',
|
|
862
|
+
);
|
|
863
|
+
}
|
|
835
864
|
}
|
|
836
865
|
|
|
837
866
|
if (!customElements.get("y-button")) {
|
|
@@ -2021,7 +2050,7 @@ class YumeSidebar extends HTMLElement {
|
|
|
2021
2050
|
{
|
|
2022
2051
|
class: "collapse-btn",
|
|
2023
2052
|
color: "base",
|
|
2024
|
-
"
|
|
2053
|
+
"variant": "flat",
|
|
2025
2054
|
size: cfg.buttonSize,
|
|
2026
2055
|
"aria-label": isCollapsed
|
|
2027
2056
|
? "Expand sidebar"
|
|
@@ -2069,7 +2098,7 @@ class YumeSidebar extends HTMLElement {
|
|
|
2069
2098
|
const btn = createElement("y-button", {
|
|
2070
2099
|
id: btnId,
|
|
2071
2100
|
color: isActive ? "primary" : "base",
|
|
2072
|
-
"
|
|
2101
|
+
"variant": "flat",
|
|
2073
2102
|
size: cfg.buttonSize,
|
|
2074
2103
|
"aria-current": isActive ? "page" : false,
|
|
2075
2104
|
});
|
|
@@ -2,11 +2,22 @@ export class YumeTabs extends HTMLElement {
|
|
|
2
2
|
static get observedAttributes(): string[];
|
|
3
3
|
_activeTab: string;
|
|
4
4
|
_warnedSlots: Set<any>;
|
|
5
|
+
_resizeObserver: ResizeObserver;
|
|
6
|
+
_onTablistScroll(): void;
|
|
5
7
|
connectedCallback(): void;
|
|
8
|
+
disconnectedCallback(): void;
|
|
6
9
|
attributeChangedCallback(name: any, oldVal: any, newVal: any): void;
|
|
7
10
|
set options(val: Array<any>);
|
|
8
11
|
/** @type {Array<Object>} Tab definitions. Each object: `{ id, label, slot, disabled?, leftIcon?, rightIcon? }`. `leftIcon`/`rightIcon` are `y-icon` names rendered inside the tab button. Use the `tab-content-{id}` slot to supply fully custom tab button content instead. */
|
|
9
12
|
get options(): Array<any>;
|
|
13
|
+
set overflow(val: "scroll" | "wrap");
|
|
14
|
+
/**
|
|
15
|
+
* @type {"scroll"|"wrap"} How a tab strip wider (or taller) than its
|
|
16
|
+
* container behaves. `"scroll"` keeps tabs on a single line and reveals
|
|
17
|
+
* prev/next arrow buttons when the strip overflows; `"wrap"` lets tabs flow
|
|
18
|
+
* onto multiple rows (or columns, for left/right positions).
|
|
19
|
+
*/
|
|
20
|
+
get overflow(): "scroll" | "wrap";
|
|
10
21
|
set position(val: "top" | "bottom" | "left" | "right");
|
|
11
22
|
/** @type {"top"|"bottom"|"left"|"right"} Which edge the tab strip is placed on. */
|
|
12
23
|
get position(): "top" | "bottom" | "left" | "right";
|
|
@@ -27,6 +38,8 @@ export class YumeTabs extends HTMLElement {
|
|
|
27
38
|
activateTab(id: string): void;
|
|
28
39
|
render(): void;
|
|
29
40
|
_appendDeprecatedIconSlot(parent: any, side: any, tabId: any): void;
|
|
41
|
+
_buildScrollButton(direction: any): HTMLElement;
|
|
42
|
+
_buildTabStrip(tablist: any): HTMLElement;
|
|
30
43
|
_createIcon(name: any): HTMLElement;
|
|
31
44
|
_createPanel(slotName: any): HTMLElement;
|
|
32
45
|
_createTabButton(tab: any): HTMLElement;
|
|
@@ -34,5 +47,9 @@ export class YumeTabs extends HTMLElement {
|
|
|
34
47
|
_getStyles(): string;
|
|
35
48
|
_handleTabKeydown(e: any, buttons: any): void;
|
|
36
49
|
_resolveActiveTab(tabs: any): void;
|
|
50
|
+
_scrollTabs(direction: any): void;
|
|
37
51
|
_setupEvents(): void;
|
|
52
|
+
_setupScroll(): void;
|
|
53
|
+
_teardownScroll(): void;
|
|
54
|
+
_updateScrollButtons(): void;
|
|
38
55
|
}
|
|
@@ -2,11 +2,22 @@ export class YumeTabs extends HTMLElement {
|
|
|
2
2
|
static get observedAttributes(): string[];
|
|
3
3
|
_activeTab: string;
|
|
4
4
|
_warnedSlots: Set<any>;
|
|
5
|
+
_resizeObserver: ResizeObserver;
|
|
6
|
+
_onTablistScroll(): void;
|
|
5
7
|
connectedCallback(): void;
|
|
8
|
+
disconnectedCallback(): void;
|
|
6
9
|
attributeChangedCallback(name: any, oldVal: any, newVal: any): void;
|
|
7
10
|
set options(val: Array<any>);
|
|
8
11
|
/** @type {Array<Object>} Tab definitions. Each object: `{ id, label, slot, disabled?, leftIcon?, rightIcon? }`. `leftIcon`/`rightIcon` are `y-icon` names rendered inside the tab button. Use the `tab-content-{id}` slot to supply fully custom tab button content instead. */
|
|
9
12
|
get options(): Array<any>;
|
|
13
|
+
set overflow(val: "scroll" | "wrap");
|
|
14
|
+
/**
|
|
15
|
+
* @type {"scroll"|"wrap"} How a tab strip wider (or taller) than its
|
|
16
|
+
* container behaves. `"scroll"` keeps tabs on a single line and reveals
|
|
17
|
+
* prev/next arrow buttons when the strip overflows; `"wrap"` lets tabs flow
|
|
18
|
+
* onto multiple rows (or columns, for left/right positions).
|
|
19
|
+
*/
|
|
20
|
+
get overflow(): "scroll" | "wrap";
|
|
10
21
|
set position(val: "top" | "bottom" | "left" | "right");
|
|
11
22
|
/** @type {"top"|"bottom"|"left"|"right"} Which edge the tab strip is placed on. */
|
|
12
23
|
get position(): "top" | "bottom" | "left" | "right";
|
|
@@ -27,6 +38,8 @@ export class YumeTabs extends HTMLElement {
|
|
|
27
38
|
activateTab(id: string): void;
|
|
28
39
|
render(): void;
|
|
29
40
|
_appendDeprecatedIconSlot(parent: any, side: any, tabId: any): void;
|
|
41
|
+
_buildScrollButton(direction: any): HTMLElement;
|
|
42
|
+
_buildTabStrip(tablist: any): HTMLElement;
|
|
30
43
|
_createIcon(name: any): HTMLElement;
|
|
31
44
|
_createPanel(slotName: any): HTMLElement;
|
|
32
45
|
_createTabButton(tab: any): HTMLElement;
|
|
@@ -34,5 +47,9 @@ export class YumeTabs extends HTMLElement {
|
|
|
34
47
|
_getStyles(): string;
|
|
35
48
|
_handleTabKeydown(e: any, buttons: any): void;
|
|
36
49
|
_resolveActiveTab(tabs: any): void;
|
|
50
|
+
_scrollTabs(direction: any): void;
|
|
37
51
|
_setupEvents(): void;
|
|
52
|
+
_setupScroll(): void;
|
|
53
|
+
_teardownScroll(): void;
|
|
54
|
+
_updateScrollButtons(): void;
|
|
38
55
|
}
|
|
@@ -362,7 +362,7 @@ if (!customElements.get("y-icon")) {
|
|
|
362
362
|
|
|
363
363
|
class YumeTabs extends HTMLElement {
|
|
364
364
|
static get observedAttributes() {
|
|
365
|
-
return ["options", "size", "position", "variant"];
|
|
365
|
+
return ["options", "size", "position", "variant", "overflow"];
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
// -------------------------------------------------------------------------
|
|
@@ -374,15 +374,23 @@ class YumeTabs extends HTMLElement {
|
|
|
374
374
|
this.attachShadow({ mode: "open" });
|
|
375
375
|
this._activeTab = "";
|
|
376
376
|
this._warnedSlots = new Set();
|
|
377
|
+
this._resizeObserver = null;
|
|
378
|
+
this._onTablistScroll = this._onTablistScroll.bind(this);
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
connectedCallback() {
|
|
380
382
|
if (!this.hasAttribute("size")) this.setAttribute("size", "medium");
|
|
381
383
|
if (!this.hasAttribute("position"))
|
|
382
384
|
this.setAttribute("position", "top");
|
|
385
|
+
if (!this.hasAttribute("overflow"))
|
|
386
|
+
this.setAttribute("overflow", "scroll");
|
|
383
387
|
this.render();
|
|
384
388
|
}
|
|
385
389
|
|
|
390
|
+
disconnectedCallback() {
|
|
391
|
+
this._teardownScroll();
|
|
392
|
+
}
|
|
393
|
+
|
|
386
394
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
387
395
|
if (oldVal === newVal) return;
|
|
388
396
|
if (name === "options") this._warnedSlots.clear();
|
|
@@ -408,6 +416,19 @@ class YumeTabs extends HTMLElement {
|
|
|
408
416
|
this.render();
|
|
409
417
|
}
|
|
410
418
|
|
|
419
|
+
/**
|
|
420
|
+
* @type {"scroll"|"wrap"} How a tab strip wider (or taller) than its
|
|
421
|
+
* container behaves. `"scroll"` keeps tabs on a single line and reveals
|
|
422
|
+
* prev/next arrow buttons when the strip overflows; `"wrap"` lets tabs flow
|
|
423
|
+
* onto multiple rows (or columns, for left/right positions).
|
|
424
|
+
*/
|
|
425
|
+
get overflow() {
|
|
426
|
+
return this.getAttribute("overflow") === "wrap" ? "wrap" : "scroll";
|
|
427
|
+
}
|
|
428
|
+
set overflow(val) {
|
|
429
|
+
this.setAttribute("overflow", val === "wrap" ? "wrap" : "scroll");
|
|
430
|
+
}
|
|
431
|
+
|
|
411
432
|
/** @type {"top"|"bottom"|"left"|"right"} Which edge the tab strip is placed on. */
|
|
412
433
|
get position() {
|
|
413
434
|
const pos = this.getAttribute("position");
|
|
@@ -466,6 +487,7 @@ class YumeTabs extends HTMLElement {
|
|
|
466
487
|
|
|
467
488
|
const activeDef = tabs.find((t) => t.id === this._activeTab);
|
|
468
489
|
|
|
490
|
+
this._teardownScroll();
|
|
469
491
|
this.shadowRoot.innerHTML = "";
|
|
470
492
|
|
|
471
493
|
const style = document.createElement("style");
|
|
@@ -478,11 +500,12 @@ class YumeTabs extends HTMLElement {
|
|
|
478
500
|
part: "tablist",
|
|
479
501
|
});
|
|
480
502
|
tabs.forEach((tab) => tablist.appendChild(this._createTabButton(tab)));
|
|
481
|
-
this.shadowRoot.appendChild(tablist);
|
|
482
503
|
|
|
504
|
+
this.shadowRoot.appendChild(this._buildTabStrip(tablist));
|
|
483
505
|
this.shadowRoot.appendChild(this._createPanel(activeDef?.slot || ""));
|
|
484
506
|
|
|
485
507
|
this._setupEvents();
|
|
508
|
+
this._setupScroll();
|
|
486
509
|
}
|
|
487
510
|
|
|
488
511
|
// -------------------------------------------------------------------------
|
|
@@ -507,6 +530,47 @@ class YumeTabs extends HTMLElement {
|
|
|
507
530
|
parent.appendChild(createElement("slot", { name: slotName, class: "icon-slot" }));
|
|
508
531
|
}
|
|
509
532
|
|
|
533
|
+
_buildScrollButton(direction) {
|
|
534
|
+
const vertical = this.position === "left" || this.position === "right";
|
|
535
|
+
const icon =
|
|
536
|
+
direction === "prev"
|
|
537
|
+
? vertical
|
|
538
|
+
? "chevron-up"
|
|
539
|
+
: "chevron-left"
|
|
540
|
+
: vertical
|
|
541
|
+
? "chevron-down"
|
|
542
|
+
: "chevron-right";
|
|
543
|
+
const btn = createElement(
|
|
544
|
+
"button",
|
|
545
|
+
{
|
|
546
|
+
type: "button",
|
|
547
|
+
class: `scroll-btn scroll-${direction}`,
|
|
548
|
+
part: `scroll-button scroll-${direction}`,
|
|
549
|
+
"aria-label":
|
|
550
|
+
direction === "prev"
|
|
551
|
+
? "Scroll tabs backward"
|
|
552
|
+
: "Scroll tabs forward",
|
|
553
|
+
tabindex: "-1",
|
|
554
|
+
hidden: "",
|
|
555
|
+
},
|
|
556
|
+
[createElement("y-icon", { name: icon, size: this.size, "aria-hidden": "true" })],
|
|
557
|
+
);
|
|
558
|
+
btn.addEventListener("click", () => this._scrollTabs(direction));
|
|
559
|
+
return btn;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
_buildTabStrip(tablist) {
|
|
563
|
+
const strip = createElement("div", { class: "tabstrip", part: "tabstrip" });
|
|
564
|
+
if (this.overflow === "scroll") {
|
|
565
|
+
strip.appendChild(this._buildScrollButton("prev"));
|
|
566
|
+
strip.appendChild(tablist);
|
|
567
|
+
strip.appendChild(this._buildScrollButton("next"));
|
|
568
|
+
} else {
|
|
569
|
+
strip.appendChild(tablist);
|
|
570
|
+
}
|
|
571
|
+
return strip;
|
|
572
|
+
}
|
|
573
|
+
|
|
510
574
|
_createIcon(name) {
|
|
511
575
|
return createElement("y-icon", { name, size: this.size });
|
|
512
576
|
}
|
|
@@ -587,16 +651,63 @@ class YumeTabs extends HTMLElement {
|
|
|
587
651
|
:host([position="left"]) { flex-direction: row; }
|
|
588
652
|
:host([position="right"]) { flex-direction: row-reverse; }
|
|
589
653
|
|
|
654
|
+
.tabstrip {
|
|
655
|
+
display: flex;
|
|
656
|
+
position: relative;
|
|
657
|
+
z-index: 1;
|
|
658
|
+
min-width: 0;
|
|
659
|
+
min-height: 0;
|
|
660
|
+
}
|
|
661
|
+
:host([position="left"]) .tabstrip,
|
|
662
|
+
:host([position="right"]) .tabstrip { flex-direction: column; }
|
|
663
|
+
:host([position="top"]) .tabstrip { margin-bottom: -1px; }
|
|
664
|
+
:host([position="bottom"]) .tabstrip { margin-top: -1px; }
|
|
665
|
+
:host([position="left"]) .tabstrip { margin-right: -1px; }
|
|
666
|
+
:host([position="right"]) .tabstrip { margin-left: -1px; }
|
|
667
|
+
|
|
590
668
|
.tablist {
|
|
591
669
|
display: flex;
|
|
592
670
|
gap: 0;
|
|
593
671
|
position: relative;
|
|
594
|
-
|
|
672
|
+
min-width: 0;
|
|
673
|
+
min-height: 0;
|
|
674
|
+
}
|
|
675
|
+
:host([position="left"]) .tablist,
|
|
676
|
+
:host([position="right"]) .tablist { flex-direction: column; }
|
|
677
|
+
|
|
678
|
+
/* Scroll mode: tabs stay on one line; arrow buttons drive scrolling,
|
|
679
|
+
so the native scrollbar is hidden. */
|
|
680
|
+
:host([overflow="scroll"]) .tablist {
|
|
681
|
+
flex: 1 1 auto;
|
|
682
|
+
overflow: auto;
|
|
683
|
+
scrollbar-width: none;
|
|
684
|
+
-ms-overflow-style: none;
|
|
685
|
+
}
|
|
686
|
+
:host([overflow="scroll"]) .tablist::-webkit-scrollbar { display: none; }
|
|
687
|
+
|
|
688
|
+
/* Wrap mode: tabs flow onto multiple rows (or columns). */
|
|
689
|
+
:host([overflow="wrap"]) .tablist { flex-wrap: wrap; }
|
|
690
|
+
|
|
691
|
+
.scroll-btn {
|
|
692
|
+
flex: 0 0 auto;
|
|
693
|
+
display: inline-flex;
|
|
694
|
+
align-items: center;
|
|
695
|
+
justify-content: center;
|
|
696
|
+
padding: 0 4px;
|
|
697
|
+
background: var(--component-tabs-inactive-background, var(--component-tabs-border-color));
|
|
698
|
+
color: var(--component-tabs-color);
|
|
699
|
+
border: 1px solid var(--component-tabs-border-color);
|
|
700
|
+
border-width: var(--component-tabs-border-width, var(--component-tab-border-width, 1px));
|
|
701
|
+
cursor: pointer;
|
|
702
|
+
font-family: inherit;
|
|
703
|
+
}
|
|
704
|
+
.scroll-btn[hidden] { display: none; }
|
|
705
|
+
.scroll-btn:hover { background: var(--component-tabs-background); }
|
|
706
|
+
.scroll-btn:focus-visible {
|
|
707
|
+
outline: 2px solid var(--component-tabs-accent);
|
|
708
|
+
outline-offset: -1px;
|
|
595
709
|
}
|
|
596
|
-
:host([
|
|
597
|
-
:host([position="bottom"]) .tablist { margin-top: -1px; margin-bottom: 0; }
|
|
598
|
-
:host([position="left"]) .tablist { flex-direction: column; margin-right: -1px; margin-left: 0; }
|
|
599
|
-
:host([position="right"]) .tablist { flex-direction: column; margin-left: -1px; margin-right: 0; }
|
|
710
|
+
:host([variant="accent"]) .scroll-btn { background: transparent; border: none; }
|
|
600
711
|
|
|
601
712
|
:host([position="top"]) .tablist button { border-bottom: none; }
|
|
602
713
|
:host([position="bottom"]) .tablist button { border-top: none; }
|
|
@@ -712,6 +823,10 @@ class YumeTabs extends HTMLElement {
|
|
|
712
823
|
}
|
|
713
824
|
}
|
|
714
825
|
|
|
826
|
+
_onTablistScroll() {
|
|
827
|
+
this._updateScrollButtons();
|
|
828
|
+
}
|
|
829
|
+
|
|
715
830
|
_resolveActiveTab(tabs) {
|
|
716
831
|
const currentInvalid =
|
|
717
832
|
!this._activeTab ||
|
|
@@ -721,8 +836,26 @@ class YumeTabs extends HTMLElement {
|
|
|
721
836
|
}
|
|
722
837
|
}
|
|
723
838
|
|
|
839
|
+
_scrollTabs(direction) {
|
|
840
|
+
const tablist = this.shadowRoot.querySelector(".tablist");
|
|
841
|
+
if (!tablist) return;
|
|
842
|
+
|
|
843
|
+
const vertical = this.position === "left" || this.position === "right";
|
|
844
|
+
const amount =
|
|
845
|
+
(vertical ? tablist.clientHeight : tablist.clientWidth) * 0.75;
|
|
846
|
+
const delta = direction === "prev" ? -amount : amount;
|
|
847
|
+
|
|
848
|
+
tablist.scrollBy(
|
|
849
|
+
vertical
|
|
850
|
+
? { top: delta, behavior: "smooth" }
|
|
851
|
+
: { left: delta, behavior: "smooth" },
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
|
|
724
855
|
_setupEvents() {
|
|
725
|
-
const buttons = Array.from(
|
|
856
|
+
const buttons = Array.from(
|
|
857
|
+
this.shadowRoot.querySelectorAll(".tablist button"),
|
|
858
|
+
);
|
|
726
859
|
buttons.forEach((button) => {
|
|
727
860
|
if (button.disabled) return;
|
|
728
861
|
button.addEventListener("click", () =>
|
|
@@ -733,6 +866,58 @@ class YumeTabs extends HTMLElement {
|
|
|
733
866
|
);
|
|
734
867
|
});
|
|
735
868
|
}
|
|
869
|
+
|
|
870
|
+
_setupScroll() {
|
|
871
|
+
if (this.overflow !== "scroll") return;
|
|
872
|
+
|
|
873
|
+
const tablist = this.shadowRoot.querySelector(".tablist");
|
|
874
|
+
if (!tablist) return;
|
|
875
|
+
|
|
876
|
+
tablist.addEventListener("scroll", this._onTablistScroll, {
|
|
877
|
+
passive: true,
|
|
878
|
+
});
|
|
879
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
880
|
+
this._resizeObserver = new ResizeObserver(() =>
|
|
881
|
+
this._updateScrollButtons(),
|
|
882
|
+
);
|
|
883
|
+
this._resizeObserver.observe(tablist);
|
|
884
|
+
this._resizeObserver.observe(this);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
this._updateScrollButtons();
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
_teardownScroll() {
|
|
891
|
+
this._resizeObserver?.disconnect();
|
|
892
|
+
this._resizeObserver = null;
|
|
893
|
+
const tablist = this.shadowRoot?.querySelector(".tablist");
|
|
894
|
+
tablist?.removeEventListener("scroll", this._onTablistScroll);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
_updateScrollButtons() {
|
|
898
|
+
const tablist = this.shadowRoot.querySelector(".tablist");
|
|
899
|
+
const prev = this.shadowRoot.querySelector(".scroll-prev");
|
|
900
|
+
const next = this.shadowRoot.querySelector(".scroll-next");
|
|
901
|
+
if (!tablist || !prev || !next) return;
|
|
902
|
+
|
|
903
|
+
const vertical = this.position === "left" || this.position === "right";
|
|
904
|
+
const scrollSize = vertical
|
|
905
|
+
? tablist.scrollHeight
|
|
906
|
+
: tablist.scrollWidth;
|
|
907
|
+
const clientSize = vertical
|
|
908
|
+
? tablist.clientHeight
|
|
909
|
+
: tablist.clientWidth;
|
|
910
|
+
const scrollPos = vertical ? tablist.scrollTop : tablist.scrollLeft;
|
|
911
|
+
|
|
912
|
+
if (scrollSize - clientSize <= 1) {
|
|
913
|
+
prev.hidden = true;
|
|
914
|
+
next.hidden = true;
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
prev.hidden = scrollPos <= 1;
|
|
919
|
+
next.hidden = scrollPos >= scrollSize - clientSize - 1;
|
|
920
|
+
}
|
|
736
921
|
}
|
|
737
922
|
|
|
738
923
|
if (!customElements.get("y-tabs")) {
|
|
@@ -15,10 +15,17 @@ export class YumeTag extends HTMLElement {
|
|
|
15
15
|
/** Size: "small" | "medium" | "large" (default "medium"). */
|
|
16
16
|
get size(): string;
|
|
17
17
|
set styleType(val: string);
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Deprecated alias for `variant`. Use `variant` instead; retained for
|
|
20
|
+
* backward compatibility and removed in a future major version.
|
|
21
|
+
*/
|
|
19
22
|
get styleType(): string;
|
|
23
|
+
set variant(val: string);
|
|
24
|
+
/** Visual style: "filled" (default) | "outlined" | "flat". */
|
|
25
|
+
get variant(): string;
|
|
20
26
|
render(): void;
|
|
21
27
|
_bindRemoveListener(): void;
|
|
22
|
-
_getCustomColorVariant(color: any,
|
|
28
|
+
_getCustomColorVariant(color: any, variant: any): any;
|
|
23
29
|
_getStyle(): string;
|
|
30
|
+
_warnStyleTypeDeprecated(): void;
|
|
24
31
|
}
|
|
@@ -15,10 +15,17 @@ export class YumeTag extends HTMLElement {
|
|
|
15
15
|
/** Size: "small" | "medium" | "large" (default "medium"). */
|
|
16
16
|
get size(): string;
|
|
17
17
|
set styleType(val: string);
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Deprecated alias for `variant`. Use `variant` instead; retained for
|
|
20
|
+
* backward compatibility and removed in a future major version.
|
|
21
|
+
*/
|
|
19
22
|
get styleType(): string;
|
|
23
|
+
set variant(val: string);
|
|
24
|
+
/** Visual style: "filled" (default) | "outlined" | "flat". */
|
|
25
|
+
get variant(): string;
|
|
20
26
|
render(): void;
|
|
21
27
|
_bindRemoveListener(): void;
|
|
22
|
-
_getCustomColorVariant(color: any,
|
|
28
|
+
_getCustomColorVariant(color: any, variant: any): any;
|
|
23
29
|
_getStyle(): string;
|
|
30
|
+
_warnStyleTypeDeprecated(): void;
|
|
24
31
|
}
|
package/dist/components/y-tag.js
CHANGED
|
@@ -4,7 +4,7 @@ var xSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill
|
|
|
4
4
|
|
|
5
5
|
class YumeTag extends HTMLElement {
|
|
6
6
|
static get observedAttributes() {
|
|
7
|
-
return ["removable", "color", "style-type", "shape", "size"];
|
|
7
|
+
return ["removable", "color", "variant", "style-type", "shape", "size"];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
// -------------------------------------------------------------------------
|
|
@@ -22,6 +22,10 @@ class YumeTag extends HTMLElement {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
25
|
+
if (name === "style-type" && newValue !== null) {
|
|
26
|
+
this._warnStyleTypeDeprecated();
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
if (oldValue !== newValue) this.render();
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -62,14 +66,29 @@ class YumeTag extends HTMLElement {
|
|
|
62
66
|
this.setAttribute("size", val);
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Deprecated alias for `variant`. Use `variant` instead; retained for
|
|
71
|
+
* backward compatibility and removed in a future major version.
|
|
72
|
+
*/
|
|
66
73
|
get styleType() {
|
|
67
|
-
return this.
|
|
74
|
+
return this.variant;
|
|
68
75
|
}
|
|
69
76
|
set styleType(val) {
|
|
70
77
|
this.setAttribute("style-type", val);
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
/** Visual style: "filled" (default) | "outlined" | "flat". */
|
|
81
|
+
get variant() {
|
|
82
|
+
return (
|
|
83
|
+
this.getAttribute("variant") ||
|
|
84
|
+
this.getAttribute("style-type") ||
|
|
85
|
+
"filled"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
set variant(val) {
|
|
89
|
+
this.setAttribute("variant", val);
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
// -------------------------------------------------------------------------
|
|
74
93
|
// Public
|
|
75
94
|
// -------------------------------------------------------------------------
|
|
@@ -104,7 +123,7 @@ class YumeTag extends HTMLElement {
|
|
|
104
123
|
});
|
|
105
124
|
}
|
|
106
125
|
|
|
107
|
-
_getCustomColorVariant(color,
|
|
126
|
+
_getCustomColorVariant(color, variant) {
|
|
108
127
|
const textColor = contrastTextColor(color);
|
|
109
128
|
const variants = {
|
|
110
129
|
filled: `
|
|
@@ -120,11 +139,11 @@ class YumeTag extends HTMLElement {
|
|
|
120
139
|
.remove { color: ${color}; }
|
|
121
140
|
`,
|
|
122
141
|
};
|
|
123
|
-
return variants[
|
|
142
|
+
return variants[variant] || variants.filled;
|
|
124
143
|
}
|
|
125
144
|
|
|
126
145
|
_getStyle() {
|
|
127
|
-
const { color,
|
|
146
|
+
const { color, variant, shape, size } = this;
|
|
128
147
|
|
|
129
148
|
const vars = {
|
|
130
149
|
primary: [
|
|
@@ -226,7 +245,7 @@ class YumeTag extends HTMLElement {
|
|
|
226
245
|
`;
|
|
227
246
|
|
|
228
247
|
if (isCustomColor)
|
|
229
|
-
return baseStyle + this._getCustomColorVariant(color,
|
|
248
|
+
return baseStyle + this._getCustomColorVariant(color, variant);
|
|
230
249
|
|
|
231
250
|
const [content, inverse, flatBackground] = varEntry || vars.base;
|
|
232
251
|
|
|
@@ -245,7 +264,16 @@ class YumeTag extends HTMLElement {
|
|
|
245
264
|
`,
|
|
246
265
|
};
|
|
247
266
|
|
|
248
|
-
return baseStyle + (styleVariants[
|
|
267
|
+
return baseStyle + (styleVariants[variant] || styleVariants.filled);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
_warnStyleTypeDeprecated() {
|
|
271
|
+
if (YumeTag._styleTypeDeprecationWarned) return;
|
|
272
|
+
|
|
273
|
+
YumeTag._styleTypeDeprecationWarned = true;
|
|
274
|
+
console.warn(
|
|
275
|
+
'y-tag: the "style-type" attribute is deprecated and will be removed in a future major version. Use "variant" instead.',
|
|
276
|
+
);
|
|
249
277
|
}
|
|
250
278
|
}
|
|
251
279
|
|