@dreamtree-org/twreact-ui 1.0.61 → 1.0.62

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
@@ -10430,7 +10430,7 @@ function Switch(props) {
10430
10430
 
10431
10431
  // Container layout: column if top or bottom labels exist, otherwise row
10432
10432
  var containerIsColumn = Boolean(topLabel || bottomLabel);
10433
- var containerClass = [containerIsColumn ? "flex flex-col items-center" : "inline-flex items-center", "gap-2", className].filter(Boolean).join(" ");
10433
+ var containerClass = [containerIsColumn ? "flex flex-col " : "inline-flex items-center", "gap-2", className].filter(Boolean).join(" ");
10434
10434
  var labelOpacityClass = disabled ? "opacity-50" : "";
10435
10435
  return /*#__PURE__*/React.createElement("div", {
10436
10436
  className: containerClass
@@ -15112,23 +15112,56 @@ function LocationPicker(_ref) {
15112
15112
  }, iconButton)));
15113
15113
  }
15114
15114
 
15115
- var _excluded$d = ["items", "collapsed", "onToggle", "className", "logo", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen"];
15116
- var Sidebar = function Sidebar(_ref) {
15117
- var _ref$items = _ref.items,
15118
- items = _ref$items === void 0 ? [] : _ref$items,
15119
- _ref$collapsed = _ref.collapsed,
15120
- collapsed = _ref$collapsed === void 0 ? false : _ref$collapsed,
15121
- onToggle = _ref.onToggle,
15122
- className = _ref.className,
15123
- logo = _ref.logo,
15124
- user = _ref.user,
15125
- onUserClick = _ref.onUserClick,
15126
- _ref$drawerPosition = _ref.drawerPosition,
15127
- drawerPosition = _ref$drawerPosition === void 0 ? "left" : _ref$drawerPosition,
15128
- _ref$isMobileOpen = _ref.isMobileOpen,
15129
- isMobileOpen = _ref$isMobileOpen === void 0 ? false : _ref$isMobileOpen,
15130
- setIsMobileOpen = _ref.setIsMobileOpen,
15131
- props = _objectWithoutProperties$1(_ref, _excluded$d);
15115
+ var _excluded$d = ["items", "collapsed", "onToggle", "className", "logo", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipClassName"];
15116
+
15117
+ /**
15118
+ * Small built-in tooltip used by the Sidebar when collapsed.
15119
+ * Pure CSS + tiny visible prop for fade in/out.
15120
+ */
15121
+ var SidebarTooltip = function SidebarTooltip(_ref) {
15122
+ var label = _ref.label,
15123
+ visible = _ref.visible,
15124
+ className = _ref.className;
15125
+ return /*#__PURE__*/React.createElement("div", {
15126
+ className: cn$1("absolute left-full top-1/2 -translate-y-1/2 ml-2 whitespace-nowrap", "px-2 py-1 rounded-md bg-gray-900 text-white text-xs shadow-lg", "opacity-0 pointer-events-none transition-opacity duration-150 pb-2 pt-2", {
15127
+ "opacity-100": visible
15128
+ }, className),
15129
+ role: "tooltip",
15130
+ "aria-hidden": !visible
15131
+ }, label);
15132
+ };
15133
+
15134
+ /**
15135
+ * Sidebar component with custom tooltip for collapsed mode.
15136
+ *
15137
+ * Props:
15138
+ * - items: array of { id, label, icon, children?, onClick?, active? }
15139
+ * - collapsed: boolean (desktop collapsed)
15140
+ * - onToggle: function to toggle collapse
15141
+ * - className, logo, user, onUserClick
15142
+ * - drawerPosition: 'left' | 'right'
15143
+ * - isMobileOpen, setIsMobileOpen
15144
+ * - showCollapsedTooltips: boolean (default true)
15145
+ */
15146
+ var Sidebar = function Sidebar(_ref2) {
15147
+ var _ref2$items = _ref2.items,
15148
+ items = _ref2$items === void 0 ? [] : _ref2$items,
15149
+ _ref2$collapsed = _ref2.collapsed,
15150
+ collapsed = _ref2$collapsed === void 0 ? false : _ref2$collapsed,
15151
+ onToggle = _ref2.onToggle,
15152
+ className = _ref2.className,
15153
+ logo = _ref2.logo,
15154
+ user = _ref2.user,
15155
+ onUserClick = _ref2.onUserClick,
15156
+ _ref2$drawerPosition = _ref2.drawerPosition,
15157
+ drawerPosition = _ref2$drawerPosition === void 0 ? "left" : _ref2$drawerPosition,
15158
+ _ref2$isMobileOpen = _ref2.isMobileOpen,
15159
+ isMobileOpen = _ref2$isMobileOpen === void 0 ? false : _ref2$isMobileOpen,
15160
+ setIsMobileOpen = _ref2.setIsMobileOpen,
15161
+ _ref2$showCollapsedTo = _ref2.showCollapsedTooltips,
15162
+ showCollapsedTooltips = _ref2$showCollapsedTo === void 0 ? true : _ref2$showCollapsedTo,
15163
+ tooltipClassName = _ref2.tooltipClassName,
15164
+ props = _objectWithoutProperties$1(_ref2, _excluded$d);
15132
15165
  var _useState = React.useState(new Set()),
15133
15166
  _useState2 = _slicedToArray(_useState, 2),
15134
15167
  expandedItems = _useState2[0],
@@ -15137,19 +15170,14 @@ var Sidebar = function Sidebar(_ref) {
15137
15170
  _useState4 = _slicedToArray(_useState3, 2),
15138
15171
  activeItemId = _useState4[0],
15139
15172
  setActiveItemId = _useState4[1];
15140
-
15141
- // Use props for mobile state, fallback to false
15173
+ var _useState5 = React.useState(null),
15174
+ _useState6 = _slicedToArray(_useState5, 2),
15175
+ hoveredItemId = _useState6[0],
15176
+ setHoveredItemId = _useState6[1];
15142
15177
  var mobileOpen = isMobileOpen !== null && isMobileOpen !== void 0 ? isMobileOpen : false;
15143
-
15144
- // Ensure mobile always shows full sidebar (no collapse on mobile)
15145
15178
  var effectiveCollapsed = mobileOpen ? false : collapsed;
15146
15179
  React.useEffect(function () {
15147
- // Prevent body scroll when mobile sidebar is open
15148
- if (mobileOpen) {
15149
- document.body.style.overflow = "hidden";
15150
- } else {
15151
- document.body.style.overflow = "";
15152
- }
15180
+ if (mobileOpen) document.body.style.overflow = "hidden";else document.body.style.overflow = "";
15153
15181
  return function () {
15154
15182
  document.body.style.overflow = "";
15155
15183
  };
@@ -15159,58 +15187,53 @@ var Sidebar = function Sidebar(_ref) {
15159
15187
  if (next.has(itemId)) next["delete"](itemId);else next.add(itemId);
15160
15188
  setExpandedItems(next);
15161
15189
  };
15162
-
15163
- // New helper to expand a single item (replace existing expanded set)
15164
15190
  var expandSingle = function expandSingle(itemId) {
15165
- var next = new Set(expandedItems);
15191
+ var next = new Set();
15166
15192
  next.add(itemId);
15167
15193
  setExpandedItems(next);
15168
15194
  };
15169
15195
  var handleItemClick = function handleItemClick(item) {
15170
15196
  var hasChildren = item.children && item.children.length > 0;
15171
-
15172
- // If item has children and sidebar is collapsed (desktop),
15173
- // uncollapse the sidebar and expand + activate this item.
15174
15197
  if (hasChildren && effectiveCollapsed && !mobileOpen) {
15175
- // Ask parent to toggle collapsed state (uncollapse)
15198
+ // ask parent to uncollapse
15176
15199
  onToggle === null || onToggle === void 0 || onToggle();
15177
-
15178
- // Mark this item active and expanded locally.
15179
- // We don't delay because the parent prop change will re-render; this state persists.
15180
15200
  setActiveItemId(item.id);
15181
15201
  expandSingle(item.id);
15182
15202
  return;
15183
15203
  }
15184
-
15185
- // Normal behavior when not collapsed or on mobile:
15186
15204
  if (hasChildren) {
15187
15205
  toggleExpanded(item.id);
15188
15206
  setActiveItemId(item.id);
15189
15207
  } else {
15190
15208
  var _item$onClick;
15191
- // leaf item: call its onClick and close mobile if needed
15192
15209
  (_item$onClick = item.onClick) === null || _item$onClick === void 0 || _item$onClick.call(item, item);
15193
15210
  setActiveItemId(item.id);
15194
- if (mobileOpen && setIsMobileOpen) {
15195
- setIsMobileOpen(false);
15196
- }
15211
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
15197
15212
  }
15198
15213
  };
15199
15214
  var handleUserClick = function handleUserClick() {
15200
15215
  onUserClick === null || onUserClick === void 0 || onUserClick(user);
15201
- // Close mobile sidebar when user is clicked
15202
- if (mobileOpen && setIsMobileOpen) {
15203
- setIsMobileOpen(false);
15204
- }
15216
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
15205
15217
  };
15206
15218
  var _renderMenuItem = function renderMenuItem(item) {
15207
15219
  var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
15208
15220
  var hasChildren = item.children && item.children.length > 0;
15209
15221
  var isExpanded = expandedItems.has(item.id);
15210
- // isActive if either the prop says so or we marked it active locally
15211
15222
  var isActive = Boolean(item.active) || activeItemId === item.id;
15223
+ var showTooltipForThis = effectiveCollapsed && level === 0 && showCollapsedTooltips;
15224
+
15225
+ // container needs relative to position tooltip
15212
15226
  return /*#__PURE__*/React.createElement("div", {
15213
- key: item.id
15227
+ key: item.id,
15228
+ className: "relative",
15229
+ onMouseEnter: function onMouseEnter() {
15230
+ return setHoveredItemId(item.id);
15231
+ },
15232
+ onMouseLeave: function onMouseLeave() {
15233
+ return setHoveredItemId(function (id) {
15234
+ return id === item.id ? null : id;
15235
+ });
15236
+ }
15214
15237
  }, /*#__PURE__*/React.createElement("div", {
15215
15238
  className: cn$1("flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors cursor-pointer", {
15216
15239
  "bg-primary-100 text-primary-700": isActive,
@@ -15222,11 +15245,20 @@ var Sidebar = function Sidebar(_ref) {
15222
15245
  },
15223
15246
  role: "button",
15224
15247
  tabIndex: 0,
15248
+ "aria-label": item.label,
15225
15249
  onKeyDown: function onKeyDown(e) {
15226
15250
  if (e.key === "Enter" || e.key === " ") {
15227
15251
  e.preventDefault();
15228
15252
  handleItemClick(item);
15229
15253
  }
15254
+ },
15255
+ onFocus: function onFocus() {
15256
+ return setHoveredItemId(item.id);
15257
+ },
15258
+ onBlur: function onBlur() {
15259
+ return setHoveredItemId(function (id) {
15260
+ return id === item.id ? null : id;
15261
+ });
15230
15262
  }
15231
15263
  }, item.icon && /*#__PURE__*/React.createElement("span", {
15232
15264
  className: cn$1("flex-shrink-0", {
@@ -15245,16 +15277,14 @@ var Sidebar = function Sidebar(_ref) {
15245
15277
  className: "mt-1 space-y-1 ml-2"
15246
15278
  }, item.children.map(function (child) {
15247
15279
  return _renderMenuItem(child, level + 1);
15248
- })));
15280
+ })), showTooltipForThis && /*#__PURE__*/React.createElement(SidebarTooltip, {
15281
+ label: item.label,
15282
+ visible: hoveredItemId === item.id,
15283
+ className: tooltipClassName
15284
+ }));
15249
15285
  };
15250
-
15251
- // When on mobile, clicking the toggle should close drawer instead of toggling collapse
15252
15286
  var handleToggleClick = function handleToggleClick() {
15253
- if (mobileOpen && setIsMobileOpen) {
15254
- setIsMobileOpen(false);
15255
- } else {
15256
- onToggle === null || onToggle === void 0 || onToggle();
15257
- }
15287
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);else onToggle === null || onToggle === void 0 || onToggle();
15258
15288
  };
15259
15289
  var SidebarContent = /*#__PURE__*/React.createElement("div", {
15260
15290
  className: cn$1("flex h-full flex-col bg-white border-r border-gray-200 shadow-sm", "w-64 transition-all duration-200", {
@@ -15274,11 +15304,21 @@ var Sidebar = function Sidebar(_ref) {
15274
15304
  }) : /*#__PURE__*/React.createElement(ChevronLeft, {
15275
15305
  className: "h-5 w-5"
15276
15306
  }))), /*#__PURE__*/React.createElement("nav", {
15277
- className: "flex-1 space-y-1 p-4 overflow-y-auto [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 hover:[&::-webkit-scrollbar-thumb]:bg-gray-400"
15307
+ className: "flex-1 space-y-1 p-4 [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 hover:[&::-webkit-scrollbar-thumb]:bg-gray-400"
15278
15308
  }, items.map(function (item) {
15279
15309
  return _renderMenuItem(item);
15280
15310
  })), user && /*#__PURE__*/React.createElement("div", {
15281
15311
  className: "border-t border-gray-200 p-4"
15312
+ }, /*#__PURE__*/React.createElement("div", {
15313
+ className: "relative",
15314
+ onMouseEnter: function onMouseEnter() {
15315
+ return setHoveredItemId("user");
15316
+ },
15317
+ onMouseLeave: function onMouseLeave() {
15318
+ return setHoveredItemId(function (id) {
15319
+ return id === "user" ? null : id;
15320
+ });
15321
+ }
15282
15322
  }, /*#__PURE__*/React.createElement("div", {
15283
15323
  className: cn$1("flex items-center rounded-md px-3 py-2 cursor-pointer hover:bg-gray-100 transition-colors", {
15284
15324
  "justify-center": effectiveCollapsed,
@@ -15287,10 +15327,13 @@ var Sidebar = function Sidebar(_ref) {
15287
15327
  onClick: handleUserClick,
15288
15328
  role: "button",
15289
15329
  tabIndex: 0,
15290
- onKeyDown: function onKeyDown(e) {
15291
- if (e.key === "Enter" || e.key === " ") {
15292
- handleUserClick();
15293
- }
15330
+ onFocus: function onFocus() {
15331
+ return setHoveredItemId("user");
15332
+ },
15333
+ onBlur: function onBlur() {
15334
+ return setHoveredItemId(function (id) {
15335
+ return id === "user" ? null : id;
15336
+ });
15294
15337
  }
15295
15338
  }, user.avatar && /*#__PURE__*/React.createElement("img", {
15296
15339
  src: user.avatar,
@@ -15302,12 +15345,11 @@ var Sidebar = function Sidebar(_ref) {
15302
15345
  className: "text-sm font-medium text-gray-700 truncate"
15303
15346
  }, user.name), /*#__PURE__*/React.createElement("p", {
15304
15347
  className: "text-xs text-gray-500 truncate"
15305
- }, user.email)))));
15306
-
15307
- // Compute classes based on drawer position
15348
+ }, user.email))), effectiveCollapsed && showCollapsedTooltips && /*#__PURE__*/React.createElement(SidebarTooltip, {
15349
+ label: user.name,
15350
+ visible: hoveredItemId === "user"
15351
+ }))));
15308
15352
  var isRight = drawerPosition === "right";
15309
-
15310
- // Mobile drawer styles
15311
15353
  var mobileDrawerClasses = cn$1("fixed top-0 z-50 h-full transition-transform duration-300 ease-in-out md:hidden", {
15312
15354
  "left-0": !isRight,
15313
15355
  "right-0": isRight
@@ -15316,8 +15358,6 @@ var Sidebar = function Sidebar(_ref) {
15316
15358
  "-translate-x-full": !mobileOpen && !isRight,
15317
15359
  "translate-x-full": !mobileOpen && isRight
15318
15360
  });
15319
-
15320
- // Desktop placement
15321
15361
  var desktopPlacementClass = isRight ? "md:order-last" : "";
15322
15362
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
15323
15363
  className: "hidden md:flex sticky top-0 h-screen"