@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +54 -63
  3. package/dist/ai/llm.txt +14 -11
  4. package/dist/ai/skill/examples/nav-layout.html +5 -5
  5. package/dist/ai/skill/examples/themed-app.html +6 -6
  6. package/dist/ai/skill/patterns.md +7 -7
  7. package/dist/ai/skill/reference.md +21 -18
  8. package/dist/components/y-appbar.js +45 -16
  9. package/dist/components/y-banner.js +44 -15
  10. package/dist/components/y-button/y-button.d.ts +11 -4
  11. package/dist/components/y-button.d.ts +11 -4
  12. package/dist/components/y-button.js +43 -14
  13. package/dist/components/y-checkbox.js +7 -1
  14. package/dist/components/y-code.js +9 -2
  15. package/dist/components/y-color.js +12 -2
  16. package/dist/components/y-colorpicker.js +12 -2
  17. package/dist/components/y-data-grid.js +83 -35
  18. package/dist/components/y-date.js +72 -30
  19. package/dist/components/y-datepicker.js +72 -30
  20. package/dist/components/y-dialog.js +1 -1
  21. package/dist/components/y-help.js +46 -17
  22. package/dist/components/y-input.js +11 -1
  23. package/dist/components/y-paginator.js +46 -17
  24. package/dist/components/y-select.js +1 -1
  25. package/dist/components/y-sidebar.js +45 -16
  26. package/dist/components/y-tabs/y-tabs.d.ts +17 -0
  27. package/dist/components/y-tabs.d.ts +17 -0
  28. package/dist/components/y-tabs.js +193 -8
  29. package/dist/components/y-tag/y-tag.d.ts +9 -2
  30. package/dist/components/y-tag.d.ts +9 -2
  31. package/dist/components/y-tag.js +36 -8
  32. package/dist/components/y-textarea.js +11 -1
  33. package/dist/index.js +341 -63
  34. package/dist/react.d.ts +5 -0
  35. package/dist/yumekit.min.js +1 -1
  36. package/llm.txt +14 -11
  37. package/package.json +1 -1
  38. 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
- /** Visual style: "filled" | "outlined" | "flat" (default "outlined"). */
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.getAttribute("style-type") || "outlined";
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, styleType, size) {
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[styleType] || styles.outlined).forEach(
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, styleType) {
348
- if (styleType === "filled") {
367
+ _applyInteractionStyles(vars, variant) {
368
+ if (variant === "filled") {
349
369
  this._applyFilledInteractionStyles(vars);
350
370
  } else {
351
- this._applyUnfilledInteractionStyles(vars, styleType);
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, styleType) {
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 (styleType === "outlined") {
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, styleType } = this;
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, styleType, size);
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[styleType] || styleVars.outlined;
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, styleType);
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
- "style-type": "flat",
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
- "style-type": "flat",
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
- z-index: 1;
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([position="top"]) .tablist { margin-bottom: -1px; margin-top: 0; }
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(this.shadowRoot.querySelectorAll("button"));
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
- /** Visual style: "filled" | "outlined" | "flat" (default "filled"). */
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, styleType: any): 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
- /** Visual style: "filled" | "outlined" | "flat" (default "filled"). */
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, styleType: any): any;
28
+ _getCustomColorVariant(color: any, variant: any): any;
23
29
  _getStyle(): string;
30
+ _warnStyleTypeDeprecated(): void;
24
31
  }
@@ -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
- /** Visual style: "filled" | "outlined" | "flat" (default "filled"). */
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.getAttribute("style-type") || "filled";
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, styleType) {
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[styleType] || variants.filled;
142
+ return variants[variant] || variants.filled;
124
143
  }
125
144
 
126
145
  _getStyle() {
127
- const { color, styleType, shape, size } = this;
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, styleType);
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[styleType] || styleVariants.filled);
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