react-ui-suite 1.1.4 → 1.1.6

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.
@@ -1,12 +1,30 @@
1
- .rui-tab-group {
2
- display: flex;
3
- width: 100%;
4
- height: 100%;
5
- --rui-tab-border: 1px;
6
- --rui-tab-panel-radius: 15px;
7
- --rui-tab-radius: 10px;
8
- --rui-tab-min-main: 32px;
9
- }
1
+ .rui-tab-group {
2
+ display: flex;
3
+ width: 100%;
4
+ height: 100%;
5
+ position: relative;
6
+ --rui-tab-border: 1px;
7
+ --rui-tab-panel-radius: 15px;
8
+ --rui-tab-radius: 10px;
9
+ --rui-tab-min-main: 32px;
10
+ }
11
+
12
+ .rui-tab-group__measure {
13
+ position: fixed;
14
+ left: 0;
15
+ top: 0;
16
+ visibility: hidden;
17
+ pointer-events: none;
18
+ z-index: -1;
19
+ display: inline-flex;
20
+ gap: 0;
21
+ }
22
+
23
+ .rui-tab-group__measure .rui-tab-group__tab {
24
+ flex: 0 0 auto !important;
25
+ width: auto !important;
26
+ height: auto !important;
27
+ }
10
28
 
11
29
  .rui-tab-group[data-position="top"],
12
30
  .rui-tab-group[data-position="bottom"] {
@@ -70,20 +88,21 @@
70
88
  justify-content: flex-end;
71
89
  }
72
90
 
73
- .rui-tab-group__tab {
74
- border: var(--rui-tab-border) solid var(--rui-color-border);
75
- background-color: var(--rui-color-surface-muted);
76
- position: relative;
91
+ .rui-tab-group__tab {
92
+ border: var(--rui-tab-border) solid var(--rui-color-border);
93
+ background-color: var(--rui-color-surface-muted);
94
+ position: relative;
77
95
  padding: 5px;
78
96
  font-weight: 500;
79
97
  display: inline-flex;
80
98
  align-items: center;
81
99
  justify-content: center;
82
100
  transform: none;
83
- min-width: 0;
84
- min-height: 0;
85
- flex: 0 0 auto;
86
- }
101
+ min-width: 0;
102
+ min-height: 0;
103
+ flex: 0 0 auto;
104
+ overflow: hidden;
105
+ }
87
106
 
88
107
  .rui-tab-group__scroll {
89
108
  border: var(--rui-tab-border) solid var(--rui-color-border);
@@ -108,12 +127,19 @@
108
127
  line-height: 1;
109
128
  }
110
129
 
111
- .rui-tab-group__label {
112
- display: inline-flex;
113
- align-items: center;
114
- justify-content: center;
115
- line-height: 1;
116
- }
130
+ .rui-tab-group__label {
131
+ display: inline-flex;
132
+ align-items: center;
133
+ justify-content: center;
134
+ line-height: 1;
135
+ white-space: normal;
136
+ overflow: hidden;
137
+ overflow-wrap: normal;
138
+ word-break: normal;
139
+ hyphens: none;
140
+ max-width: 100%;
141
+ max-height: 100%;
142
+ }
117
143
 
118
144
  .rui-tab-group__tab.is-active {
119
145
  background-color: var(--rui-color-surface);
@@ -205,10 +231,10 @@
205
231
  border-bottom-right-radius: var(--rui-tab-radius);
206
232
  }
207
233
 
208
- .rui-tab-group[data-rotation="vertical"] .rui-tab-group__label {
209
- writing-mode: vertical-rl;
210
- text-orientation: mixed;
211
- }
234
+ .rui-tab-group[data-rotation="vertical"] .rui-tab-group__label {
235
+ writing-mode: vertical-rl;
236
+ text-orientation: mixed;
237
+ }
212
238
 
213
239
  .rui-tab-group[data-position="top"][data-rotation="vertical"] .rui-tab-group__label {
214
240
  transform: rotate(180deg);
package/dist/index.js CHANGED
@@ -1016,7 +1016,16 @@ var Dropdown = React6.forwardRef(
1016
1016
  ref: chevronRef,
1017
1017
  type: "button",
1018
1018
  "aria-label": isOpen ? "Close" : "Open",
1019
- onClick: onChevronClick,
1019
+ onPointerDown: (event) => {
1020
+ if (!onChevronClick) return;
1021
+ if (event.button !== 0) return;
1022
+ event.preventDefault();
1023
+ onChevronClick();
1024
+ },
1025
+ onClick: (event) => {
1026
+ if (!onChevronClick || event.detail !== 0) return;
1027
+ onChevronClick();
1028
+ },
1020
1029
  className: buttonClasses,
1021
1030
  disabled: !!disabled,
1022
1031
  children: /* @__PURE__ */ jsx8(
@@ -1635,10 +1644,7 @@ function InnerCombobox({
1635
1644
  openList();
1636
1645
  return;
1637
1646
  }
1638
- requestAnimationFrame(() => {
1639
- var _a2;
1640
- return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
1641
- });
1647
+ setOpen(false);
1642
1648
  },
1643
1649
  children: isEffectivelyOpen && /* @__PURE__ */ jsx11(
1644
1650
  Popover,
@@ -1860,6 +1866,7 @@ function Select({
1860
1866
  const containerRef = React11.useRef(null);
1861
1867
  const inputRef = React11.useRef(null);
1862
1868
  const chevronRef = React11.useRef(null);
1869
+ const popoverRef = React11.useRef(null);
1863
1870
  const popoverListRef = React11.useRef(null);
1864
1871
  const suppressToggleRef = React11.useRef(false);
1865
1872
  const id = React11.useId();
@@ -1879,10 +1886,14 @@ function Select({
1879
1886
  );
1880
1887
  const activeIndex = activeIndexState;
1881
1888
  const [selected, setSelected] = useControlledState(value, defaultValue != null ? defaultValue : null);
1882
- useOutsideClick(
1883
- [containerRef],
1884
- () => setOpen(false)
1889
+ const outsideClickRefs = React11.useMemo(
1890
+ () => [
1891
+ containerRef,
1892
+ popoverRef
1893
+ ],
1894
+ []
1885
1895
  );
1896
+ useOutsideClick(outsideClickRefs, () => setOpen(false));
1886
1897
  const selectedOption = (_a = options.find((opt) => opt.value === selected)) != null ? _a : null;
1887
1898
  const selectedIndex = React11.useMemo(
1888
1899
  () => options.findIndex((opt) => opt.value === selected),
@@ -2049,7 +2060,7 @@ function Select({
2049
2060
  }
2050
2061
  setOpen((o) => !o);
2051
2062
  },
2052
- children: open && /* @__PURE__ */ jsx13(Popover, { anchorRef: containerRef, className: listboxHighlight, children: ({ scrollRef }) => {
2063
+ children: open && /* @__PURE__ */ jsx13(Popover, { anchorRef: containerRef, rootRef: popoverRef, className: listboxHighlight, children: ({ scrollRef }) => {
2053
2064
  popoverListRef.current = scrollRef;
2054
2065
  return /* @__PURE__ */ jsx13(
2055
2066
  "ul",
@@ -3860,7 +3871,7 @@ function StackedList({ items, dense, className, ...rest }) {
3860
3871
 
3861
3872
  // components/TabGroup/TabGroup.tsx
3862
3873
  import React21 from "react";
3863
- import "./TabGroup-CV2AC3EO.css";
3874
+ import "./TabGroup-3NH74LET.css";
3864
3875
  import { Fragment as Fragment2, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
3865
3876
  function TabGroup({
3866
3877
  align = "start",
@@ -3876,11 +3887,16 @@ function TabGroup({
3876
3887
  var _a, _b;
3877
3888
  const rootRef = React21.useRef(null);
3878
3889
  const tabStripRef = React21.useRef(null);
3890
+ const measureRef = React21.useRef(null);
3879
3891
  const idBase = React21.useId();
3880
3892
  const [effectiveFill, setEffectiveFill] = React21.useState(fill);
3881
3893
  const [availableMain, setAvailableMain] = React21.useState(0);
3882
- const [minMain, setMinMain] = React21.useState(32);
3894
+ const [cssMinMain, setCssMinMain] = React21.useState(32);
3895
+ const [contentMinMain, setContentMinMain] = React21.useState(0);
3883
3896
  const count = tabs.length;
3897
+ const isVertical = position === "left" || position === "right";
3898
+ const minMain = Math.max(cssMinMain, contentMinMain);
3899
+ const partialMainSize = Math.max(Number.isFinite(size) ? size : 0, minMain);
3884
3900
  const clampIndex = React21.useCallback(
3885
3901
  (i) => {
3886
3902
  if (count <= 0) {
@@ -3923,14 +3939,16 @@ function TabGroup({
3923
3939
  const radius = parseFloat(computed.getPropertyValue("--rui-tab-panel-radius")) || 0;
3924
3940
  const border = parseFloat(computed.getPropertyValue("--rui-tab-border")) || 0;
3925
3941
  const minMainValue = parseFloat(computed.getPropertyValue("--rui-tab-min-main")) || 32;
3942
+ const effectiveMinMain = Math.max(minMainValue, contentMinMain);
3926
3943
  const wiggle = border * 2 + 1;
3927
3944
  const available = position === "top" || position === "bottom" ? rect.width : rect.height;
3928
- const required = (size != null ? size : 0) * tabs.length;
3929
- const slots2 = minMainValue > 0 ? Math.floor(available / minMainValue) : tabs.length;
3945
+ const requiredPerTab = Math.max(size != null ? size : 0, effectiveMinMain);
3946
+ const required = requiredPerTab * tabs.length;
3947
+ const slots2 = effectiveMinMain > 0 ? Math.floor(available / effectiveMinMain) : tabs.length;
3930
3948
  const hasOverflowControls = slots2 < tabs.length;
3931
3949
  const shouldFill = available - 2 * radius - wiggle <= required;
3932
3950
  setEffectiveFill(shouldFill || hasOverflowControls ? "full" : "partial");
3933
- }, [fill, position, size, tabs.length]);
3951
+ }, [contentMinMain, fill, position, size, tabs.length]);
3934
3952
  React21.useLayoutEffect(() => {
3935
3953
  if (fill === "full") {
3936
3954
  setEffectiveFill("full");
@@ -3945,14 +3963,43 @@ function TabGroup({
3945
3963
  observer.observe(node);
3946
3964
  return () => observer.disconnect();
3947
3965
  }, [fill, updateEffectiveFill]);
3948
- const isVertical = position === "left" || position === "right";
3949
3966
  React21.useLayoutEffect(() => {
3950
3967
  const root = rootRef.current;
3951
3968
  if (!root) return;
3952
3969
  const computed = getComputedStyle(root);
3953
3970
  const cssMin = parseFloat(computed.getPropertyValue("--rui-tab-min-main"));
3954
- setMinMain(Number.isFinite(cssMin) && cssMin > 0 ? cssMin : 32);
3971
+ setCssMinMain(Number.isFinite(cssMin) && cssMin > 0 ? cssMin : 32);
3955
3972
  }, [position]);
3973
+ React21.useLayoutEffect(() => {
3974
+ const node = measureRef.current;
3975
+ if (!node) return;
3976
+ const measure = () => {
3977
+ const sampleTab = node.querySelector(".rui-tab-group__tab");
3978
+ const labels = Array.from(node.querySelectorAll(".rui-tab-group__label"));
3979
+ if (!sampleTab || labels.length === 0) {
3980
+ setContentMinMain(0);
3981
+ return;
3982
+ }
3983
+ const tabStyle = getComputedStyle(sampleTab);
3984
+ const paddingMain = isVertical ? (parseFloat(tabStyle.paddingTop) || 0) + (parseFloat(tabStyle.paddingBottom) || 0) : (parseFloat(tabStyle.paddingLeft) || 0) + (parseFloat(tabStyle.paddingRight) || 0);
3985
+ const borderMain = isVertical ? (parseFloat(tabStyle.borderTopWidth) || 0) + (parseFloat(tabStyle.borderBottomWidth) || 0) : (parseFloat(tabStyle.borderLeftWidth) || 0) + (parseFloat(tabStyle.borderRightWidth) || 0);
3986
+ let largestLabelMain = 0;
3987
+ for (const label of labels) {
3988
+ const rect = label.getBoundingClientRect();
3989
+ const labelMain = isVertical ? rect.height : rect.width;
3990
+ if (labelMain > largestLabelMain) {
3991
+ largestLabelMain = labelMain;
3992
+ }
3993
+ }
3994
+ const next = Math.ceil(largestLabelMain + paddingMain + borderMain);
3995
+ setContentMinMain((prev) => prev === next ? prev : next);
3996
+ };
3997
+ measure();
3998
+ if (typeof ResizeObserver === "undefined") return;
3999
+ const observer = new ResizeObserver(() => measure());
4000
+ observer.observe(node);
4001
+ return () => observer.disconnect();
4002
+ }, [isVertical, position, rotation, tabs]);
3956
4003
  React21.useLayoutEffect(() => {
3957
4004
  const node = tabStripRef.current;
3958
4005
  if (!node) return;
@@ -3968,7 +4015,8 @@ function TabGroup({
3968
4015
  }, [isVertical]);
3969
4016
  const slots = availableMain > 0 && minMain > 0 ? Math.floor(availableMain / minMain) : count;
3970
4017
  const overflow = slots < count;
3971
- const windowSize = overflow ? Math.max(1, slots - 2) : count;
4018
+ const layoutSlots = overflow ? Math.max(3, slots) : Math.max(1, slots);
4019
+ const windowSize = overflow ? Math.max(1, layoutSlots - 2) : count;
3972
4020
  const maxStart = Math.max(0, count - windowSize);
3973
4021
  const [startIndex, setStartIndex] = React21.useState(0);
3974
4022
  React21.useEffect(() => {
@@ -3988,9 +4036,9 @@ function TabGroup({
3988
4036
  });
3989
4037
  }, [currentActive, overflow, windowSize]);
3990
4038
  const visibleTabs = overflow ? tabs.slice(startIndex, startIndex + windowSize) : tabs;
3991
- const slotSize = overflow && slots > 0 ? availableMain / slots : 0;
4039
+ const slotSize = overflow && layoutSlots > 0 ? availableMain / layoutSlots : 0;
3992
4040
  const overflowMainStyle = overflow && slotSize > 0 ? isVertical ? { height: slotSize } : { width: slotSize } : void 0;
3993
- const mainStyle = overflow ? overflowMainStyle : effectiveFill === "partial" ? isVertical ? { height: size } : { width: size } : void 0;
4041
+ const mainStyle = overflow ? overflowMainStyle : effectiveFill === "partial" ? isVertical ? { height: partialMainSize } : { width: partialMainSize } : void 0;
3994
4042
  const scrollLabels = isVertical ? { back: "Scroll tabs up", forward: "Scroll tabs down" } : { back: "Scroll tabs left", forward: "Scroll tabs right" };
3995
4043
  const scrollMainStyle = overflowMainStyle;
3996
4044
  const panelId = `${idBase}-panel`;
@@ -4125,7 +4173,7 @@ function TabGroup({
4125
4173
  children: (_b = (_a = tabs[currentActive]) == null ? void 0 : _a.content) != null ? _b : null
4126
4174
  }
4127
4175
  );
4128
- return /* @__PURE__ */ jsx25(
4176
+ return /* @__PURE__ */ jsxs23(
4129
4177
  "div",
4130
4178
  {
4131
4179
  ref: rootRef,
@@ -4136,13 +4184,16 @@ function TabGroup({
4136
4184
  "data-requested-fill": fill,
4137
4185
  "data-rotation": rotation,
4138
4186
  "data-overflow": overflow ? "true" : "false",
4139
- children: tabsFirst ? /* @__PURE__ */ jsxs23(Fragment2, { children: [
4140
- tabList,
4141
- panel
4142
- ] }) : /* @__PURE__ */ jsxs23(Fragment2, { children: [
4143
- panel,
4144
- tabList
4145
- ] })
4187
+ children: [
4188
+ /* @__PURE__ */ jsx25("div", { ref: measureRef, className: "rui-tab-group__measure", "aria-hidden": "true", children: tabs.map((tab, index) => /* @__PURE__ */ jsx25("button", { type: "button", className: "rui-tab-group__tab", children: /* @__PURE__ */ jsx25("span", { className: "rui-tab-group__label", children: tab.label }) }, index)) }),
4189
+ tabsFirst ? /* @__PURE__ */ jsxs23(Fragment2, { children: [
4190
+ tabList,
4191
+ panel
4192
+ ] }) : /* @__PURE__ */ jsxs23(Fragment2, { children: [
4193
+ panel,
4194
+ tabList
4195
+ ] })
4196
+ ]
4146
4197
  }
4147
4198
  );
4148
4199
  }