@dreamtree-org/twreact-ui 1.0.60 → 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.esm.js CHANGED
@@ -10356,7 +10356,7 @@ function Switch(props) {
10356
10356
  topLabel = props.topLabel,
10357
10357
  bottomLabel = props.bottomLabel,
10358
10358
  rightLabel = props.rightLabel,
10359
- leftLable = props.leftLable,
10359
+ leftLabel = props.leftLabel,
10360
10360
  ariaLabel = props.ariaLabel;
10361
10361
  var isControlled = typeof checked === "boolean";
10362
10362
  var _useState = useState(defaultChecked),
@@ -10406,11 +10406,11 @@ function Switch(props) {
10406
10406
  var fallbackOnClass = isOn && !bgColor ? "bg-sky-500" : "";
10407
10407
 
10408
10408
  // Accessible label fallback: prefer ariaLabel, otherwise first provided visible label, otherwise "Toggle"
10409
- var accessibleLabel = ariaLabel || rightLabel || leftLable || topLabel || bottomLabel || "Toggle";
10409
+ var accessibleLabel = ariaLabel || rightLabel || leftLabel || topLabel || bottomLabel || "Toggle";
10410
10410
 
10411
10411
  // Container layout: column if top or bottom labels exist, otherwise row
10412
10412
  var containerIsColumn = Boolean(topLabel || bottomLabel);
10413
- var containerClass = [containerIsColumn ? "flex flex-col items-center" : "inline-flex items-center", "gap-2", className].filter(Boolean).join(" ");
10413
+ var containerClass = [containerIsColumn ? "flex flex-col " : "inline-flex items-center", "gap-2", className].filter(Boolean).join(" ");
10414
10414
  var labelOpacityClass = disabled ? "opacity-50" : "";
10415
10415
  return /*#__PURE__*/React__default.createElement("div", {
10416
10416
  className: containerClass
@@ -10419,10 +10419,10 @@ function Switch(props) {
10419
10419
  className: labelOpacityClass
10420
10420
  }, topLabel) : null, /*#__PURE__*/React__default.createElement("div", {
10421
10421
  className: "inline-flex items-center gap-2"
10422
- }, leftLable ? /*#__PURE__*/React__default.createElement("label", {
10422
+ }, leftLabel ? /*#__PURE__*/React__default.createElement("label", {
10423
10423
  htmlFor: idRef.current,
10424
10424
  className: labelOpacityClass
10425
- }, leftLable) : null, /*#__PURE__*/React__default.createElement("button", {
10425
+ }, leftLabel) : null, /*#__PURE__*/React__default.createElement("button", {
10426
10426
  id: idRef.current,
10427
10427
  type: "button",
10428
10428
  role: "switch",
@@ -10522,13 +10522,13 @@ var Form = function Form(_ref) {
10522
10522
  placeholder = field.placeholder,
10523
10523
  fieldProps = _objectWithoutProperties$1(field, _excluded2$3);
10524
10524
  var error = (_errors$name = errors[name]) === null || _errors$name === void 0 ? void 0 : _errors$name.message;
10525
- var commonProps = _objectSpread$8({
10525
+ var commonProps = _objectSpread$8(_objectSpread$8({
10526
10526
  name: name,
10527
10527
  label: label,
10528
10528
  required: required,
10529
10529
  error: error,
10530
10530
  placeholder: placeholder
10531
- }, fieldProps);
10531
+ }, fieldProps), field.options);
10532
10532
  switch (type) {
10533
10533
  case "text":
10534
10534
  case "email":
@@ -10784,13 +10784,13 @@ var Form = function Form(_ref) {
10784
10784
  onChange = _ref9$field.onChange,
10785
10785
  value = _ref9$field.value,
10786
10786
  ref = _ref9$field.ref;
10787
- return /*#__PURE__*/React__default.createElement(Switch, {
10787
+ return /*#__PURE__*/React__default.createElement(Switch, _extends({
10788
10788
  checked: !!value,
10789
10789
  onChange: onChange,
10790
10790
  ref: ref,
10791
10791
  label: label,
10792
10792
  disabled: fieldProps.disabled
10793
- });
10793
+ }, commonProps));
10794
10794
  }
10795
10795
  });
10796
10796
  case "custom":
@@ -15092,23 +15092,56 @@ function LocationPicker(_ref) {
15092
15092
  }, iconButton)));
15093
15093
  }
15094
15094
 
15095
- var _excluded$d = ["items", "collapsed", "onToggle", "className", "logo", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen"];
15096
- var Sidebar = function Sidebar(_ref) {
15097
- var _ref$items = _ref.items,
15098
- items = _ref$items === void 0 ? [] : _ref$items,
15099
- _ref$collapsed = _ref.collapsed,
15100
- collapsed = _ref$collapsed === void 0 ? false : _ref$collapsed,
15101
- onToggle = _ref.onToggle,
15102
- className = _ref.className,
15103
- logo = _ref.logo,
15104
- user = _ref.user,
15105
- onUserClick = _ref.onUserClick,
15106
- _ref$drawerPosition = _ref.drawerPosition,
15107
- drawerPosition = _ref$drawerPosition === void 0 ? "left" : _ref$drawerPosition,
15108
- _ref$isMobileOpen = _ref.isMobileOpen,
15109
- isMobileOpen = _ref$isMobileOpen === void 0 ? false : _ref$isMobileOpen,
15110
- setIsMobileOpen = _ref.setIsMobileOpen,
15111
- props = _objectWithoutProperties$1(_ref, _excluded$d);
15095
+ var _excluded$d = ["items", "collapsed", "onToggle", "className", "logo", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipClassName"];
15096
+
15097
+ /**
15098
+ * Small built-in tooltip used by the Sidebar when collapsed.
15099
+ * Pure CSS + tiny visible prop for fade in/out.
15100
+ */
15101
+ var SidebarTooltip = function SidebarTooltip(_ref) {
15102
+ var label = _ref.label,
15103
+ visible = _ref.visible,
15104
+ className = _ref.className;
15105
+ return /*#__PURE__*/React__default.createElement("div", {
15106
+ 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", {
15107
+ "opacity-100": visible
15108
+ }, className),
15109
+ role: "tooltip",
15110
+ "aria-hidden": !visible
15111
+ }, label);
15112
+ };
15113
+
15114
+ /**
15115
+ * Sidebar component with custom tooltip for collapsed mode.
15116
+ *
15117
+ * Props:
15118
+ * - items: array of { id, label, icon, children?, onClick?, active? }
15119
+ * - collapsed: boolean (desktop collapsed)
15120
+ * - onToggle: function to toggle collapse
15121
+ * - className, logo, user, onUserClick
15122
+ * - drawerPosition: 'left' | 'right'
15123
+ * - isMobileOpen, setIsMobileOpen
15124
+ * - showCollapsedTooltips: boolean (default true)
15125
+ */
15126
+ var Sidebar = function Sidebar(_ref2) {
15127
+ var _ref2$items = _ref2.items,
15128
+ items = _ref2$items === void 0 ? [] : _ref2$items,
15129
+ _ref2$collapsed = _ref2.collapsed,
15130
+ collapsed = _ref2$collapsed === void 0 ? false : _ref2$collapsed,
15131
+ onToggle = _ref2.onToggle,
15132
+ className = _ref2.className,
15133
+ logo = _ref2.logo,
15134
+ user = _ref2.user,
15135
+ onUserClick = _ref2.onUserClick,
15136
+ _ref2$drawerPosition = _ref2.drawerPosition,
15137
+ drawerPosition = _ref2$drawerPosition === void 0 ? "left" : _ref2$drawerPosition,
15138
+ _ref2$isMobileOpen = _ref2.isMobileOpen,
15139
+ isMobileOpen = _ref2$isMobileOpen === void 0 ? false : _ref2$isMobileOpen,
15140
+ setIsMobileOpen = _ref2.setIsMobileOpen,
15141
+ _ref2$showCollapsedTo = _ref2.showCollapsedTooltips,
15142
+ showCollapsedTooltips = _ref2$showCollapsedTo === void 0 ? true : _ref2$showCollapsedTo,
15143
+ tooltipClassName = _ref2.tooltipClassName,
15144
+ props = _objectWithoutProperties$1(_ref2, _excluded$d);
15112
15145
  var _useState = useState(new Set()),
15113
15146
  _useState2 = _slicedToArray(_useState, 2),
15114
15147
  expandedItems = _useState2[0],
@@ -15117,19 +15150,14 @@ var Sidebar = function Sidebar(_ref) {
15117
15150
  _useState4 = _slicedToArray(_useState3, 2),
15118
15151
  activeItemId = _useState4[0],
15119
15152
  setActiveItemId = _useState4[1];
15120
-
15121
- // Use props for mobile state, fallback to false
15153
+ var _useState5 = useState(null),
15154
+ _useState6 = _slicedToArray(_useState5, 2),
15155
+ hoveredItemId = _useState6[0],
15156
+ setHoveredItemId = _useState6[1];
15122
15157
  var mobileOpen = isMobileOpen !== null && isMobileOpen !== void 0 ? isMobileOpen : false;
15123
-
15124
- // Ensure mobile always shows full sidebar (no collapse on mobile)
15125
15158
  var effectiveCollapsed = mobileOpen ? false : collapsed;
15126
15159
  useEffect(function () {
15127
- // Prevent body scroll when mobile sidebar is open
15128
- if (mobileOpen) {
15129
- document.body.style.overflow = "hidden";
15130
- } else {
15131
- document.body.style.overflow = "";
15132
- }
15160
+ if (mobileOpen) document.body.style.overflow = "hidden";else document.body.style.overflow = "";
15133
15161
  return function () {
15134
15162
  document.body.style.overflow = "";
15135
15163
  };
@@ -15139,58 +15167,53 @@ var Sidebar = function Sidebar(_ref) {
15139
15167
  if (next.has(itemId)) next["delete"](itemId);else next.add(itemId);
15140
15168
  setExpandedItems(next);
15141
15169
  };
15142
-
15143
- // New helper to expand a single item (replace existing expanded set)
15144
15170
  var expandSingle = function expandSingle(itemId) {
15145
- var next = new Set(expandedItems);
15171
+ var next = new Set();
15146
15172
  next.add(itemId);
15147
15173
  setExpandedItems(next);
15148
15174
  };
15149
15175
  var handleItemClick = function handleItemClick(item) {
15150
15176
  var hasChildren = item.children && item.children.length > 0;
15151
-
15152
- // If item has children and sidebar is collapsed (desktop),
15153
- // uncollapse the sidebar and expand + activate this item.
15154
15177
  if (hasChildren && effectiveCollapsed && !mobileOpen) {
15155
- // Ask parent to toggle collapsed state (uncollapse)
15178
+ // ask parent to uncollapse
15156
15179
  onToggle === null || onToggle === void 0 || onToggle();
15157
-
15158
- // Mark this item active and expanded locally.
15159
- // We don't delay because the parent prop change will re-render; this state persists.
15160
15180
  setActiveItemId(item.id);
15161
15181
  expandSingle(item.id);
15162
15182
  return;
15163
15183
  }
15164
-
15165
- // Normal behavior when not collapsed or on mobile:
15166
15184
  if (hasChildren) {
15167
15185
  toggleExpanded(item.id);
15168
15186
  setActiveItemId(item.id);
15169
15187
  } else {
15170
15188
  var _item$onClick;
15171
- // leaf item: call its onClick and close mobile if needed
15172
15189
  (_item$onClick = item.onClick) === null || _item$onClick === void 0 || _item$onClick.call(item, item);
15173
15190
  setActiveItemId(item.id);
15174
- if (mobileOpen && setIsMobileOpen) {
15175
- setIsMobileOpen(false);
15176
- }
15191
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
15177
15192
  }
15178
15193
  };
15179
15194
  var handleUserClick = function handleUserClick() {
15180
15195
  onUserClick === null || onUserClick === void 0 || onUserClick(user);
15181
- // Close mobile sidebar when user is clicked
15182
- if (mobileOpen && setIsMobileOpen) {
15183
- setIsMobileOpen(false);
15184
- }
15196
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
15185
15197
  };
15186
15198
  var _renderMenuItem = function renderMenuItem(item) {
15187
15199
  var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
15188
15200
  var hasChildren = item.children && item.children.length > 0;
15189
15201
  var isExpanded = expandedItems.has(item.id);
15190
- // isActive if either the prop says so or we marked it active locally
15191
15202
  var isActive = Boolean(item.active) || activeItemId === item.id;
15203
+ var showTooltipForThis = effectiveCollapsed && level === 0 && showCollapsedTooltips;
15204
+
15205
+ // container needs relative to position tooltip
15192
15206
  return /*#__PURE__*/React__default.createElement("div", {
15193
- key: item.id
15207
+ key: item.id,
15208
+ className: "relative",
15209
+ onMouseEnter: function onMouseEnter() {
15210
+ return setHoveredItemId(item.id);
15211
+ },
15212
+ onMouseLeave: function onMouseLeave() {
15213
+ return setHoveredItemId(function (id) {
15214
+ return id === item.id ? null : id;
15215
+ });
15216
+ }
15194
15217
  }, /*#__PURE__*/React__default.createElement("div", {
15195
15218
  className: cn$1("flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors cursor-pointer", {
15196
15219
  "bg-primary-100 text-primary-700": isActive,
@@ -15202,11 +15225,20 @@ var Sidebar = function Sidebar(_ref) {
15202
15225
  },
15203
15226
  role: "button",
15204
15227
  tabIndex: 0,
15228
+ "aria-label": item.label,
15205
15229
  onKeyDown: function onKeyDown(e) {
15206
15230
  if (e.key === "Enter" || e.key === " ") {
15207
15231
  e.preventDefault();
15208
15232
  handleItemClick(item);
15209
15233
  }
15234
+ },
15235
+ onFocus: function onFocus() {
15236
+ return setHoveredItemId(item.id);
15237
+ },
15238
+ onBlur: function onBlur() {
15239
+ return setHoveredItemId(function (id) {
15240
+ return id === item.id ? null : id;
15241
+ });
15210
15242
  }
15211
15243
  }, item.icon && /*#__PURE__*/React__default.createElement("span", {
15212
15244
  className: cn$1("flex-shrink-0", {
@@ -15225,16 +15257,14 @@ var Sidebar = function Sidebar(_ref) {
15225
15257
  className: "mt-1 space-y-1 ml-2"
15226
15258
  }, item.children.map(function (child) {
15227
15259
  return _renderMenuItem(child, level + 1);
15228
- })));
15260
+ })), showTooltipForThis && /*#__PURE__*/React__default.createElement(SidebarTooltip, {
15261
+ label: item.label,
15262
+ visible: hoveredItemId === item.id,
15263
+ className: tooltipClassName
15264
+ }));
15229
15265
  };
15230
-
15231
- // When on mobile, clicking the toggle should close drawer instead of toggling collapse
15232
15266
  var handleToggleClick = function handleToggleClick() {
15233
- if (mobileOpen && setIsMobileOpen) {
15234
- setIsMobileOpen(false);
15235
- } else {
15236
- onToggle === null || onToggle === void 0 || onToggle();
15237
- }
15267
+ if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);else onToggle === null || onToggle === void 0 || onToggle();
15238
15268
  };
15239
15269
  var SidebarContent = /*#__PURE__*/React__default.createElement("div", {
15240
15270
  className: cn$1("flex h-full flex-col bg-white border-r border-gray-200 shadow-sm", "w-64 transition-all duration-200", {
@@ -15254,11 +15284,21 @@ var Sidebar = function Sidebar(_ref) {
15254
15284
  }) : /*#__PURE__*/React__default.createElement(ChevronLeft, {
15255
15285
  className: "h-5 w-5"
15256
15286
  }))), /*#__PURE__*/React__default.createElement("nav", {
15257
- 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"
15287
+ 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"
15258
15288
  }, items.map(function (item) {
15259
15289
  return _renderMenuItem(item);
15260
15290
  })), user && /*#__PURE__*/React__default.createElement("div", {
15261
15291
  className: "border-t border-gray-200 p-4"
15292
+ }, /*#__PURE__*/React__default.createElement("div", {
15293
+ className: "relative",
15294
+ onMouseEnter: function onMouseEnter() {
15295
+ return setHoveredItemId("user");
15296
+ },
15297
+ onMouseLeave: function onMouseLeave() {
15298
+ return setHoveredItemId(function (id) {
15299
+ return id === "user" ? null : id;
15300
+ });
15301
+ }
15262
15302
  }, /*#__PURE__*/React__default.createElement("div", {
15263
15303
  className: cn$1("flex items-center rounded-md px-3 py-2 cursor-pointer hover:bg-gray-100 transition-colors", {
15264
15304
  "justify-center": effectiveCollapsed,
@@ -15267,10 +15307,13 @@ var Sidebar = function Sidebar(_ref) {
15267
15307
  onClick: handleUserClick,
15268
15308
  role: "button",
15269
15309
  tabIndex: 0,
15270
- onKeyDown: function onKeyDown(e) {
15271
- if (e.key === "Enter" || e.key === " ") {
15272
- handleUserClick();
15273
- }
15310
+ onFocus: function onFocus() {
15311
+ return setHoveredItemId("user");
15312
+ },
15313
+ onBlur: function onBlur() {
15314
+ return setHoveredItemId(function (id) {
15315
+ return id === "user" ? null : id;
15316
+ });
15274
15317
  }
15275
15318
  }, user.avatar && /*#__PURE__*/React__default.createElement("img", {
15276
15319
  src: user.avatar,
@@ -15282,12 +15325,11 @@ var Sidebar = function Sidebar(_ref) {
15282
15325
  className: "text-sm font-medium text-gray-700 truncate"
15283
15326
  }, user.name), /*#__PURE__*/React__default.createElement("p", {
15284
15327
  className: "text-xs text-gray-500 truncate"
15285
- }, user.email)))));
15286
-
15287
- // Compute classes based on drawer position
15328
+ }, user.email))), effectiveCollapsed && showCollapsedTooltips && /*#__PURE__*/React__default.createElement(SidebarTooltip, {
15329
+ label: user.name,
15330
+ visible: hoveredItemId === "user"
15331
+ }))));
15288
15332
  var isRight = drawerPosition === "right";
15289
-
15290
- // Mobile drawer styles
15291
15333
  var mobileDrawerClasses = cn$1("fixed top-0 z-50 h-full transition-transform duration-300 ease-in-out md:hidden", {
15292
15334
  "left-0": !isRight,
15293
15335
  "right-0": isRight
@@ -15296,8 +15338,6 @@ var Sidebar = function Sidebar(_ref) {
15296
15338
  "-translate-x-full": !mobileOpen && !isRight,
15297
15339
  "translate-x-full": !mobileOpen && isRight
15298
15340
  });
15299
-
15300
- // Desktop placement
15301
15341
  var desktopPlacementClass = isRight ? "md:order-last" : "";
15302
15342
  return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", {
15303
15343
  className: "hidden md:flex sticky top-0 h-screen"