@marcoschwartz/lite-ui 0.7.0 → 0.7.1

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.d.mts CHANGED
@@ -105,13 +105,16 @@ interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement
105
105
  }
106
106
  declare const TextInput: React.ForwardRefExoticComponent<TextInputProps & React.RefAttributes<HTMLInputElement>>;
107
107
 
108
- interface ActionMenuItem {
108
+ type ActionMenuItem = {
109
+ type?: 'item';
109
110
  label: string;
110
111
  onClick: () => void;
111
112
  icon?: React.ReactNode;
112
113
  disabled?: boolean;
113
114
  variant?: 'default' | 'danger';
114
- }
115
+ } | {
116
+ type: 'divider';
117
+ };
115
118
  interface ActionMenuProps {
116
119
  items: ActionMenuItem[];
117
120
  trigger?: React.ReactNode;
package/dist/index.d.ts CHANGED
@@ -105,13 +105,16 @@ interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement
105
105
  }
106
106
  declare const TextInput: React.ForwardRefExoticComponent<TextInputProps & React.RefAttributes<HTMLInputElement>>;
107
107
 
108
- interface ActionMenuItem {
108
+ type ActionMenuItem = {
109
+ type?: 'item';
109
110
  label: string;
110
111
  onClick: () => void;
111
112
  icon?: React.ReactNode;
112
113
  disabled?: boolean;
113
114
  variant?: 'default' | 'danger';
114
- }
115
+ } | {
116
+ type: 'divider';
117
+ };
115
118
  interface ActionMenuProps {
116
119
  items: ActionMenuItem[];
117
120
  trigger?: React.ReactNode;
package/dist/index.js CHANGED
@@ -1029,6 +1029,7 @@ TextInput.displayName = "TextInput";
1029
1029
 
1030
1030
  // src/components/ActionMenu.tsx
1031
1031
  var import_react8 = require("react");
1032
+ var import_react_dom = require("react-dom");
1032
1033
  var import_jsx_runtime41 = require("react/jsx-runtime");
1033
1034
  var ActionMenu = ({
1034
1035
  items,
@@ -1037,10 +1038,16 @@ var ActionMenu = ({
1037
1038
  }) => {
1038
1039
  const { themeName } = useTheme();
1039
1040
  const [isOpen, setIsOpen] = (0, import_react8.useState)(false);
1041
+ const [menuPosition, setMenuPosition] = (0, import_react8.useState)(null);
1042
+ const [mounted, setMounted] = (0, import_react8.useState)(false);
1040
1043
  const menuRef = (0, import_react8.useRef)(null);
1044
+ const triggerRef = (0, import_react8.useRef)(null);
1045
+ (0, import_react8.useEffect)(() => {
1046
+ setMounted(true);
1047
+ }, []);
1041
1048
  (0, import_react8.useEffect)(() => {
1042
1049
  const handleClickOutside = (event) => {
1043
- if (menuRef.current && !menuRef.current.contains(event.target)) {
1050
+ if (menuRef.current && !menuRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
1044
1051
  setIsOpen(false);
1045
1052
  }
1046
1053
  };
@@ -1049,7 +1056,20 @@ var ActionMenu = ({
1049
1056
  return () => document.removeEventListener("mousedown", handleClickOutside);
1050
1057
  }
1051
1058
  }, [isOpen]);
1059
+ (0, import_react8.useEffect)(() => {
1060
+ if (isOpen && triggerRef.current) {
1061
+ const rect = triggerRef.current.getBoundingClientRect();
1062
+ const menuWidth = 224;
1063
+ setMenuPosition({
1064
+ top: rect.bottom + 8,
1065
+ left: position === "left" ? rect.left : rect.right - menuWidth
1066
+ });
1067
+ } else {
1068
+ setMenuPosition(null);
1069
+ }
1070
+ }, [isOpen, position]);
1052
1071
  const handleItemClick = (item) => {
1072
+ if (item.type === "divider") return;
1053
1073
  if (!item.disabled) {
1054
1074
  item.onClick();
1055
1075
  setIsOpen(false);
@@ -1065,15 +1085,27 @@ var ActionMenu = ({
1065
1085
  );
1066
1086
  const menuBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-lg";
1067
1087
  const itemBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors";
1068
- const positionClass = position === "left" ? "left-0" : "right-0";
1069
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "relative inline-block", ref: menuRef, children: [
1070
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { onClick: () => setIsOpen(!isOpen), children: trigger || defaultTrigger }),
1071
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
1072
- "div",
1073
- {
1074
- className: `absolute ${positionClass} mt-2 w-56 rounded-lg ${menuBaseStyles} z-50 overflow-hidden`,
1075
- style: { minWidth: "14rem" },
1076
- children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
1088
+ const menu = isOpen && mounted && menuPosition ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
1089
+ "div",
1090
+ {
1091
+ ref: menuRef,
1092
+ className: `fixed w-56 rounded-lg ${menuBaseStyles} z-[9999] max-h-[80vh] overflow-auto`,
1093
+ style: {
1094
+ minWidth: "14rem",
1095
+ top: `${menuPosition.top}px`,
1096
+ left: `${menuPosition.left}px`
1097
+ },
1098
+ children: items.map((item, index) => {
1099
+ if (item.type === "divider") {
1100
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
1101
+ "div",
1102
+ {
1103
+ className: "my-1 border-t border-gray-200 dark:border-gray-700"
1104
+ },
1105
+ index
1106
+ );
1107
+ }
1108
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
1077
1109
  "button",
1078
1110
  {
1079
1111
  onClick: () => handleItemClick(item),
@@ -1085,9 +1117,13 @@ var ActionMenu = ({
1085
1117
  ]
1086
1118
  },
1087
1119
  index
1088
- ))
1089
- }
1090
- )
1120
+ );
1121
+ })
1122
+ }
1123
+ ) : null;
1124
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
1125
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "relative inline-block", ref: triggerRef, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { onClick: () => setIsOpen(!isOpen), children: trigger || defaultTrigger }) }),
1126
+ mounted && (0, import_react_dom.createPortal)(menu, document.body)
1091
1127
  ] });
1092
1128
  };
1093
1129
 
@@ -1347,33 +1383,42 @@ function Table({
1347
1383
  const { theme } = useTheme();
1348
1384
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: `overflow-x-auto ${className}`, children: [
1349
1385
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("table", { className: "w-full text-left", children: [
1350
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("thead", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("tr", { children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1351
- "th",
1352
- {
1353
- className: "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
1354
- style: { width: column.width },
1355
- children: column.title
1356
- },
1357
- column.key
1358
- )) }) }),
1359
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1360
- "tr",
1361
- {
1362
- className: `
1363
- ${striped && rowIndex % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : ""}
1364
- ${hoverable ? "hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" : ""}
1365
- `,
1366
- children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1367
- "td",
1368
- {
1369
- className: "px-6 py-4 text-sm text-gray-900 dark:text-gray-100",
1370
- children: column.render ? column.render(row[column.key], row, rowIndex) : row[column.key]
1371
- },
1372
- column.key
1373
- ))
1374
- },
1375
- row[keyField] || rowIndex
1376
- )) })
1386
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("thead", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("tr", { children: columns.map((column, colIndex) => {
1387
+ const isLast = colIndex === columns.length - 1;
1388
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1389
+ "th",
1390
+ {
1391
+ className: isLast ? "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider relative" : "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
1392
+ style: { width: column.width },
1393
+ children: column.title
1394
+ },
1395
+ column.key
1396
+ );
1397
+ }) }) }),
1398
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: data.map((row, rowIndex) => {
1399
+ const rowClasses = [
1400
+ striped && rowIndex % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : "",
1401
+ hoverable ? "hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" : ""
1402
+ ].filter(Boolean).join(" ");
1403
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1404
+ "tr",
1405
+ {
1406
+ className: rowClasses,
1407
+ children: columns.map((column, colIndex) => {
1408
+ const isLast = colIndex === columns.length - 1;
1409
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1410
+ "td",
1411
+ {
1412
+ className: isLast ? "px-6 py-4 text-sm text-gray-900 dark:text-gray-100 overflow-visible" : "px-6 py-4 text-sm text-gray-900 dark:text-gray-100",
1413
+ children: column.render ? column.render(row[column.key], row, rowIndex) : row[column.key]
1414
+ },
1415
+ column.key
1416
+ );
1417
+ })
1418
+ },
1419
+ row[keyField] || rowIndex
1420
+ );
1421
+ }) })
1377
1422
  ] }),
1378
1423
  data.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "text-center py-8 text-gray-500 dark:text-gray-400", children: "No data available" })
1379
1424
  ] });