bolt-table 0.1.35 → 0.1.36

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
@@ -84,31 +84,52 @@ interface ColumnType<T = unknown> {
84
84
  interface CellContextMenuItem<T = unknown> {
85
85
  /** Unique identifier for this menu item, used as the React `key`. */
86
86
  key: string;
87
- /** The label shown in the menu. Can be a string or React node. */
88
- label: React.ReactNode;
89
- /** Optional icon shown to the left of the label. */
90
- icon?: React.ReactNode;
87
+ /**
88
+ * The label shown in the menu. Can be a string, React node, or a function
89
+ * `(columnKey, record, rowIndex) => ReactNode` that returns a custom node
90
+ * derived from the row being clicked.
91
+ */
92
+ label: React.ReactNode | ((columnKey: string, record: T, rowIndex: number) => React.ReactNode);
93
+ /**
94
+ * Optional icon shown to the left of the label. Can be a React node or a
95
+ * function `(columnKey, record, rowIndex) => ReactNode` for row-aware icons.
96
+ */
97
+ icon?: React.ReactNode | ((columnKey: string, record: T, rowIndex: number) => React.ReactNode);
91
98
  /** When `true`, the label renders in red to indicate a destructive action. */
92
99
  danger?: boolean;
93
100
  /** When `true`, the item is grayed out and click handler is not called. */
94
101
  disabled?: boolean;
95
- /** Called when the user clicks this menu item. Receives the column key, row record, and row index. */
96
- onClick: (columnKey: string, record: T, rowIndex: number) => void;
102
+ /**
103
+ * Called when the user clicks this menu item. Receives the column key, row
104
+ * record, and row index. Optional — omit if the item's label renders its
105
+ * own interactive content (e.g. a custom React node that handles clicks).
106
+ */
107
+ onClick?: (columnKey: string, record: T, rowIndex: number) => void;
97
108
  }
98
109
  /** A single item in the column header right-click context menu. */
99
110
  interface ColumnContextMenuItem {
100
111
  /** Unique identifier for this menu item, used as the React `key`. */
101
112
  key: string;
102
- /** The label shown in the menu. Can be a string or React node. */
103
- label: React.ReactNode;
104
- /** Optional icon shown to the left of the label. */
105
- icon?: React.ReactNode;
113
+ /**
114
+ * The label shown in the menu. Can be a string, React node, or a function
115
+ * `(columnKey) => ReactNode` that returns a custom node derived from the
116
+ * column being clicked.
117
+ */
118
+ label: React.ReactNode | ((columnKey: string) => React.ReactNode);
119
+ /**
120
+ * Optional icon shown to the left of the label. Can be a React node or a
121
+ * function `(columnKey) => ReactNode` for column-aware icons.
122
+ */
123
+ icon?: React.ReactNode | ((columnKey: string) => React.ReactNode);
106
124
  /** When `true`, the label renders in red to indicate a destructive action. */
107
125
  danger?: boolean;
108
126
  /** When `true`, the item is grayed out and click handler is not called. */
109
127
  disabled?: boolean;
110
- /** Called when the user clicks this menu item. Receives the column `key`. */
111
- onClick: (columnKey: string) => void;
128
+ /**
129
+ * Called when the user clicks this menu item. Receives the column `key`.
130
+ * Optional — omit if the item's label renders its own interactive content.
131
+ */
132
+ onClick?: (columnKey: string) => void;
112
133
  }
113
134
  /** How the row selection was triggered: `'all'`, `'single'`, or `'multiple'`. */
114
135
  type RowSelectMethod = "all" | "single" | "multiple";
package/dist/index.d.ts CHANGED
@@ -84,31 +84,52 @@ interface ColumnType<T = unknown> {
84
84
  interface CellContextMenuItem<T = unknown> {
85
85
  /** Unique identifier for this menu item, used as the React `key`. */
86
86
  key: string;
87
- /** The label shown in the menu. Can be a string or React node. */
88
- label: React.ReactNode;
89
- /** Optional icon shown to the left of the label. */
90
- icon?: React.ReactNode;
87
+ /**
88
+ * The label shown in the menu. Can be a string, React node, or a function
89
+ * `(columnKey, record, rowIndex) => ReactNode` that returns a custom node
90
+ * derived from the row being clicked.
91
+ */
92
+ label: React.ReactNode | ((columnKey: string, record: T, rowIndex: number) => React.ReactNode);
93
+ /**
94
+ * Optional icon shown to the left of the label. Can be a React node or a
95
+ * function `(columnKey, record, rowIndex) => ReactNode` for row-aware icons.
96
+ */
97
+ icon?: React.ReactNode | ((columnKey: string, record: T, rowIndex: number) => React.ReactNode);
91
98
  /** When `true`, the label renders in red to indicate a destructive action. */
92
99
  danger?: boolean;
93
100
  /** When `true`, the item is grayed out and click handler is not called. */
94
101
  disabled?: boolean;
95
- /** Called when the user clicks this menu item. Receives the column key, row record, and row index. */
96
- onClick: (columnKey: string, record: T, rowIndex: number) => void;
102
+ /**
103
+ * Called when the user clicks this menu item. Receives the column key, row
104
+ * record, and row index. Optional — omit if the item's label renders its
105
+ * own interactive content (e.g. a custom React node that handles clicks).
106
+ */
107
+ onClick?: (columnKey: string, record: T, rowIndex: number) => void;
97
108
  }
98
109
  /** A single item in the column header right-click context menu. */
99
110
  interface ColumnContextMenuItem {
100
111
  /** Unique identifier for this menu item, used as the React `key`. */
101
112
  key: string;
102
- /** The label shown in the menu. Can be a string or React node. */
103
- label: React.ReactNode;
104
- /** Optional icon shown to the left of the label. */
105
- icon?: React.ReactNode;
113
+ /**
114
+ * The label shown in the menu. Can be a string, React node, or a function
115
+ * `(columnKey) => ReactNode` that returns a custom node derived from the
116
+ * column being clicked.
117
+ */
118
+ label: React.ReactNode | ((columnKey: string) => React.ReactNode);
119
+ /**
120
+ * Optional icon shown to the left of the label. Can be a React node or a
121
+ * function `(columnKey) => ReactNode` for column-aware icons.
122
+ */
123
+ icon?: React.ReactNode | ((columnKey: string) => React.ReactNode);
106
124
  /** When `true`, the label renders in red to indicate a destructive action. */
107
125
  danger?: boolean;
108
126
  /** When `true`, the item is grayed out and click handler is not called. */
109
127
  disabled?: boolean;
110
- /** Called when the user clicks this menu item. Receives the column `key`. */
111
- onClick: (columnKey: string) => void;
128
+ /**
129
+ * Called when the user clicks this menu item. Receives the column `key`.
130
+ * Optional — omit if the item's label renders its own interactive content.
131
+ */
132
+ onClick?: (columnKey: string) => void;
112
133
  }
113
134
  /** How the row selection was triggered: `'all'`, `'single'`, or `'multiple'`. */
114
135
  type RowSelectMethod = "all" | "single" | "multiple";
package/dist/index.js CHANGED
@@ -623,40 +623,44 @@ var DraggableHeader = import_react.default.memo(
623
623
  ] }),
624
624
  customContextMenuItems && customContextMenuItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
625
625
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } }),
626
- customContextMenuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
627
- "button",
628
- {
629
- type: "button",
630
- "data-bt-ctx-item": "",
631
- disabled: item.disabled,
632
- style: {
633
- display: "flex",
634
- width: "100%",
635
- alignItems: "center",
636
- gap: 8,
637
- paddingLeft: 12,
638
- paddingRight: 12,
639
- paddingTop: 6,
640
- paddingBottom: 6,
641
- textAlign: "left",
642
- background: "none",
643
- border: "none",
644
- fontSize: "inherit",
645
- cursor: item.disabled ? "not-allowed" : "pointer",
646
- opacity: item.disabled ? 0.5 : 1,
647
- color: item.danger ? "#ef4444" : "inherit"
648
- },
649
- onClick: () => {
650
- item.onClick(column.key);
651
- setContextMenu(null);
626
+ customContextMenuItems.map((item) => {
627
+ const resolvedIcon = typeof item.icon === "function" ? item.icon(column.key) : item.icon;
628
+ const resolvedLabel = typeof item.label === "function" ? item.label(column.key) : item.label;
629
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
630
+ "button",
631
+ {
632
+ type: "button",
633
+ "data-bt-ctx-item": "",
634
+ disabled: item.disabled,
635
+ style: {
636
+ display: "flex",
637
+ width: "100%",
638
+ alignItems: "center",
639
+ gap: 8,
640
+ paddingLeft: 12,
641
+ paddingRight: 12,
642
+ paddingTop: 6,
643
+ paddingBottom: 6,
644
+ textAlign: "left",
645
+ background: "none",
646
+ border: "none",
647
+ fontSize: "inherit",
648
+ cursor: item.disabled ? "not-allowed" : "pointer",
649
+ opacity: item.disabled ? 0.5 : 1,
650
+ color: item.danger ? "#ef4444" : "inherit"
651
+ },
652
+ onClick: () => {
653
+ item.onClick?.(column.key);
654
+ setContextMenu(null);
655
+ },
656
+ children: [
657
+ resolvedIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { display: "flex", width: 12, height: 12, alignItems: "center", justifyContent: "center" }, children: resolvedIcon }),
658
+ resolvedLabel
659
+ ]
652
660
  },
653
- children: [
654
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { display: "flex", width: 12, height: 12, alignItems: "center", justifyContent: "center" }, children: item.icon }),
655
- item.label
656
- ]
657
- },
658
- item.key
659
- ))
661
+ item.key
662
+ );
663
+ })
660
664
  ] })
661
665
  ] });
662
666
  })()
@@ -4225,44 +4229,60 @@ function BoltTable({
4225
4229
  }
4226
4230
  }
4227
4231
  ),
4228
- menuCol.columnCellContextMenuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
4229
- "button",
4230
- {
4231
- type: "button",
4232
- "data-bt-ctx-item": "",
4233
- disabled: item.disabled,
4234
- style: {
4235
- ...btnStyle,
4236
- cursor: item.disabled ? "not-allowed" : "pointer",
4237
- opacity: item.disabled ? 0.5 : 1,
4238
- color: item.danger ? "#ef4444" : "inherit"
4239
- },
4240
- onClick: () => {
4241
- if (menuRecord) {
4242
- item.onClick(menuCol.key, menuRecord, menuRowIndex);
4243
- }
4244
- setCellContextMenu(null);
4245
- },
4246
- children: [
4247
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4248
- "span",
4249
- {
4250
- style: {
4251
- display: "flex",
4252
- width: 14,
4253
- height: 14,
4254
- alignItems: "center",
4255
- justifyContent: "center",
4256
- flexShrink: 0
4257
- },
4258
- children: item.icon
4232
+ menuCol.columnCellContextMenuItems.map((item) => {
4233
+ const resolvedIcon = typeof item.icon === "function" ? menuRecord ? item.icon(
4234
+ menuCol.key,
4235
+ menuRecord,
4236
+ menuRowIndex
4237
+ ) : null : item.icon;
4238
+ const resolvedLabel = typeof item.label === "function" ? menuRecord ? item.label(
4239
+ menuCol.key,
4240
+ menuRecord,
4241
+ menuRowIndex
4242
+ ) : null : item.label;
4243
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
4244
+ "button",
4245
+ {
4246
+ type: "button",
4247
+ "data-bt-ctx-item": "",
4248
+ disabled: item.disabled,
4249
+ style: {
4250
+ ...btnStyle,
4251
+ cursor: item.disabled ? "not-allowed" : "pointer",
4252
+ opacity: item.disabled ? 0.5 : 1,
4253
+ color: item.danger ? "#ef4444" : "inherit"
4254
+ },
4255
+ onClick: () => {
4256
+ if (menuRecord && item.onClick) {
4257
+ item.onClick(
4258
+ menuCol.key,
4259
+ menuRecord,
4260
+ menuRowIndex
4261
+ );
4259
4262
  }
4260
- ),
4261
- item.label
4262
- ]
4263
- },
4264
- item.key
4265
- ))
4263
+ setCellContextMenu(null);
4264
+ },
4265
+ children: [
4266
+ resolvedIcon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4267
+ "span",
4268
+ {
4269
+ style: {
4270
+ display: "flex",
4271
+ width: 14,
4272
+ height: 14,
4273
+ alignItems: "center",
4274
+ justifyContent: "center",
4275
+ flexShrink: 0
4276
+ },
4277
+ children: resolvedIcon
4278
+ }
4279
+ ),
4280
+ resolvedLabel
4281
+ ]
4282
+ },
4283
+ item.key
4284
+ );
4285
+ })
4266
4286
  ] })
4267
4287
  ]
4268
4288
  }
package/dist/index.mjs CHANGED
@@ -589,40 +589,44 @@ var DraggableHeader = React.memo(
589
589
  ] }),
590
590
  customContextMenuItems && customContextMenuItems.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
591
591
  /* @__PURE__ */ jsx2("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } }),
592
- customContextMenuItems.map((item) => /* @__PURE__ */ jsxs2(
593
- "button",
594
- {
595
- type: "button",
596
- "data-bt-ctx-item": "",
597
- disabled: item.disabled,
598
- style: {
599
- display: "flex",
600
- width: "100%",
601
- alignItems: "center",
602
- gap: 8,
603
- paddingLeft: 12,
604
- paddingRight: 12,
605
- paddingTop: 6,
606
- paddingBottom: 6,
607
- textAlign: "left",
608
- background: "none",
609
- border: "none",
610
- fontSize: "inherit",
611
- cursor: item.disabled ? "not-allowed" : "pointer",
612
- opacity: item.disabled ? 0.5 : 1,
613
- color: item.danger ? "#ef4444" : "inherit"
614
- },
615
- onClick: () => {
616
- item.onClick(column.key);
617
- setContextMenu(null);
592
+ customContextMenuItems.map((item) => {
593
+ const resolvedIcon = typeof item.icon === "function" ? item.icon(column.key) : item.icon;
594
+ const resolvedLabel = typeof item.label === "function" ? item.label(column.key) : item.label;
595
+ return /* @__PURE__ */ jsxs2(
596
+ "button",
597
+ {
598
+ type: "button",
599
+ "data-bt-ctx-item": "",
600
+ disabled: item.disabled,
601
+ style: {
602
+ display: "flex",
603
+ width: "100%",
604
+ alignItems: "center",
605
+ gap: 8,
606
+ paddingLeft: 12,
607
+ paddingRight: 12,
608
+ paddingTop: 6,
609
+ paddingBottom: 6,
610
+ textAlign: "left",
611
+ background: "none",
612
+ border: "none",
613
+ fontSize: "inherit",
614
+ cursor: item.disabled ? "not-allowed" : "pointer",
615
+ opacity: item.disabled ? 0.5 : 1,
616
+ color: item.danger ? "#ef4444" : "inherit"
617
+ },
618
+ onClick: () => {
619
+ item.onClick?.(column.key);
620
+ setContextMenu(null);
621
+ },
622
+ children: [
623
+ resolvedIcon && /* @__PURE__ */ jsx2("span", { style: { display: "flex", width: 12, height: 12, alignItems: "center", justifyContent: "center" }, children: resolvedIcon }),
624
+ resolvedLabel
625
+ ]
618
626
  },
619
- children: [
620
- item.icon && /* @__PURE__ */ jsx2("span", { style: { display: "flex", width: 12, height: 12, alignItems: "center", justifyContent: "center" }, children: item.icon }),
621
- item.label
622
- ]
623
- },
624
- item.key
625
- ))
627
+ item.key
628
+ );
629
+ })
626
630
  ] })
627
631
  ] });
628
632
  })()
@@ -4197,44 +4201,60 @@ function BoltTable({
4197
4201
  }
4198
4202
  }
4199
4203
  ),
4200
- menuCol.columnCellContextMenuItems.map((item) => /* @__PURE__ */ jsxs5(
4201
- "button",
4202
- {
4203
- type: "button",
4204
- "data-bt-ctx-item": "",
4205
- disabled: item.disabled,
4206
- style: {
4207
- ...btnStyle,
4208
- cursor: item.disabled ? "not-allowed" : "pointer",
4209
- opacity: item.disabled ? 0.5 : 1,
4210
- color: item.danger ? "#ef4444" : "inherit"
4211
- },
4212
- onClick: () => {
4213
- if (menuRecord) {
4214
- item.onClick(menuCol.key, menuRecord, menuRowIndex);
4215
- }
4216
- setCellContextMenu(null);
4217
- },
4218
- children: [
4219
- item.icon && /* @__PURE__ */ jsx5(
4220
- "span",
4221
- {
4222
- style: {
4223
- display: "flex",
4224
- width: 14,
4225
- height: 14,
4226
- alignItems: "center",
4227
- justifyContent: "center",
4228
- flexShrink: 0
4229
- },
4230
- children: item.icon
4204
+ menuCol.columnCellContextMenuItems.map((item) => {
4205
+ const resolvedIcon = typeof item.icon === "function" ? menuRecord ? item.icon(
4206
+ menuCol.key,
4207
+ menuRecord,
4208
+ menuRowIndex
4209
+ ) : null : item.icon;
4210
+ const resolvedLabel = typeof item.label === "function" ? menuRecord ? item.label(
4211
+ menuCol.key,
4212
+ menuRecord,
4213
+ menuRowIndex
4214
+ ) : null : item.label;
4215
+ return /* @__PURE__ */ jsxs5(
4216
+ "button",
4217
+ {
4218
+ type: "button",
4219
+ "data-bt-ctx-item": "",
4220
+ disabled: item.disabled,
4221
+ style: {
4222
+ ...btnStyle,
4223
+ cursor: item.disabled ? "not-allowed" : "pointer",
4224
+ opacity: item.disabled ? 0.5 : 1,
4225
+ color: item.danger ? "#ef4444" : "inherit"
4226
+ },
4227
+ onClick: () => {
4228
+ if (menuRecord && item.onClick) {
4229
+ item.onClick(
4230
+ menuCol.key,
4231
+ menuRecord,
4232
+ menuRowIndex
4233
+ );
4231
4234
  }
4232
- ),
4233
- item.label
4234
- ]
4235
- },
4236
- item.key
4237
- ))
4235
+ setCellContextMenu(null);
4236
+ },
4237
+ children: [
4238
+ resolvedIcon && /* @__PURE__ */ jsx5(
4239
+ "span",
4240
+ {
4241
+ style: {
4242
+ display: "flex",
4243
+ width: 14,
4244
+ height: 14,
4245
+ alignItems: "center",
4246
+ justifyContent: "center",
4247
+ flexShrink: 0
4248
+ },
4249
+ children: resolvedIcon
4250
+ }
4251
+ ),
4252
+ resolvedLabel
4253
+ ]
4254
+ },
4255
+ item.key
4256
+ );
4257
+ })
4238
4258
  ] })
4239
4259
  ]
4240
4260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bolt-table",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Virtualized React table with column drag & drop, pinning, resizing, sorting, filtering, and pagination.",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",