@dreamtree-org/twreact-ui 1.1.63 → 1.1.64

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 (34) hide show
  1. package/dist/components/core/Table/Table.d.ts +2 -1
  2. package/dist/components/core/Table/Table.d.ts.map +1 -1
  3. package/dist/components/feedback/Alert.d.ts +2 -9
  4. package/dist/components/feedback/Alert.d.ts.map +1 -1
  5. package/dist/components/feedback/Dialog.d.ts +1 -30
  6. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  7. package/dist/components/feedback/Toast.d.ts +1 -10
  8. package/dist/components/feedback/Toast.d.ts.map +1 -1
  9. package/dist/components/navigation/Breadcrumbs.d.ts +2 -9
  10. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  11. package/dist/components/navigation/FootNav.d.ts +2 -5
  12. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  13. package/dist/components/navigation/Navbar.d.ts +2 -29
  14. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  15. package/dist/components/navigation/Sidebar.d.ts +2 -15
  16. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  17. package/dist/components/utility/Avatar.d.ts +2 -10
  18. package/dist/components/utility/Avatar.d.ts.map +1 -1
  19. package/dist/components/utility/Badge.d.ts +2 -8
  20. package/dist/components/utility/Badge.d.ts.map +1 -1
  21. package/dist/components/utility/Card.d.ts +2 -38
  22. package/dist/components/utility/Card.d.ts.map +1 -1
  23. package/dist/components/utility/Carousel.d.ts +2 -1
  24. package/dist/components/utility/Carousel.d.ts.map +1 -1
  25. package/dist/components/utility/FileUpload.d.ts +2 -11
  26. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  27. package/dist/components/utility/Pagination.d.ts +2 -10
  28. package/dist/components/utility/Pagination.d.ts.map +1 -1
  29. package/dist/components/utility/Stepper.d.ts +2 -9
  30. package/dist/components/utility/Stepper.d.ts.map +1 -1
  31. package/dist/index.esm.js +92 -46
  32. package/dist/index.js +92 -46
  33. package/mcp/catalog.snapshot.json +15 -3
  34. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4761,7 +4761,7 @@ function MobileCard(_ref) {
4761
4761
  }, key);
4762
4762
  }
4763
4763
 
4764
- var _excluded$x = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "theme", "responsiveBreakpoint", "serverSide", "totalRecords", "pageNumber", "TheadComponent", "TfootComponent"];
4764
+ var _excluded$x = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "theme", "responsiveBreakpoint", "serverSide", "totalRecords", "pageNumber", "onPageChange", "TheadComponent", "TfootComponent"];
4765
4765
  function ownKeys$B(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4766
4766
  function _objectSpread$B(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$B(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$B(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4767
4767
  var DEFAULT_DATA = [];
@@ -4829,6 +4829,7 @@ var Table = function Table(_ref) {
4829
4829
  _ref$totalRecords = _ref.totalRecords,
4830
4830
  totalRecords = _ref$totalRecords === void 0 ? 0 : _ref$totalRecords,
4831
4831
  pageNumber = _ref.pageNumber,
4832
+ onPageChange = _ref.onPageChange,
4832
4833
  _ref$TheadComponent = _ref.TheadComponent,
4833
4834
  TheadComponent = _ref$TheadComponent === void 0 ? null : _ref$TheadComponent,
4834
4835
  _ref$TfootComponent = _ref.TfootComponent,
@@ -5169,7 +5170,8 @@ var Table = function Table(_ref) {
5169
5170
  }, [applyGlobalSearch]);
5170
5171
  var handlePageChange = React.useCallback(function (newPage) {
5171
5172
  setCurrentPage(newPage);
5172
- }, []);
5173
+ onPageChange === null || onPageChange === void 0 || onPageChange(newPage);
5174
+ }, [onPageChange]);
5173
5175
  var renderCell = React.useCallback(function (column, row, globalIndex) {
5174
5176
  if (column.render) return column.render(row, globalIndex);
5175
5177
  return row === null || row === void 0 ? void 0 : row[column.key];
@@ -16576,7 +16578,7 @@ function _objectSpread$h(e) { for (var r = 1; r < arguments.length; r++) { var t
16576
16578
  * - isMobileOpen, setIsMobileOpen
16577
16579
  * - showCollapsedTooltips: boolean (default true)
16578
16580
  */
16579
- var Sidebar = function Sidebar(_ref2) {
16581
+ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
16580
16582
  var _ref2$items = _ref2.items,
16581
16583
  items = _ref2$items === void 0 ? [] : _ref2$items,
16582
16584
  _ref2$collapsed = _ref2.collapsed,
@@ -16819,6 +16821,7 @@ var Sidebar = function Sidebar(_ref2) {
16819
16821
  children: [jsxRuntime.jsx("div", {
16820
16822
  className: "hidden md:flex sticky top-0 h-screen",
16821
16823
  children: jsxRuntime.jsx("div", _objectSpread$h(_objectSpread$h({
16824
+ ref: ref,
16822
16825
  className: cn$1(desktopPlacementClass, className)
16823
16826
  }, props), {}, {
16824
16827
  children: SidebarContent
@@ -16839,7 +16842,8 @@ var Sidebar = function Sidebar(_ref2) {
16839
16842
  children: SidebarContent
16840
16843
  })]
16841
16844
  });
16842
- };
16845
+ });
16846
+ Sidebar.displayName = "Sidebar";
16843
16847
 
16844
16848
  var _excluded$c = ["trigger", "children", "placement", "className"];
16845
16849
  function ownKeys$g(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -16891,7 +16895,7 @@ var Dropdown = function Dropdown(_ref) {
16891
16895
  };
16892
16896
 
16893
16897
  var _excluded$b = ["emitter", "content", "notifications"],
16894
- _excluded2$2 = ["emitter", "logo", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className"];
16898
+ _excluded2$2 = ["emitter", "logo", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen"];
16895
16899
  function ownKeys$f(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
16896
16900
  function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$f(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$f(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
16897
16901
  // Simplified Notifications, uses notifications from props and a single effect for fetch/update
@@ -17038,7 +17042,7 @@ var styledClassNames = {
17038
17042
  icon: "h-6 w-6",
17039
17043
  dropdown: "w-56 rounded-md border border-gray-200 bg-white py-1 shadow-lg"
17040
17044
  };
17041
- var Navbar = function Navbar(_ref3) {
17045
+ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
17042
17046
  var emitter = _ref3.emitter,
17043
17047
  logo = _ref3.logo,
17044
17048
  _ref3$items = _ref3.items,
@@ -17062,7 +17066,10 @@ var Navbar = function Navbar(_ref3) {
17062
17066
  return console.log("invoked onLogoutClick");
17063
17067
  } : _ref3$onLogoutClick,
17064
17068
  className = _ref3.className,
17065
- props = _objectWithoutProperties$1(_ref3, _excluded2$2);
17069
+ onFetch = _ref3.onFetch;
17070
+ _ref3.isMobileOpen;
17071
+ _ref3.setIsMobileOpen;
17072
+ var props = _objectWithoutProperties$1(_ref3, _excluded2$2);
17066
17073
  var _useState3 = React.useState(false),
17067
17074
  _useState4 = _slicedToArray(_useState3, 2),
17068
17075
  isMobileMenuOpen = _useState4[0],
@@ -17131,6 +17138,7 @@ var Navbar = function Navbar(_ref3) {
17131
17138
  }, rest));
17132
17139
  };
17133
17140
  return jsxRuntime.jsxs("nav", _objectSpread$f(_objectSpread$f({
17141
+ ref: ref,
17134
17142
  className: cn$1("bg-white border-b border-gray-200 px-4 sm:px-6 lg:px-8", className)
17135
17143
  }, props), {}, {
17136
17144
  children: [jsxRuntime.jsxs("div", {
@@ -17175,7 +17183,8 @@ var Navbar = function Navbar(_ref3) {
17175
17183
  })]
17176
17184
  })
17177
17185
  }), jsxRuntime.jsx(RightMenuComponent, {
17178
- notifications: notifications
17186
+ notifications: notifications,
17187
+ onFetch: onFetch
17179
17188
  }), !user && jsxRuntime.jsx("button", {
17180
17189
  className: styledClassNames.button,
17181
17190
  onClick: handleLoginClick,
@@ -17267,7 +17276,7 @@ var Navbar = function Navbar(_ref3) {
17267
17276
  })
17268
17277
  })]
17269
17278
  }));
17270
- };
17279
+ });
17271
17280
  Navbar.displayName = "Navbar";
17272
17281
  Navbar.propTypes = {
17273
17282
  emitter: PropTypes.object.isRequired,
@@ -17282,12 +17291,13 @@ Navbar.propTypes = {
17282
17291
  var _excluded$a = ["items", "className"];
17283
17292
  function ownKeys$e(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17284
17293
  function _objectSpread$e(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$e(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$e(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17285
- var FootNav = function FootNav(_ref) {
17294
+ var FootNav = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17286
17295
  var _ref$items = _ref.items,
17287
17296
  items = _ref$items === void 0 ? [] : _ref$items,
17288
17297
  className = _ref.className,
17289
17298
  props = _objectWithoutProperties$1(_ref, _excluded$a);
17290
17299
  return jsxRuntime.jsx("nav", _objectSpread$e(_objectSpread$e({
17300
+ ref: ref,
17291
17301
  className: cn$1('fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-2 md:hidden', className)
17292
17302
  }, props), {}, {
17293
17303
  children: jsxRuntime.jsx("div", {
@@ -17315,12 +17325,13 @@ var FootNav = function FootNav(_ref) {
17315
17325
  })
17316
17326
  })
17317
17327
  }));
17318
- };
17328
+ });
17329
+ FootNav.displayName = 'FootNav';
17319
17330
 
17320
17331
  var _excluded$9 = ["items", "separator", "showHome", "homeIcon", "onHomeClick", "className"];
17321
17332
  function ownKeys$d(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17322
17333
  function _objectSpread$d(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$d(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$d(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17323
- var Breadcrumbs = function Breadcrumbs(_ref) {
17334
+ var Breadcrumbs = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17324
17335
  var _ref$items = _ref.items,
17325
17336
  items = _ref$items === void 0 ? [] : _ref$items,
17326
17337
  _ref$separator = _ref.separator,
@@ -17344,6 +17355,7 @@ var Breadcrumbs = function Breadcrumbs(_ref) {
17344
17355
  onClick: onHomeClick
17345
17356
  }].concat(_toConsumableArray$1(items)) : items;
17346
17357
  return jsxRuntime.jsx("nav", _objectSpread$d(_objectSpread$d({
17358
+ ref: ref,
17347
17359
  className: cn$1('flex items-center space-x-1 text-sm', className),
17348
17360
  "aria-label": "Breadcrumb"
17349
17361
  }, props), {}, {
@@ -17377,7 +17389,8 @@ var Breadcrumbs = function Breadcrumbs(_ref) {
17377
17389
  }, item.id);
17378
17390
  })
17379
17391
  }));
17380
- };
17392
+ });
17393
+ Breadcrumbs.displayName = 'Breadcrumbs';
17381
17394
 
17382
17395
  var _excluded$8 = ["isOpen", "onClose", "title", "children", "size", "dismissible", "showCloseButton", "footer", "className", "onOpen"],
17383
17396
  _excluded2$1 = ["children", "className"],
@@ -17393,7 +17406,19 @@ var getFocusable = function getFocusable(root) {
17393
17406
  return el.getAttribute('aria-hidden') !== 'true';
17394
17407
  }) : [];
17395
17408
  };
17396
- var Dialog = function Dialog(_ref) {
17409
+ // Assign one node to several refs (callback or object). Lets the dialog keep
17410
+ // its internal `dialogRef` for the focus trap while still exposing the panel
17411
+ // node to a consumer-supplied `ref` (issue #56).
17412
+ var setRefs = function setRefs(node) {
17413
+ for (var _len = arguments.length, refs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
17414
+ refs[_key - 1] = arguments[_key];
17415
+ }
17416
+ refs.forEach(function (ref) {
17417
+ if (!ref) return;
17418
+ if (typeof ref === 'function') ref(node);else ref.current = node;
17419
+ });
17420
+ };
17421
+ var Dialog = /*#__PURE__*/React.forwardRef(function (_ref, _ref3) {
17397
17422
  var isOpen = _ref.isOpen,
17398
17423
  onClose = _ref.onClose,
17399
17424
  title = _ref.title,
@@ -17484,7 +17509,9 @@ var Dialog = function Dialog(_ref) {
17484
17509
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4",
17485
17510
  onClick: handleBackdropClick,
17486
17511
  children: jsxRuntime.jsxs("div", _objectSpread$c(_objectSpread$c({
17487
- ref: dialogRef,
17512
+ ref: function ref(node) {
17513
+ return setRefs(node, dialogRef, _ref3);
17514
+ },
17488
17515
  className: cn$1('w-full rounded-lg bg-white shadow-xl animate-scale-in motion-reduce:animate-none', sizeClasses[size], className),
17489
17516
  tabIndex: -1,
17490
17517
  role: "dialog",
@@ -17515,32 +17542,33 @@ var Dialog = function Dialog(_ref) {
17515
17542
  })]
17516
17543
  }))
17517
17544
  }), document.body);
17518
- };
17545
+ });
17546
+ Dialog.displayName = 'Dialog';
17519
17547
  // Dialog components for composition
17520
- Dialog.Header = function (_ref3) {
17521
- var children = _ref3.children,
17522
- className = _ref3.className,
17523
- props = _objectWithoutProperties$1(_ref3, _excluded2$1);
17548
+ Dialog.Header = function (_ref4) {
17549
+ var children = _ref4.children,
17550
+ className = _ref4.className,
17551
+ props = _objectWithoutProperties$1(_ref4, _excluded2$1);
17524
17552
  return jsxRuntime.jsx("div", _objectSpread$c(_objectSpread$c({
17525
17553
  className: cn$1('border-b border-gray-200 px-6 py-4', className)
17526
17554
  }, props), {}, {
17527
17555
  children: children
17528
17556
  }));
17529
17557
  };
17530
- Dialog.Body = function (_ref4) {
17531
- var children = _ref4.children,
17532
- className = _ref4.className,
17533
- props = _objectWithoutProperties$1(_ref4, _excluded3$1);
17558
+ Dialog.Body = function (_ref5) {
17559
+ var children = _ref5.children,
17560
+ className = _ref5.className,
17561
+ props = _objectWithoutProperties$1(_ref5, _excluded3$1);
17534
17562
  return jsxRuntime.jsx("div", _objectSpread$c(_objectSpread$c({
17535
17563
  className: cn$1('px-6 py-4', className)
17536
17564
  }, props), {}, {
17537
17565
  children: children
17538
17566
  }));
17539
17567
  };
17540
- Dialog.Footer = function (_ref5) {
17541
- var children = _ref5.children,
17542
- className = _ref5.className,
17543
- props = _objectWithoutProperties$1(_ref5, _excluded4$1);
17568
+ Dialog.Footer = function (_ref6) {
17569
+ var children = _ref6.children,
17570
+ className = _ref6.className,
17571
+ props = _objectWithoutProperties$1(_ref6, _excluded4$1);
17544
17572
  return jsxRuntime.jsx("div", _objectSpread$c(_objectSpread$c({
17545
17573
  className: cn$1('flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4', className)
17546
17574
  }, props), {}, {
@@ -17551,7 +17579,7 @@ Dialog.Footer = function (_ref5) {
17551
17579
  var _excluded$7 = ["id", "title", "message", "type", "duration", "onClose", "position"];
17552
17580
  function ownKeys$b(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17553
17581
  function _objectSpread$b(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$b(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$b(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17554
- var Toast = function Toast(_ref) {
17582
+ var Toast = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17555
17583
  var id = _ref.id,
17556
17584
  title = _ref.title,
17557
17585
  message = _ref.message,
@@ -17607,6 +17635,7 @@ var Toast = function Toast(_ref) {
17607
17635
  };
17608
17636
  if (!isVisible) return null;
17609
17637
  return /*#__PURE__*/ReactDOM.createPortal(jsxRuntime.jsx("div", _objectSpread$b(_objectSpread$b({
17638
+ ref: ref,
17610
17639
  className: cn$1('fixed z-50 max-w-sm rounded-lg border border-gray-200 bg-white p-4 shadow-lg animate-slide-up', positionClasses[position])
17611
17640
  }, props), {}, {
17612
17641
  children: jsxRuntime.jsxs("div", {
@@ -17633,7 +17662,8 @@ var Toast = function Toast(_ref) {
17633
17662
  })]
17634
17663
  })
17635
17664
  })), document.body);
17636
- };
17665
+ });
17666
+ Toast.displayName = 'Toast';
17637
17667
  // Toast Container Component
17638
17668
  var ToastContainer = function ToastContainer(_ref2) {
17639
17669
  var _ref2$toasts = _ref2.toasts,
@@ -17713,7 +17743,7 @@ var useToast = function useToast() {
17713
17743
  var _excluded$6 = ["variant", "title", "children", "dismissible", "onDismiss", "className"];
17714
17744
  function ownKeys$a(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17715
17745
  function _objectSpread$a(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$a(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$a(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17716
- var Alert = function Alert(_ref) {
17746
+ var Alert = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17717
17747
  var _ref$variant = _ref.variant,
17718
17748
  variant = _ref$variant === void 0 ? 'info' : _ref$variant,
17719
17749
  title = _ref.title,
@@ -17759,6 +17789,7 @@ var Alert = function Alert(_ref) {
17759
17789
  };
17760
17790
  var variantStyles = variants[variant];
17761
17791
  return jsxRuntime.jsx("div", _objectSpread$a(_objectSpread$a({
17792
+ ref: ref,
17762
17793
  className: cn$1('rounded-md border p-4', variantStyles.container, className),
17763
17794
  role: "alert"
17764
17795
  }, props), {}, {
@@ -17796,12 +17827,13 @@ var Alert = function Alert(_ref) {
17796
17827
  })]
17797
17828
  })
17798
17829
  }));
17799
- };
17830
+ });
17831
+ Alert.displayName = 'Alert';
17800
17832
 
17801
17833
  var _excluded$5 = ["children", "variant", "size", "rounded", "className"];
17802
17834
  function ownKeys$9(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17803
17835
  function _objectSpread$9(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$9(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$9(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17804
- var Badge = function Badge(_ref) {
17836
+ var Badge = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17805
17837
  var children = _ref.children,
17806
17838
  _ref$variant = _ref.variant,
17807
17839
  variant = _ref$variant === void 0 ? 'default' : _ref$variant,
@@ -17826,6 +17858,7 @@ var Badge = function Badge(_ref) {
17826
17858
  lg: 'px-3 py-1 text-base'
17827
17859
  };
17828
17860
  return jsxRuntime.jsx("span", _objectSpread$9(_objectSpread$9({
17861
+ ref: ref,
17829
17862
  className: cn$1('inline-flex items-center font-medium', variants[variant], sizes[size], {
17830
17863
  'rounded-full': rounded,
17831
17864
  'rounded-md': !rounded
@@ -17833,12 +17866,13 @@ var Badge = function Badge(_ref) {
17833
17866
  }, props), {}, {
17834
17867
  children: children
17835
17868
  }));
17836
- };
17869
+ });
17870
+ Badge.displayName = 'Badge';
17837
17871
 
17838
17872
  var _excluded$4 = ["src", "alt", "name", "size", "shape", "status", "className"];
17839
17873
  function ownKeys$8(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17840
17874
  function _objectSpread$8(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$8(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$8(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17841
- var Avatar = function Avatar(_ref) {
17875
+ var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17842
17876
  var src = _ref.src,
17843
17877
  alt = _ref.alt,
17844
17878
  name = _ref.name,
@@ -17878,6 +17912,7 @@ var Avatar = function Avatar(_ref) {
17878
17912
  '2xl': 'h-5 w-5'
17879
17913
  };
17880
17914
  return jsxRuntime.jsxs("div", {
17915
+ ref: ref,
17881
17916
  className: "relative inline-block",
17882
17917
  children: [jsxRuntime.jsxs("div", _objectSpread$8(_objectSpread$8({
17883
17918
  className: cn$1('flex items-center justify-center bg-gray-100 text-primary-600 font-medium', sizes[size], {
@@ -17914,7 +17949,8 @@ var Avatar = function Avatar(_ref) {
17914
17949
  className: cn$1('absolute bottom-0 right-0 rounded-full border-2 border-white', statusColors[status], statusSizes[size])
17915
17950
  })]
17916
17951
  });
17917
- };
17952
+ });
17953
+ Avatar.displayName = 'Avatar';
17918
17954
 
17919
17955
  var _excluded$3 = ["children", "className", "hover"],
17920
17956
  _excluded2 = ["children", "className"],
@@ -17924,20 +17960,22 @@ var _excluded$3 = ["children", "className", "hover"],
17924
17960
  _excluded6 = ["children", "className"];
17925
17961
  function ownKeys$7(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17926
17962
  function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$7(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17927
- var Card = function Card(_ref) {
17963
+ var Card = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
17928
17964
  var children = _ref.children,
17929
17965
  className = _ref.className,
17930
17966
  _ref$hover = _ref.hover,
17931
17967
  hover = _ref$hover === void 0 ? false : _ref$hover,
17932
17968
  props = _objectWithoutProperties$1(_ref, _excluded$3);
17933
17969
  return jsxRuntime.jsx("div", _objectSpread$7(_objectSpread$7({
17970
+ ref: ref,
17934
17971
  className: cn$1('rounded-lg border border-gray-200 bg-white shadow-sm', {
17935
17972
  'hover:shadow-md transition-shadow': hover
17936
17973
  }, className)
17937
17974
  }, props), {}, {
17938
17975
  children: children
17939
17976
  }));
17940
- };
17977
+ });
17978
+ Card.displayName = 'Card';
17941
17979
  var CardHeader = function CardHeader(_ref2) {
17942
17980
  var children = _ref2.children,
17943
17981
  className = _ref2.className,
@@ -17997,7 +18035,7 @@ Card.Footer = CardFooter;
17997
18035
  var _excluded$2 = ["currentPage", "totalPages", "onPageChange", "showFirstLast", "showPrevNext", "maxVisiblePages", "className"];
17998
18036
  function ownKeys$6(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17999
18037
  function _objectSpread$6(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$6(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18000
- var Pagination = function Pagination(_ref) {
18038
+ var Pagination = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
18001
18039
  var _ref$currentPage = _ref.currentPage,
18002
18040
  currentPage = _ref$currentPage === void 0 ? 1 : _ref$currentPage,
18003
18041
  _ref$totalPages = _ref.totalPages,
@@ -18037,6 +18075,7 @@ var Pagination = function Pagination(_ref) {
18037
18075
  };
18038
18076
  if (totalPages <= 1) return null;
18039
18077
  return jsxRuntime.jsxs("nav", _objectSpread$6(_objectSpread$6({
18078
+ ref: ref,
18040
18079
  className: cn$1('flex items-center justify-center space-x-1', className),
18041
18080
  "aria-label": "Pagination"
18042
18081
  }, props), {}, {
@@ -18095,12 +18134,13 @@ var Pagination = function Pagination(_ref) {
18095
18134
  children: totalPages
18096
18135
  })]
18097
18136
  }));
18098
- };
18137
+ });
18138
+ Pagination.displayName = 'Pagination';
18099
18139
 
18100
18140
  var _excluded$1 = ["steps", "currentStep", "orientation", "variant", "onStepClick", "className"];
18101
18141
  function ownKeys$5(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18102
18142
  function _objectSpread$5(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$5(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$5(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18103
- var Stepper = function Stepper(_ref) {
18143
+ var Stepper = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
18104
18144
  var _ref$steps = _ref.steps,
18105
18145
  steps = _ref$steps === void 0 ? [] : _ref$steps,
18106
18146
  _ref$currentStep = _ref.currentStep,
@@ -18134,6 +18174,7 @@ var Stepper = function Stepper(_ref) {
18134
18174
  }
18135
18175
  };
18136
18176
  return jsxRuntime.jsx("nav", _objectSpread$5(_objectSpread$5({
18177
+ ref: ref,
18137
18178
  className: cn$1('flex', {
18138
18179
  'flex-col': orientation === 'vertical',
18139
18180
  'flex-row': orientation === 'horizontal'
@@ -18188,12 +18229,13 @@ var Stepper = function Stepper(_ref) {
18188
18229
  }, step.id || stepIndex);
18189
18230
  })
18190
18231
  }));
18191
- };
18232
+ });
18233
+ Stepper.displayName = 'Stepper';
18192
18234
 
18193
18235
  var _excluded = ["accept", "multiple", "maxSize", "onFileSelect", "onFileRemove", "files", "disabled", "className"];
18194
18236
  function ownKeys$4(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18195
18237
  function _objectSpread$4(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$4(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$4(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18196
- var FileUpload = function FileUpload(_ref) {
18238
+ var FileUpload = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
18197
18239
  var accept = _ref.accept,
18198
18240
  _ref$multiple = _ref.multiple,
18199
18241
  multiple = _ref$multiple === void 0 ? false : _ref$multiple,
@@ -18285,6 +18327,7 @@ var FileUpload = function FileUpload(_ref) {
18285
18327
  }
18286
18328
  };
18287
18329
  return jsxRuntime.jsxs("div", _objectSpread$4(_objectSpread$4({
18330
+ ref: ref,
18288
18331
  className: cn$1('w-full', className)
18289
18332
  }, props), {}, {
18290
18333
  children: [jsxRuntime.jsxs("div", {
@@ -18357,7 +18400,8 @@ var FileUpload = function FileUpload(_ref) {
18357
18400
  })
18358
18401
  })]
18359
18402
  }));
18360
- };
18403
+ });
18404
+ FileUpload.displayName = 'FileUpload';
18361
18405
 
18362
18406
  var Condition = function Condition(_ref) {
18363
18407
  var condition = _ref.condition,
@@ -18367,7 +18411,7 @@ var Condition = function Condition(_ref) {
18367
18411
  return condition ? children : fallback;
18368
18412
  };
18369
18413
 
18370
- function Carousel(props) {
18414
+ var Carousel = /*#__PURE__*/React.forwardRef(function Carousel(props, ref) {
18371
18415
  var children = props.children,
18372
18416
  _props$autoPlay = props.autoPlay,
18373
18417
  autoPlay = _props$autoPlay === void 0 ? false : _props$autoPlay,
@@ -18407,6 +18451,7 @@ function Carousel(props) {
18407
18451
  }, [autoPlay, isPaused, next, interval]);
18408
18452
  var childrenArray = React.Children.toArray(children);
18409
18453
  return jsxRuntime.jsxs("div", {
18454
+ ref: ref,
18410
18455
  className: cn$1("relative group overflow-hidden rounded-xl bg-card border border-border/50 shadow-sm", className),
18411
18456
  onMouseEnter: function onMouseEnter() {
18412
18457
  return setIsPaused(true);
@@ -18452,7 +18497,8 @@ function Carousel(props) {
18452
18497
  })
18453
18498
  })]
18454
18499
  });
18455
- }
18500
+ });
18501
+ Carousel.displayName = "Carousel";
18456
18502
 
18457
18503
  var ThemeContext = /*#__PURE__*/React.createContext(undefined);
18458
18504
  var useTheme = function useTheme() {
@@ -538,6 +538,12 @@
538
538
  "default": "",
539
539
  "description": "Controlled page"
540
540
  },
541
+ {
542
+ "prop": "onPageChange",
543
+ "type": "`(page: number) => void`",
544
+ "default": "",
545
+ "description": "Called with the new page number when the page changes. Consumed by the table — it is **not** forwarded onto the `<table>`."
546
+ },
541
547
  {
542
548
  "prop": "responsiveBreakpoint",
543
549
  "type": "`number`",
@@ -2396,6 +2402,12 @@
2396
2402
  "default": "",
2397
2403
  "description": "Called when logout button is clicked."
2398
2404
  },
2405
+ {
2406
+ "prop": "onFetch",
2407
+ "type": "`({ setNotifications }) => void`",
2408
+ "default": "",
2409
+ "description": "Refresh handler for the default notifications dropdown. Called on mount and when `notifications` changes. Consumed by the right menu — it is **not** forwarded onto `<nav>`."
2410
+ },
2399
2411
  {
2400
2412
  "prop": "className",
2401
2413
  "type": "`string`",
@@ -2406,7 +2418,7 @@
2406
2418
  "prop": "...rest",
2407
2419
  "type": "—",
2408
2420
  "default": "",
2409
- "description": "Passed to `<nav>` and to default right menu (e.g. `onFetch({ setNotifications })` for loading notifications)."
2421
+ "description": "Only DOM-valid attributes (e.g. `id`, `aria-*`, `data-*`, event handlers) are forwarded to the root `<nav>`. The component's own control props (`isMobileOpen`, `setIsMobileOpen`, `onFetch`, ) are consumed and never leak to the DOM."
2410
2422
  }
2411
2423
  ],
2412
2424
  "examples": "```jsx\nimport { Navbar } from '@dreamtree-org/twreact-ui';\nimport MyEmitter from './emitter';\n\n<Navbar\n emitter={MyEmitter}\n logo={<a href=\"/\"><img src=\"/logo.svg\" alt=\"Home\" /></a>}\n items={[\n { id: '1', label: 'Home', href: '/', active: pathname === '/' },\n { id: '2', label: 'About', href: '/about' },\n { id: '3', label: 'Settings', onClick: () => openSettings() },\n ]}\n user={user}\n notifications={notifications}\n searchable\n onSearch={(term) => doSearch(term)}\n onLoginClick={() => navigate('/login')}\n onLogoutClick={logout}\n onFetch={async ({ setNotifications }) => {\n const res = await fetch('/api/notifications');\n const data = await res.json();\n setNotifications(data.items);\n }}\n/>\n```\n\n[← Component overview](README.md)"
@@ -3136,7 +3148,7 @@
3136
3148
  "Input": "# Input\n\nText input with optional label, error/success states, clear button, character count, and password visibility toggle.\n\n## Import\n\n```jsx\nimport { Input } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `id` | `string` | — | Input id (auto-generated if not set) |\n| `className` | `string` | — | Extra CSS classes |\n| `type` | `string` | `\"text\"` | `text`, `search`, `password`, etc. |\n| `label` | `string` | — | Label text |\n| `placeholder` | `string` | — | Placeholder |\n| `error` | `string` | — | Error message (shows error state) |\n| `success` | `boolean` | — | Success state |\n| `disabled` | `boolean` | `false` | Disable input |\n| `required` | `boolean` | `false` | Required field |\n| `clearable` | `boolean` | `false` | Show clear button when has value |\n| `icon` | `ReactNode` | — | Left or right icon |\n| `iconPosition` | `\"left\"` \\| `\"right\"` | `\"left\"` | Icon position |\n| `onClear` | `function` | — | Called when clear is clicked |\n| `showCount` | `boolean` | `false` | Show character count |\n| `maxLength` | `number` | — | Max length (used with showCount) |\n| `readOnly` | `boolean` | `false` | Read-only |\n| `value` | `string` | — | Controlled value |\n| `defaultValue` | `string` | — | Uncontrolled default |\n| `onChange` | `function` | — | Change handler |\n| ...rest | — | — | Passed to native `<input>` |\n\n## Examples\n\n### Basic\n\n```jsx\n<Input label=\"Email\" placeholder=\"you@example.com\" />\n```\n\n### With error\n\n```jsx\n<Input label=\"Email\" error=\"Invalid email address\" />\n```\n\n### Password with toggle\n\n```jsx\n<Input type=\"password\" label=\"Password\" placeholder=\"Enter password\" />\n```\n\n### Clearable and character count\n\n```jsx\n<Input\n label=\"Bio\"\n clearable\n showCount\n maxLength={200}\n placeholder=\"Tell us about yourself\"\n/>\n```\n\n[← Component overview](README.md)\n",
3137
3149
  "Loader": "# Loader\n\nLoading indicator in three variants: spinner (default), dots, or bar. Configurable size, speed, colors, and optional label text.\n\n## Import\n\n```jsx\nimport { Loader } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `number` | `\"md\"` | Size: sm=14px, md=20px, lg=36px, or numeric px. |\n| `speed` | `number` | `0.9` | Animation duration in seconds. |\n| `thickness` | `number` | `2.5` | Stroke thickness (spinner). |\n| `color` | `string` | `\"currentColor\"` | Main color (spinner/dots/bar). |\n| `secondaryColor` | `string` | `\"rgba(0,0,0,0.08)\"` | Track/background color. |\n| `variant` | `\"spinner\"` \\| `\"dots\"` \\| `\"bar\"` | `\"spinner\"` | Visual style. |\n| `className` | `string` | `\"\"` | Wrapper CSS classes. |\n| `inline` | `boolean` | `false` | If true, wrapper is inline-flex. |\n| `ariaLabel` | `string` | `\"Loading\"` | Accessibility label. |\n| `text` | `string` | — | Optional label shown next to loader. |\n| `reverse` | `boolean` | `false` | Reverse spinner rotation direction. |\n| `style` | `object` | — | Inline style for wrapper. |\n\n## Examples\n\n```jsx\n<Loader />\n<Loader variant=\"dots\" size=\"sm\" />\n<Loader variant=\"bar\" text=\"Loading...\" />\n<Loader size={32} color=\"#2563eb\" />\n```\n\n[← Component overview](README.md)\n",
3138
3150
  "LocationPicker": "# LocationPicker\n\nInput for latitude/longitude. User can type `lat, lng` (e.g. `12.34, 56.78`) or click the icon to use browser geolocation. Value is `{ lat, lng }` or `null`.\n\n## Import\n\n```jsx\nimport { LocationPicker } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `value` | `{ lat: number, lng: number }` \\| `null` | `null` | Current coordinates. |\n| `onChange` | `(coords: { lat, lng } \\| null) => void` | — | Called when value changes (typed or from geolocation). |\n| `inputProps` | `object` | `{}` | Props spread to the underlying input (e.g. `placeholder`). A supplied `inputProps.onChange` is forwarded **in addition to** (not instead of) the component's coord-parsing handler — both fire. `inputProps.className` is merged via `cn()`. |\n| `className` | `string` | — | Classes merged (via `cn()`) onto the root wrapper. |\n| `icon` | `ReactNode` | default pin SVG | Icon for \"use my location\" button. |\n| `iconProps` | `object` | `{}` | Props for the icon button (e.g. `className`, `onClick`). |\n| `iconPosition` | `\"left\"` \\| `\"right\"` | `\"right\"` | Position of the icon button. |\n| `placeholder` | `string` | `\"lat, lng\"` | Input placeholder. |\n\n## Behavior\n\n- Display format is `lat.toFixed(6), lng.toFixed(6)`.\n- Typing a valid \"lat, lng\" string calls `onChange` with `{ lat, lng }` (e.g.\n typing `\"1.5, 2.5\"` calls `onChange({ lat: 1.5, lng: 2.5 })`). A\n consumer-supplied `inputProps.onChange` still fires alongside it.\n- Clearing the input calls `onChange(null)`.\n- Clicking the icon calls `navigator.geolocation.getCurrentPosition` and passes the result to `onChange`. Requires HTTPS in production.\n- Forwards `ref` to the underlying `<input>` and spreads unknown props (`...rest`) onto the root wrapper.\n\n## Example\n\n```jsx\nconst [location, setLocation] = useState(null);\n<LocationPicker\n value={location}\n onChange={setLocation}\n placeholder=\"Enter lat, lng or use location\"\n/>\n```\n\n[← Component overview](README.md)\n",
3139
- "Navbar": "# Navbar\n\nTop navigation bar with logo, nav items (links or buttons), optional search, notifications dropdown, and login/logout. Uses an **emitter** for notification actions (view, markAsRead, markAsUnread, clearAll, delete). Responsive: left icon and hamburger on mobile; desktop nav and search. You can replace the right area with a custom component via `rightMenuContent`.\n\n## Import\n\n```jsx\nimport { Navbar } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `emitter` | `object` | **required** | Event emitter for notifications (e.g. `notification:view`, `notification:markAsRead`, etc.). |\n| `logo` | `ReactNode` | — | Logo (e.g. image or link). |\n| `items` | `Array` | `[]` | Nav items: `{ id, label, href?, active?, onClick?(item) }`. If `href` is set, renders `<a>`; else `<button>` with `onClick`. |\n| `user` | `object` \\| `null` | — | If set, shows logout button; if null/undefined, shows login button. |\n| `notifications` | `Array` | `[]` | List of notifications for the dropdown. Each: `{ id, title, message?, read? }`. |\n| `searchable` | `boolean` | `false` | Show search input (desktop). |\n| `onSearch` | `(term: string) => void` | — | Called on search form submit with current search term. |\n| `leftIcon` | `ReactNode` \\| `false` | `<ChevronLeft />` | Icon shown on mobile (e.g. back). Set `false` to hide. |\n| `onLeftIconClick` | `() => void` | — | Called when left icon (mobile) is clicked. |\n| `rightMenuContent` | `(props) => ReactNode` | — | Custom right menu. Receives `{ notifications }` and any Navbar `...props` (e.g. `emitter`, `onFetch`). If not provided, default renders notifications dropdown. |\n| `onLoginClick` | `() => void` | — | Called when login button is clicked. |\n| `onLogoutClick` | `() => void` | — | Called when logout button is clicked. |\n| `className` | `string` | — | Wrapper CSS classes. |\n| ...rest | — | — | Passed to `<nav>` and to default right menu (e.g. `onFetch({ setNotifications })` for loading notifications). |\n\n## Item shape (items)\n\n- `id`: string or number (key).\n- `label`: string.\n- `href`: optional; if set, item is an `<a href={href}>`.\n- `active`: optional boolean; applies primary styling.\n- `onClick(item)`: optional; used when no `href` (button click).\n\n## Notification shape (notifications)\n\n- `id`: string or number.\n- `title`: string.\n- `message`: optional string.\n- `read`: optional boolean; unread count uses `!n.read`.\n\n## Default notifications dropdown\n\nIf `rightMenuContent` is not provided, the right menu shows a bell icon and dropdown with:\n\n- Unread count badge.\n- \"Clear all\" that clears the list and calls emitter `notification:clearAll`.\n- Per notification: title, message, \"Mark as Read\" / \"Mark as Unread\", \"Delete\" (emitter events).\n- Clicking a notification calls `emitter.emit('notification:view', [n])`.\n\nTo refresh the list from the server, pass `onFetch({ setNotifications })`; the default dropdown uses it on mount and when `notifications` prop changes.\n\n## Example\n\n```jsx\nimport { Navbar } from '@dreamtree-org/twreact-ui';\nimport MyEmitter from './emitter';\n\n<Navbar\n emitter={MyEmitter}\n logo={<a href=\"/\"><img src=\"/logo.svg\" alt=\"Home\" /></a>}\n items={[\n { id: '1', label: 'Home', href: '/', active: pathname === '/' },\n { id: '2', label: 'About', href: '/about' },\n { id: '3', label: 'Settings', onClick: () => openSettings() },\n ]}\n user={user}\n notifications={notifications}\n searchable\n onSearch={(term) => doSearch(term)}\n onLoginClick={() => navigate('/login')}\n onLogoutClick={logout}\n onFetch={async ({ setNotifications }) => {\n const res = await fetch('/api/notifications');\n const data = await res.json();\n setNotifications(data.items);\n }}\n/>\n```\n\n[← Component overview](README.md)\n",
3151
+ "Navbar": "# Navbar\n\nTop navigation bar with logo, nav items (links or buttons), optional search, notifications dropdown, and login/logout. Uses an **emitter** for notification actions (view, markAsRead, markAsUnread, clearAll, delete). Responsive: left icon and hamburger on mobile; desktop nav and search. You can replace the right area with a custom component via `rightMenuContent`.\n\n## Import\n\n```jsx\nimport { Navbar } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `emitter` | `object` | **required** | Event emitter for notifications (e.g. `notification:view`, `notification:markAsRead`, etc.). |\n| `logo` | `ReactNode` | — | Logo (e.g. image or link). |\n| `items` | `Array` | `[]` | Nav items: `{ id, label, href?, active?, onClick?(item) }`. If `href` is set, renders `<a>`; else `<button>` with `onClick`. |\n| `user` | `object` \\| `null` | — | If set, shows logout button; if null/undefined, shows login button. |\n| `notifications` | `Array` | `[]` | List of notifications for the dropdown. Each: `{ id, title, message?, read? }`. |\n| `searchable` | `boolean` | `false` | Show search input (desktop). |\n| `onSearch` | `(term: string) => void` | — | Called on search form submit with current search term. |\n| `leftIcon` | `ReactNode` \\| `false` | `<ChevronLeft />` | Icon shown on mobile (e.g. back). Set `false` to hide. |\n| `onLeftIconClick` | `() => void` | — | Called when left icon (mobile) is clicked. |\n| `rightMenuContent` | `(props) => ReactNode` | — | Custom right menu. Receives `{ notifications }` and any Navbar `...props` (e.g. `emitter`, `onFetch`). If not provided, default renders notifications dropdown. |\n| `onLoginClick` | `() => void` | — | Called when login button is clicked. |\n| `onLogoutClick` | `() => void` | — | Called when logout button is clicked. |\n| `onFetch` | `({ setNotifications }) => void` | — | Refresh handler for the default notifications dropdown. Called on mount and when `notifications` changes. Consumed by the right menu — it is **not** forwarded onto `<nav>`. |\n| `className` | `string` | — | Wrapper CSS classes. |\n| ...rest | — | — | Only DOM-valid attributes (e.g. `id`, `aria-*`, `data-*`, event handlers) are forwarded to the root `<nav>`. The component's own control props (`isMobileOpen`, `setIsMobileOpen`, `onFetch`, ) are consumed and never leak to the DOM. |\n\n`Navbar` forwards `ref` to its root `<nav>` element.\n\n## Item shape (items)\n\n- `id`: string or number (key).\n- `label`: string.\n- `href`: optional; if set, item is an `<a href={href}>`.\n- `active`: optional boolean; applies primary styling.\n- `onClick(item)`: optional; used when no `href` (button click).\n\n## Notification shape (notifications)\n\n- `id`: string or number.\n- `title`: string.\n- `message`: optional string.\n- `read`: optional boolean; unread count uses `!n.read`.\n\n## Default notifications dropdown\n\nIf `rightMenuContent` is not provided, the right menu shows a bell icon and dropdown with:\n\n- Unread count badge.\n- \"Clear all\" that clears the list and calls emitter `notification:clearAll`.\n- Per notification: title, message, \"Mark as Read\" / \"Mark as Unread\", \"Delete\" (emitter events).\n- Clicking a notification calls `emitter.emit('notification:view', [n])`.\n\nTo refresh the list from the server, pass `onFetch({ setNotifications })`; the default dropdown uses it on mount and when `notifications` prop changes.\n\n## Example\n\n```jsx\nimport { Navbar } from '@dreamtree-org/twreact-ui';\nimport MyEmitter from './emitter';\n\n<Navbar\n emitter={MyEmitter}\n logo={<a href=\"/\"><img src=\"/logo.svg\" alt=\"Home\" /></a>}\n items={[\n { id: '1', label: 'Home', href: '/', active: pathname === '/' },\n { id: '2', label: 'About', href: '/about' },\n { id: '3', label: 'Settings', onClick: () => openSettings() },\n ]}\n user={user}\n notifications={notifications}\n searchable\n onSearch={(term) => doSearch(term)}\n onLoginClick={() => navigate('/login')}\n onLogoutClick={logout}\n onFetch={async ({ setNotifications }) => {\n const res = await fetch('/api/notifications');\n const data = await res.json();\n setNotifications(data.items);\n }}\n/>\n```\n\n[← Component overview](README.md)\n",
3140
3152
  "Pagination": "# Pagination\n\nPage navigation: first, previous, page numbers, next, last. Renders only when `totalPages > 1`. Optional `theme` for styling (e.g. from Table).\n\n## Import\n\n```jsx\nimport { Pagination } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `currentPage` | `number` | `1` | Current page (1-based). |\n| `totalPages` | `number` | `1` | Total pages. If ≤ 1, component returns null. |\n| `onPageChange` | `(page: number) => void` | — | Called when user selects a page. |\n| `showFirstLast` | `boolean` | `true` | Show first/last page buttons. |\n| `showPrevNext` | `boolean` | `true` | Show previous/next buttons. |\n| `maxVisiblePages` | `number` | `5` | Max page number buttons to show. |\n| `className` | `string` | — | Nav wrapper CSS classes. |\n| ...rest | — | — | Passed to `<nav>`. |\n\n## Example\n\n```jsx\n<Pagination\n currentPage={page}\n totalPages={Math.ceil(total / pageSize)}\n onPageChange={setPage}\n maxVisiblePages={5}\n/>\n```\n\n[← Component overview](README.md)\n",
3141
3153
  "PriceRangePicker": "# PriceRangePicker\n\nDual-thumb range slider for min/max values (e.g. price or any number). Optional number inputs and preset buttons. Controlled via `value` or uncontrolled via `defaultValue`.\n\n## Import\n\n```jsx\nimport { PriceRangePicker } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `min` | `number` | `0` | Minimum value. |\n| `max` | `number` | `1000` | Maximum value. |\n| `step` | `number` | `1` | Step for thumbs and inputs. |\n| `minGap` | `number` | `5` | Minimum gap between min and max. |\n| `value` | `{ min, max }` \\| `null` | `null` | Controlled value. |\n| `defaultValue` | `{ min, max }` | `{ min: 0, max: 1000 }` | Uncontrolled initial value. |\n| `onChange` | `(value: { min, max }) => void` | `() => {}` | Called on thumb/input change. |\n| `onFinalChange` | `(value: { min, max }) => void` | `() => {}` | Called on mouseup/touchend or Enter in inputs. |\n| `showInputs` | `boolean` | `true` | Show min/max number inputs. |\n| `showTooltips` | `boolean` | `true` | Show tooltips on thumbs. |\n| `disabled` | `boolean` | `false` | Disable the control. |\n| `presets` | `Array<{ id, label, value: { min, max } }>` | `[]` | Preset buttons. |\n| `formatValue` | `(n: number) => string` | `(n) => String(n)` | Format display (e.g. currency). |\n| `className` | `string` | `\"\"` | Container CSS classes. |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `\"md\"` | Thumb and spacing size. |\n| `colorClass` | `string` | `\"bg-pink-500\"` | Tailwind class for active track/thumb. |\n| `ariaLabel` | `string` | `\"Price range\"` | Accessibility label. |\n\n## Example\n\n```jsx\nconst [range, setRange] = useState({ min: 100, max: 500 });\n<PriceRangePicker\n min={0}\n max={1000}\n value={range}\n onChange={setRange}\n formatValue={(n) => `$${n}`}\n presets={[\n { id: '1', label: 'Under $200', value: { min: 0, max: 200 } },\n ]}\n/>\n```\n\n[← Component overview](README.md)\n",
3142
3154
  "ProgressBar": "# ProgressBar\n\nProgress bar showing a value between 0 and max. Supports custom HEX colors, optional label, value text inside the bar, striped and animated styles.\n\n## Import\n\n```jsx\nimport { ProgressBar } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `value` | `number` | `0` | Current value. |\n| `max` | `number` | `100` | Maximum value. |\n| `size` | `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `number` | `\"md\"` | Height: xs/sm/md/lg or px. |\n| `showValue` | `boolean` | `false` | Show percentage text inside the fill. |\n| `rounded` | `boolean` | `true` | Rounded corners. |\n| `color` | `string` (HEX) | `\"#2563eb\"` | Fill color (HEX only). |\n| `bgColor` | `string` (HEX) | `\"#e6eefc\"` | Track background (HEX only). |\n| `valueColor` | `string` (HEX) | auto | Text color inside fill; auto from luminance if omitted. |\n| `striped` | `boolean` | `false` | Striped fill pattern. |\n| `animated` | `boolean` | `false` | Animate stripe movement. |\n| `label` | `string` | `\"\"` | Label above the bar. |\n| `ariaLabel` | `string` | `\"Progress\"` | Accessibility label. |\n| `className` | `string` | `\"\"` | Wrapper CSS classes. |\n| `style` | `object` | `{}` | Wrapper inline style. |\n\n## Example\n\n```jsx\n<ProgressBar value={60} max={100} />\n<ProgressBar value={75} showValue label=\"Upload\" color=\"#16a34a\" />\n<ProgressBar value={40} striped animated size=\"lg\" />\n```\n\n[← Component overview](README.md)\n",
@@ -3149,7 +3161,7 @@
3149
3161
  "SpeechToText": "# SpeechToText\n\nVoice-to-text using the Web Speech API. Headless by default — render a custom\ncontrol via `renderButton`, or drive it imperatively through the ref. The\nbuilt-in fallback button is `className`-extensible and forwards arbitrary props.\n\n## Import\n\n```jsx\nimport { SpeechToText } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `lang` | `string` | `\"en-US\"` | Recognition language |\n| `continuous` | `boolean` | `true` | Keep listening until stopped (forced `false` on mobile) |\n| `interimResults` | `boolean` | `true` | Return interim results |\n| `onSpeechComplete` | `function` | — | Final transcript chunk callback `(text) => void` |\n| `onSpeaking` | `function` | — | Interim transcript callback `(text) => void` |\n| `onError` | `function` | — | Fatal error callback `(Error) => void`. Routine events (`no-speech`, `aborted`) are **not** surfaced |\n| `onStart` | `function` | — | Start callback |\n| `onStop` | `function` | — | Stop callback |\n| `renderButton` | `function` | — | Custom control render-prop (see signature below) |\n| `autoStart` | `boolean` | `false` | Start on mount (once, after support is detected) |\n| `disabled` | `boolean` | `false` | Disable |\n| `resetOnStart` | `boolean` | `false` | Clear the accumulated transcript when a new session starts |\n| `className` | `string` | — | Merged (via `cn`) onto the default button |\n| `...rest` | — | — | Forwarded to the default `<button>` |\n\nThe default button is keyboard-accessible (`aria-pressed`, `aria-label`) and\ntoken-driven. When `renderButton` is supplied, `className`/`...rest` are not\napplied (you own the rendered control).\n\n## `renderButton` signature\n\n```js\nrenderButton({ isListening, isSupported, error, start, stop, toggle, disabled })\n```\n\n## Ref methods\n\n`start()`, `stop()`, `toggle()`, `isListening()`, `isSupported()`,\n`getTranscript()`, `clearTranscript()`, `getError()`.\n\n## Example\n\n```jsx\nconst [transcript, setTranscript] = useState('');\n<SpeechToText\n onSpeechComplete={(chunk) => setTranscript((t) => `${t} ${chunk}`.trim())}\n onError={(e) => console.error(e)}\n/>\n<div>Transcript: {transcript}</div>\n```\n\n[← Component overview](README.md)\n",
3150
3162
  "Stepper": "# Stepper\n\nHorizontal or vertical step indicator. Each step has circle (with check for completed), optional line, and label. Optional `onStepClick` for clickable steps.\n\n## Import\n\n```jsx\nimport { Stepper } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `steps` | `Array` | `[]` | Each step: `{ id?, label?, description? }`. |\n| `currentStep` | `number` | `0` | Zero-based index of current step. |\n| `orientation` | `\"horizontal\"` \\| `\"vertical\"` | `\"horizontal\"` | Layout. |\n| `variant` | `string` | `\"default\"` | Visual variant. |\n| `onStepClick` | `(step, stepIndex) => void` | — | Called when a step is clicked (e.g. for completed/current). |\n| `className` | `string` | — | Nav wrapper CSS classes. |\n| ...rest | — | — | Passed to `<nav>`. |\n\n## Step status\n\n- **completed**: `stepIndex < currentStep` (check icon, primary color).\n- **current**: `stepIndex === currentStep`.\n- **upcoming**: `stepIndex > currentStep` (gray).\n\n## Example\n\n```jsx\n<Stepper\n steps={[\n { id: '1', label: 'Details' },\n { id: '2', label: 'Payment' },\n { id: '3', label: 'Confirm' },\n ]}\n currentStep={1}\n orientation=\"horizontal\"\n onStepClick={(step, idx) => setStep(idx)}\n/>\n```\n\n[← Component overview](README.md)\n",
3151
3163
  "Switch": "# Switch\n\nToggle switch (on/off). Controlled or uncontrolled.\n\n## Import\n\n```jsx\nimport { Switch } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `checked` | `boolean` | — | Controlled checked |\n| `defaultChecked` | `boolean` | `false` | Uncontrolled default |\n| `onChange` | `(checked: boolean) => void` | — | Receives the new boolean state (not a DOM event) |\n| `disabled` | `boolean` | `false` | Disable |\n| `size` | `string` | `\"md\"` | `sm`, `md`, `lg` |\n| `name` | `string` | — | Form name |\n| `topLabel` | `string` | — | Label above |\n| `bottomLabel` | `string` | — | Label below |\n| `leftLabel` | `string` | — | Label left |\n| `rightLabel` | `string` | — | Label right |\n\n## Example\n\n```jsx\n<Switch checked={enabled} onChange={checked => setEnabled(checked)} />\n<Switch defaultChecked rightLabel=\"Enable notifications\" />\n```\n\n[← Component overview](README.md)\n",
3152
- "Table": "# Table\n\nData table with sorting, filtering, pagination, row selection, expandable details, and responsive mobile card view.\n\n## Import\n\n```jsx\nimport { Table } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `data` | `Array` | `[]` | Row data (array of objects) |\n| `columns` | `Array` | `[]` | `[{ key, label, sortable?, isVisible?, render? }]` |\n| `sortable` | `boolean` | `true` | Enable column sort |\n| `filterable` | `boolean` | `false` | Enable column filters |\n| `selectable` | `boolean` | `false` | Row selection checkboxes |\n| `pagination` | `boolean` | `false` | Enable pagination |\n| `pageSize` | `number` | `25` | Rows per page |\n| `onSort` | `function` | — | Sort callback |\n| `onFilter` | `function` | — | Filter callback |\n| `onFetch` | `function` | — | Server-side fetch (setData, setLoading, filters, page, limit, sort) |\n| `onFilterChange` | `function` | — | Filter change callback |\n| `onSelectionChange` | `function` | — | Selected rows callback |\n| `onRowClick` | `function` | — | Row click callback |\n| `hasDetails` | `boolean` | `false` | Expandable row details |\n| `DetailsComponent` | `Component` | — | Component for expanded content |\n| `withAction` | `boolean` | `true` | Show actions column |\n| `onAction` | `function` | — | Action menu callback |\n| `actions` | `Array` | — | Custom actions (edit, delete, etc.) |\n| `showSerial` | `boolean` | `true` | Show row number column |\n| `cellClass` | `string` \\| `function` | — | Cell className |\n| `rowClass` | `string` \\| `function` | — | Row className |\n| `globalSearch` | `boolean` | `false` | Global search box |\n| `limitOptions` | `number[]` | `[10,25,50,100]` | Page size options |\n| `showLimitSelector` | `boolean` | `true` | Show page size selector |\n| `showReloadButton` | `boolean` | `true` | Show reload button |\n| `onReload` | `function` | — | Reload click handler |\n| `stripedRows` | `boolean` | `true` | Striped row background |\n| `theme` | `object` | — | `stripedColors`, `rowHover`, `accentColor` |\n| `serverSide` | `boolean` | `false` | Server-side pagination/sort/filter |\n| `totalRecords` | `number` | `0` | Total count (serverSide) |\n| `pageNumber` | `number` | — | Controlled page |\n| `responsiveBreakpoint` | `number` | `768` | px breakpoint for mobile cards |\n\n## Examples\n\n### Basic table\n\n```jsx\nconst columns = [\n { key: 'name', label: 'Name' },\n { key: 'email', label: 'Email' },\n];\nconst data = [\n { id: 1, name: 'Alice', email: 'alice@example.com' },\n { id: 2, name: 'Bob', email: 'bob@example.com' },\n];\n<Table data={data} columns={columns} />\n```\n\n### With pagination and selection\n\n```jsx\n<Table\n data={data}\n columns={columns}\n pagination\n pageSize={10}\n selectable\n onSelectionChange={(selected) => console.log(selected)}\n/>\n```\n\n### Server-side data\n\n```jsx\n<Table\n data={data}\n columns={columns}\n serverSide\n pagination\n totalRecords={total}\n onFetch={async ({ setData, setLoading, page, limit, sort }) => {\n setLoading(true);\n const res = await fetch(`/api/users?page=${page}&limit=${limit}`);\n const json = await res.json();\n setData(json.rows);\n setLoading(false);\n }}\n/>\n```\n\n[← Component overview](README.md)\n",
3164
+ "Table": "# Table\n\nData table with sorting, filtering, pagination, row selection, expandable details, and responsive mobile card view.\n\n## Import\n\n```jsx\nimport { Table } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `data` | `Array` | `[]` | Row data (array of objects) |\n| `columns` | `Array` | `[]` | `[{ key, label, sortable?, isVisible?, render? }]` |\n| `sortable` | `boolean` | `true` | Enable column sort |\n| `filterable` | `boolean` | `false` | Enable column filters |\n| `selectable` | `boolean` | `false` | Row selection checkboxes |\n| `pagination` | `boolean` | `false` | Enable pagination |\n| `pageSize` | `number` | `25` | Rows per page |\n| `onSort` | `function` | — | Sort callback |\n| `onFilter` | `function` | — | Filter callback |\n| `onFetch` | `function` | — | Server-side fetch (setData, setLoading, filters, page, limit, sort) |\n| `onFilterChange` | `function` | — | Filter change callback |\n| `onSelectionChange` | `function` | — | Selected rows callback |\n| `onRowClick` | `function` | — | Row click callback |\n| `hasDetails` | `boolean` | `false` | Expandable row details |\n| `DetailsComponent` | `Component` | — | Component for expanded content |\n| `withAction` | `boolean` | `true` | Show actions column |\n| `onAction` | `function` | — | Action menu callback |\n| `actions` | `Array` | — | Custom actions (edit, delete, etc.) |\n| `showSerial` | `boolean` | `true` | Show row number column |\n| `cellClass` | `string` \\| `function` | — | Cell className |\n| `rowClass` | `string` \\| `function` | — | Row className |\n| `globalSearch` | `boolean` | `false` | Global search box |\n| `limitOptions` | `number[]` | `[10,25,50,100]` | Page size options |\n| `showLimitSelector` | `boolean` | `true` | Show page size selector |\n| `showReloadButton` | `boolean` | `true` | Show reload button |\n| `onReload` | `function` | — | Reload click handler |\n| `stripedRows` | `boolean` | `true` | Striped row background |\n| `theme` | `object` | — | `stripedColors`, `rowHover`, `accentColor` |\n| `serverSide` | `boolean` | `false` | Server-side pagination/sort/filter |\n| `totalRecords` | `number` | `0` | Total count (serverSide) |\n| `pageNumber` | `number` | — | Controlled page |\n| `onPageChange` | `(page: number) => void` | — | Called with the new page number when the page changes. Consumed by the table — it is **not** forwarded onto the `<table>`. |\n| `responsiveBreakpoint` | `number` | `768` | px breakpoint for mobile cards |\n\nOnly DOM-valid attributes in `...rest` (e.g. `id`, `aria-*`, `data-*`) are\nforwarded to the root `<table>`; the table's own control props (`onPageChange`,\n`serverSide`, `pagination`, the `on*` callbacks, …) are consumed and never leak\nto the DOM as unknown attributes.\n\n## Examples\n\n### Basic table\n\n```jsx\nconst columns = [\n { key: 'name', label: 'Name' },\n { key: 'email', label: 'Email' },\n];\nconst data = [\n { id: 1, name: 'Alice', email: 'alice@example.com' },\n { id: 2, name: 'Bob', email: 'bob@example.com' },\n];\n<Table data={data} columns={columns} />\n```\n\n### With pagination and selection\n\n```jsx\n<Table\n data={data}\n columns={columns}\n pagination\n pageSize={10}\n selectable\n onSelectionChange={(selected) => console.log(selected)}\n/>\n```\n\n### Server-side data\n\n```jsx\n<Table\n data={data}\n columns={columns}\n serverSide\n pagination\n totalRecords={total}\n onFetch={async ({ setData, setLoading, page, limit, sort }) => {\n setLoading(true);\n const res = await fetch(`/api/users?page=${page}&limit=${limit}`);\n const json = await res.json();\n setData(json.rows);\n setLoading(false);\n }}\n/>\n```\n\n[← Component overview](README.md)\n",
3153
3165
  "Tabs": "# Tabs\n\nTabbed content with list and panels. Use subcomponents: `Tabs.List`, `Tabs.Tab`, `Tabs.Panels`, `Tabs.Panel`. Supports controlled (`index` + `onChange`) or uncontrolled (`defaultIndex`), keyboard navigation, and variants.\n\n## Import\n\n```jsx\nimport { Tabs } from '@dreamtree-org/twreact-ui';\n```\n\n## Props (Tabs root)\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `children` | `ReactNode` | — | Must include `Tabs.List` and `Tabs.Panels`. |\n| `defaultIndex` | `number` | `0` | Uncontrolled initial active tab index. |\n| `index` | `number` | — | Controlled active index. |\n| `onChange` | `(index: number) => void` | — | Called when tab changes. |\n| `orientation` | `\"horizontal\"` \\| `\"vertical\"` | `\"horizontal\"` | Layout direction. |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `\"md\"` | Tab size. |\n| `variant` | `\"line\"` \\| `\"pills\"` \\| `\"unstyled\"` | `\"line\"` | Tab style. |\n| `animated` | `boolean` | `true` | Fade animation on panel change. |\n| `className` | `string` | `\"\"` | Wrapper CSS classes. |\n\n## Usage\n\n```jsx\n<Tabs defaultIndex={0} variant=\"pills\" size=\"md\">\n <Tabs.List>\n <Tabs.Tab>Home</Tabs.Tab>\n <Tabs.Tab>Profile</Tabs.Tab>\n <Tabs.Tab>Settings</Tabs.Tab>\n </Tabs.List>\n <Tabs.Panels>\n <Tabs.Panel>Home content</Tabs.Panel>\n <Tabs.Panel>Profile content</Tabs.Panel>\n <Tabs.Panel>Settings content</Tabs.Panel>\n </Tabs.Panels>\n</Tabs>\n```\n\nControlled:\n\n```jsx\nconst [index, setIndex] = useState(0);\n<Tabs index={index} onChange={setIndex}>\n ...\n</Tabs>\n```\n\n[← Component overview](README.md)\n",
3154
3166
  "TextToSpeech": "# TextToSpeech\n\nText-to-speech using the browser’s Speech Synthesis API. Renders a default \"Speak\" / \"Stop\" button or a custom button via `renderButton`. Toggling speak while playing stops playback.\n\n## Import\n\n```jsx\nimport { TextToSpeech } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `text` | `string` | `\"\"` | Text to speak (used as initial input if component manages input). |\n| `rate` | `number` | `1` | Speech rate (0.1–10). |\n| `pitch` | `number` | `0.5` | Pitch (0–2). |\n| `onSpeak` | `(text: string) => void` | `() => {}` | Called when speech starts (with the text spoken). |\n| `renderButton` | `(props: { onClick, isSpeaking }) => ReactNode` | — | Custom button; receives `onClick` and `isSpeaking`. |\n\n## Behavior\n\n- Component keeps internal `inputText` state initialized from `text`; speaking uses that.\n- Clicking the button toggles: if not speaking, starts `SpeechSynthesisUtterance` with `inputText`; if speaking, calls `speechSynthesis.cancel()` and sets speaking to false.\n- `onSpeak` is called when speech starts.\n\n## Example\n\n```jsx\n<TextToSpeech text=\"Hello, world!\" rate={1} onSpeak={(t) => console.log('Speaking:', t)} />\n\n<TextToSpeech\n text={content}\n renderButton={({ onClick, isSpeaking }) => (\n <Button onClick={onClick}>{isSpeaking ? 'Stop' : 'Play'} audio</Button>\n )}\n/>\n```\n\n[← Component overview](README.md)\n",
3155
3167
  "ThreeDotPopover": "# ThreeDotPopover\n\nDropdown menu triggered by a three-dot (kebab) button. Use for row actions (Edit, Delete, etc.). Closes on outside click and Escape; optional close on item select.\n\n## Import\n\n```jsx\nimport { ThreeDotPopover } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `items` | `Array` | `[]` | Menu items: `{ key, label, icon?, onClick?, disabled?, destructive? }`. `icon` can be component (e.g. `Edit2`). |\n| `trigger` | `ReactNode` | — | Custom trigger; default is three-dot button. |\n| `className` | `string` | `\"\"` | CSS classes for the **default** trigger button (merged via `cn()`). |\n| `wrapperClassName` | `string` | `\"\"` | CSS classes merged (via `cn()`) onto the root container element. |\n| `menuClass` | `string` | `\"\"` | Menu container CSS classes. |\n| `menuItemClass` | `string` | `\"\"` | Each menu item CSS classes. |\n| `closeOnSelect` | `boolean` | `true` | Close menu when an item is selected. |\n| `ariaLabel` | `string` | `\"More options\"` | Trigger button aria-label. |\n\n## Item shape\n\n- `key` (string): Unique key.\n- `label` (string): Display text.\n- `icon` (optional): React component or node.\n- `onClick(item)` (optional): Called when item is clicked.\n- `disabled` (boolean): Disable the item.\n- `destructive` (boolean): Style as destructive (e.g. red for Delete).\n\n## Example\n\n```jsx\nimport { Edit2, Eye, Trash } from 'lucide-react';\n\n<ThreeDotPopover\n items={[\n { key: 'edit', label: 'Edit', icon: Edit2, onClick: () => edit(row) },\n { key: 'view', label: 'View', icon: Eye, onClick: () => view(row) },\n { key: 'delete', label: 'Delete', destructive: true, onClick: () => remove(row) },\n ]}\n closeOnSelect\n/>\n```\n\n## Notes\n\n- Forwards `ref` to the root container element and spreads unknown props\n (`...rest`) onto it.\n\n[← Component overview](README.md)\n",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamtree-org/twreact-ui",
3
- "version": "1.1.63",
3
+ "version": "1.1.64",
4
4
  "description": "A comprehensive React + Tailwind components library for building modern web apps",
5
5
  "author": {
6
6
  "name": "Partha Preetham Krishna",