@waggylabs/yumekit 0.5.1 → 0.5.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/index.js CHANGED
@@ -8864,7 +8864,8 @@ class YumeCode extends HTMLElement {
8864
8864
  _buildStyles() {
8865
8865
  return `
8866
8866
  :host {
8867
- display: block;
8867
+ display: flex;
8868
+ flex-direction: column;
8868
8869
  font-family: var(--component-code-font-family, var(--font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace));
8869
8870
  color: var(--component-code-text-color, var(--base-content--, #1a1a1a));
8870
8871
  background: var(--component-code-bg-color, var(--base-background-component, #f6f8fa));
@@ -8914,13 +8915,19 @@ class YumeCode extends HTMLElement {
8914
8915
  .pre-wrap {
8915
8916
  position: relative;
8916
8917
  overflow: hidden;
8918
+ display: flex;
8919
+ flex-direction: column;
8920
+ flex: 1 1 auto;
8921
+ min-height: 0;
8917
8922
  }
8918
8923
 
8919
8924
  pre.code {
8920
8925
  margin: 0;
8921
8926
  padding: var(--spacing-small, 8px) 0;
8927
+ flex: 1 1 auto;
8928
+ min-height: 0;
8922
8929
  overflow-x: ${this.wrap ? "hidden" : "auto"};
8923
- overflow-y: ${this.maxLines ? "auto" : "visible"};
8930
+ overflow-y: auto;
8924
8931
  font-size: var(--component-code-font-size, 0.9em);
8925
8932
  line-height: var(--component-code-line-height, 1.55);
8926
8933
  tab-size: 4;
@@ -34625,7 +34632,7 @@ if (!customElements.get("y-tag")) {
34625
34632
 
34626
34633
  class YumeTabs extends HTMLElement {
34627
34634
  static get observedAttributes() {
34628
- return ["options", "size", "position", "variant"];
34635
+ return ["options", "size", "position", "variant", "overflow"];
34629
34636
  }
34630
34637
 
34631
34638
  // -------------------------------------------------------------------------
@@ -34637,15 +34644,23 @@ class YumeTabs extends HTMLElement {
34637
34644
  this.attachShadow({ mode: "open" });
34638
34645
  this._activeTab = "";
34639
34646
  this._warnedSlots = new Set();
34647
+ this._resizeObserver = null;
34648
+ this._onTablistScroll = this._onTablistScroll.bind(this);
34640
34649
  }
34641
34650
 
34642
34651
  connectedCallback() {
34643
34652
  if (!this.hasAttribute("size")) this.setAttribute("size", "medium");
34644
34653
  if (!this.hasAttribute("position"))
34645
34654
  this.setAttribute("position", "top");
34655
+ if (!this.hasAttribute("overflow"))
34656
+ this.setAttribute("overflow", "scroll");
34646
34657
  this.render();
34647
34658
  }
34648
34659
 
34660
+ disconnectedCallback() {
34661
+ this._teardownScroll();
34662
+ }
34663
+
34649
34664
  attributeChangedCallback(name, oldVal, newVal) {
34650
34665
  if (oldVal === newVal) return;
34651
34666
  if (name === "options") this._warnedSlots.clear();
@@ -34671,6 +34686,19 @@ class YumeTabs extends HTMLElement {
34671
34686
  this.render();
34672
34687
  }
34673
34688
 
34689
+ /**
34690
+ * @type {"scroll"|"wrap"} How a tab strip wider (or taller) than its
34691
+ * container behaves. `"scroll"` keeps tabs on a single line and reveals
34692
+ * prev/next arrow buttons when the strip overflows; `"wrap"` lets tabs flow
34693
+ * onto multiple rows (or columns, for left/right positions).
34694
+ */
34695
+ get overflow() {
34696
+ return this.getAttribute("overflow") === "wrap" ? "wrap" : "scroll";
34697
+ }
34698
+ set overflow(val) {
34699
+ this.setAttribute("overflow", val === "wrap" ? "wrap" : "scroll");
34700
+ }
34701
+
34674
34702
  /** @type {"top"|"bottom"|"left"|"right"} Which edge the tab strip is placed on. */
34675
34703
  get position() {
34676
34704
  const pos = this.getAttribute("position");
@@ -34729,6 +34757,7 @@ class YumeTabs extends HTMLElement {
34729
34757
 
34730
34758
  const activeDef = tabs.find((t) => t.id === this._activeTab);
34731
34759
 
34760
+ this._teardownScroll();
34732
34761
  this.shadowRoot.innerHTML = "";
34733
34762
 
34734
34763
  const style = document.createElement("style");
@@ -34741,11 +34770,12 @@ class YumeTabs extends HTMLElement {
34741
34770
  part: "tablist",
34742
34771
  });
34743
34772
  tabs.forEach((tab) => tablist.appendChild(this._createTabButton(tab)));
34744
- this.shadowRoot.appendChild(tablist);
34745
34773
 
34774
+ this.shadowRoot.appendChild(this._buildTabStrip(tablist));
34746
34775
  this.shadowRoot.appendChild(this._createPanel(activeDef?.slot || ""));
34747
34776
 
34748
34777
  this._setupEvents();
34778
+ this._setupScroll();
34749
34779
  }
34750
34780
 
34751
34781
  // -------------------------------------------------------------------------
@@ -34770,6 +34800,47 @@ class YumeTabs extends HTMLElement {
34770
34800
  parent.appendChild(createElement("slot", { name: slotName, class: "icon-slot" }));
34771
34801
  }
34772
34802
 
34803
+ _buildScrollButton(direction) {
34804
+ const vertical = this.position === "left" || this.position === "right";
34805
+ const icon =
34806
+ direction === "prev"
34807
+ ? vertical
34808
+ ? "chevron-up"
34809
+ : "chevron-left"
34810
+ : vertical
34811
+ ? "chevron-down"
34812
+ : "chevron-right";
34813
+ const btn = createElement(
34814
+ "button",
34815
+ {
34816
+ type: "button",
34817
+ class: `scroll-btn scroll-${direction}`,
34818
+ part: `scroll-button scroll-${direction}`,
34819
+ "aria-label":
34820
+ direction === "prev"
34821
+ ? "Scroll tabs backward"
34822
+ : "Scroll tabs forward",
34823
+ tabindex: "-1",
34824
+ hidden: "",
34825
+ },
34826
+ [createElement("y-icon", { name: icon, size: this.size, "aria-hidden": "true" })],
34827
+ );
34828
+ btn.addEventListener("click", () => this._scrollTabs(direction));
34829
+ return btn;
34830
+ }
34831
+
34832
+ _buildTabStrip(tablist) {
34833
+ const strip = createElement("div", { class: "tabstrip", part: "tabstrip" });
34834
+ if (this.overflow === "scroll") {
34835
+ strip.appendChild(this._buildScrollButton("prev"));
34836
+ strip.appendChild(tablist);
34837
+ strip.appendChild(this._buildScrollButton("next"));
34838
+ } else {
34839
+ strip.appendChild(tablist);
34840
+ }
34841
+ return strip;
34842
+ }
34843
+
34773
34844
  _createIcon(name) {
34774
34845
  return createElement("y-icon", { name, size: this.size });
34775
34846
  }
@@ -34850,16 +34921,63 @@ class YumeTabs extends HTMLElement {
34850
34921
  :host([position="left"]) { flex-direction: row; }
34851
34922
  :host([position="right"]) { flex-direction: row-reverse; }
34852
34923
 
34924
+ .tabstrip {
34925
+ display: flex;
34926
+ position: relative;
34927
+ z-index: 1;
34928
+ min-width: 0;
34929
+ min-height: 0;
34930
+ }
34931
+ :host([position="left"]) .tabstrip,
34932
+ :host([position="right"]) .tabstrip { flex-direction: column; }
34933
+ :host([position="top"]) .tabstrip { margin-bottom: -1px; }
34934
+ :host([position="bottom"]) .tabstrip { margin-top: -1px; }
34935
+ :host([position="left"]) .tabstrip { margin-right: -1px; }
34936
+ :host([position="right"]) .tabstrip { margin-left: -1px; }
34937
+
34853
34938
  .tablist {
34854
34939
  display: flex;
34855
34940
  gap: 0;
34856
34941
  position: relative;
34857
- z-index: 1;
34942
+ min-width: 0;
34943
+ min-height: 0;
34858
34944
  }
34859
- :host([position="top"]) .tablist { margin-bottom: -1px; margin-top: 0; }
34860
- :host([position="bottom"]) .tablist { margin-top: -1px; margin-bottom: 0; }
34861
- :host([position="left"]) .tablist { flex-direction: column; margin-right: -1px; margin-left: 0; }
34862
- :host([position="right"]) .tablist { flex-direction: column; margin-left: -1px; margin-right: 0; }
34945
+ :host([position="left"]) .tablist,
34946
+ :host([position="right"]) .tablist { flex-direction: column; }
34947
+
34948
+ /* Scroll mode: tabs stay on one line; arrow buttons drive scrolling,
34949
+ so the native scrollbar is hidden. */
34950
+ :host([overflow="scroll"]) .tablist {
34951
+ flex: 1 1 auto;
34952
+ overflow: auto;
34953
+ scrollbar-width: none;
34954
+ -ms-overflow-style: none;
34955
+ }
34956
+ :host([overflow="scroll"]) .tablist::-webkit-scrollbar { display: none; }
34957
+
34958
+ /* Wrap mode: tabs flow onto multiple rows (or columns). */
34959
+ :host([overflow="wrap"]) .tablist { flex-wrap: wrap; }
34960
+
34961
+ .scroll-btn {
34962
+ flex: 0 0 auto;
34963
+ display: inline-flex;
34964
+ align-items: center;
34965
+ justify-content: center;
34966
+ padding: 0 4px;
34967
+ background: var(--component-tabs-inactive-background, var(--component-tabs-border-color));
34968
+ color: var(--component-tabs-color);
34969
+ border: 1px solid var(--component-tabs-border-color);
34970
+ border-width: var(--component-tabs-border-width, var(--component-tab-border-width, 1px));
34971
+ cursor: pointer;
34972
+ font-family: inherit;
34973
+ }
34974
+ .scroll-btn[hidden] { display: none; }
34975
+ .scroll-btn:hover { background: var(--component-tabs-background); }
34976
+ .scroll-btn:focus-visible {
34977
+ outline: 2px solid var(--component-tabs-accent);
34978
+ outline-offset: -1px;
34979
+ }
34980
+ :host([variant="accent"]) .scroll-btn { background: transparent; border: none; }
34863
34981
 
34864
34982
  :host([position="top"]) .tablist button { border-bottom: none; }
34865
34983
  :host([position="bottom"]) .tablist button { border-top: none; }
@@ -34975,6 +35093,10 @@ class YumeTabs extends HTMLElement {
34975
35093
  }
34976
35094
  }
34977
35095
 
35096
+ _onTablistScroll() {
35097
+ this._updateScrollButtons();
35098
+ }
35099
+
34978
35100
  _resolveActiveTab(tabs) {
34979
35101
  const currentInvalid =
34980
35102
  !this._activeTab ||
@@ -34984,8 +35106,26 @@ class YumeTabs extends HTMLElement {
34984
35106
  }
34985
35107
  }
34986
35108
 
35109
+ _scrollTabs(direction) {
35110
+ const tablist = this.shadowRoot.querySelector(".tablist");
35111
+ if (!tablist) return;
35112
+
35113
+ const vertical = this.position === "left" || this.position === "right";
35114
+ const amount =
35115
+ (vertical ? tablist.clientHeight : tablist.clientWidth) * 0.75;
35116
+ const delta = direction === "prev" ? -amount : amount;
35117
+
35118
+ tablist.scrollBy(
35119
+ vertical
35120
+ ? { top: delta, behavior: "smooth" }
35121
+ : { left: delta, behavior: "smooth" },
35122
+ );
35123
+ }
35124
+
34987
35125
  _setupEvents() {
34988
- const buttons = Array.from(this.shadowRoot.querySelectorAll("button"));
35126
+ const buttons = Array.from(
35127
+ this.shadowRoot.querySelectorAll(".tablist button"),
35128
+ );
34989
35129
  buttons.forEach((button) => {
34990
35130
  if (button.disabled) return;
34991
35131
  button.addEventListener("click", () =>
@@ -34996,6 +35136,58 @@ class YumeTabs extends HTMLElement {
34996
35136
  );
34997
35137
  });
34998
35138
  }
35139
+
35140
+ _setupScroll() {
35141
+ if (this.overflow !== "scroll") return;
35142
+
35143
+ const tablist = this.shadowRoot.querySelector(".tablist");
35144
+ if (!tablist) return;
35145
+
35146
+ tablist.addEventListener("scroll", this._onTablistScroll, {
35147
+ passive: true,
35148
+ });
35149
+ if (typeof ResizeObserver !== "undefined") {
35150
+ this._resizeObserver = new ResizeObserver(() =>
35151
+ this._updateScrollButtons(),
35152
+ );
35153
+ this._resizeObserver.observe(tablist);
35154
+ this._resizeObserver.observe(this);
35155
+ }
35156
+
35157
+ this._updateScrollButtons();
35158
+ }
35159
+
35160
+ _teardownScroll() {
35161
+ this._resizeObserver?.disconnect();
35162
+ this._resizeObserver = null;
35163
+ const tablist = this.shadowRoot?.querySelector(".tablist");
35164
+ tablist?.removeEventListener("scroll", this._onTablistScroll);
35165
+ }
35166
+
35167
+ _updateScrollButtons() {
35168
+ const tablist = this.shadowRoot.querySelector(".tablist");
35169
+ const prev = this.shadowRoot.querySelector(".scroll-prev");
35170
+ const next = this.shadowRoot.querySelector(".scroll-next");
35171
+ if (!tablist || !prev || !next) return;
35172
+
35173
+ const vertical = this.position === "left" || this.position === "right";
35174
+ const scrollSize = vertical
35175
+ ? tablist.scrollHeight
35176
+ : tablist.scrollWidth;
35177
+ const clientSize = vertical
35178
+ ? tablist.clientHeight
35179
+ : tablist.clientWidth;
35180
+ const scrollPos = vertical ? tablist.scrollTop : tablist.scrollLeft;
35181
+
35182
+ if (scrollSize - clientSize <= 1) {
35183
+ prev.hidden = true;
35184
+ next.hidden = true;
35185
+ return;
35186
+ }
35187
+
35188
+ prev.hidden = scrollPos <= 1;
35189
+ next.hidden = scrollPos >= scrollSize - clientSize - 1;
35190
+ }
34999
35191
  }
35000
35192
 
35001
35193
  if (!customElements.get("y-tabs")) {
package/dist/react.d.ts CHANGED
@@ -718,6 +718,7 @@ declare module "react" {
718
718
  size?: "small" | "medium" | "large";
719
719
  position?: "top" | "bottom" | "left" | "right";
720
720
  variant?: "default" | "accent";
721
+ overflow?: "scroll" | "wrap";
721
722
  }>;
722
723
  "y-tag": El<{
723
724
  color?: string;