@undevy-org/tablewright 0.9.0 → 0.10.0
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/es/components/data-table/ColumnHeaderMenu.js +36 -6
- package/dist/es/components/data-table/sticky-utils.js +14 -4
- package/dist/styles.css +7 -0
- package/dist/tablewright.cjs +49 -9
- package/dist/tablewright.css +7 -0
- package/dist/types/components/data-table/ColumnHeaderMenu.d.ts +8 -1
- package/package.json +1 -1
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from "../ui/dropdown-menu.js";
|
|
4
|
-
import { ChevronDown, ListFilter, EyeOff, ArrowUp, ArrowDown
|
|
4
|
+
import { ChevronDown, ListFilter, EyeOff, Pin, Check, PinOff, ArrowUp, ArrowDown } from "lucide-react";
|
|
5
5
|
const DEFAULT_LABELS = {
|
|
6
6
|
sort: "Sort",
|
|
7
7
|
sortByColumn: (label) => `Sort by ${label}`,
|
|
8
8
|
ascending: "Ascending",
|
|
9
9
|
descending: "Descending",
|
|
10
10
|
filterByColumn: "Filter by this column",
|
|
11
|
-
hideColumn: "Hide column"
|
|
11
|
+
hideColumn: "Hide column",
|
|
12
|
+
pinLeft: "Pin left",
|
|
13
|
+
pinRight: "Pin right",
|
|
14
|
+
unpin: "Unpin"
|
|
12
15
|
};
|
|
13
16
|
const sectionLabelClass = "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-[var(--text-tertiary)] first:pt-1";
|
|
14
17
|
const itemClass = "gap-2.5 rounded-md px-2.5 py-2";
|
|
@@ -60,6 +63,10 @@ function ColumnHeaderMenu({
|
|
|
60
63
|
hasFilter,
|
|
61
64
|
onFilterClick,
|
|
62
65
|
onHide,
|
|
66
|
+
pinSide = false,
|
|
67
|
+
onPinLeft,
|
|
68
|
+
onPinRight,
|
|
69
|
+
onUnpin,
|
|
63
70
|
labels: labelOverrides,
|
|
64
71
|
menuWidth = "w-[200px]"
|
|
65
72
|
}) {
|
|
@@ -68,7 +75,15 @@ function ColumnHeaderMenu({
|
|
|
68
75
|
const isStacked = !!primaryLabel;
|
|
69
76
|
const isSingleSortable = !!label && !!onSort;
|
|
70
77
|
const isSortable = isStacked || isSingleSortable;
|
|
71
|
-
const
|
|
78
|
+
const showFilterItem = Boolean(hasFilter && onFilterClick);
|
|
79
|
+
const showHideItem = Boolean(onHide);
|
|
80
|
+
const showPinLeftItem = Boolean(onPinLeft);
|
|
81
|
+
const showPinRightItem = Boolean(onPinRight);
|
|
82
|
+
const showUnpinItem = Boolean(onUnpin && pinSide);
|
|
83
|
+
const hasPinSection = showPinLeftItem || showPinRightItem || showUnpinItem;
|
|
84
|
+
const hasFilterOrHide = showFilterItem || showHideItem;
|
|
85
|
+
const showSeparatorAfterSort = isSortable && (hasFilterOrHide || hasPinSection);
|
|
86
|
+
const showSeparatorBeforePin = hasPinSection && hasFilterOrHide;
|
|
72
87
|
const labelContent = isStacked ? /* @__PURE__ */ jsxs("span", { className: "flex flex-col leading-none", children: [
|
|
73
88
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-primary)]", children: [
|
|
74
89
|
primaryLabel,
|
|
@@ -127,14 +142,29 @@ function ColumnHeaderMenu({
|
|
|
127
142
|
labels
|
|
128
143
|
}
|
|
129
144
|
),
|
|
130
|
-
|
|
131
|
-
|
|
145
|
+
showSeparatorAfterSort && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-[var(--border-subtle)]" }),
|
|
146
|
+
showFilterItem && /* @__PURE__ */ jsxs(DropdownMenuItem, { className: itemClass, onClick: onFilterClick, children: [
|
|
132
147
|
/* @__PURE__ */ jsx(ListFilter, { className: iconClass }),
|
|
133
148
|
labels.filterByColumn
|
|
134
149
|
] }),
|
|
135
|
-
|
|
150
|
+
showHideItem && /* @__PURE__ */ jsxs(DropdownMenuItem, { className: itemClass, onClick: onHide, children: [
|
|
136
151
|
/* @__PURE__ */ jsx(EyeOff, { className: iconClass }),
|
|
137
152
|
labels.hideColumn
|
|
153
|
+
] }),
|
|
154
|
+
showSeparatorBeforePin && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-[var(--border-subtle)]" }),
|
|
155
|
+
showPinLeftItem && /* @__PURE__ */ jsxs(DropdownMenuItem, { className: itemClass, onClick: onPinLeft, children: [
|
|
156
|
+
/* @__PURE__ */ jsx(Pin, { className: iconClass }),
|
|
157
|
+
labels.pinLeft,
|
|
158
|
+
pinSide === "left" && /* @__PURE__ */ jsx(Check, { className: "ml-auto h-3 w-3 text-[var(--text-tertiary)]" })
|
|
159
|
+
] }),
|
|
160
|
+
showPinRightItem && /* @__PURE__ */ jsxs(DropdownMenuItem, { className: itemClass, onClick: onPinRight, children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Pin, { className: `${iconClass} rotate-90` }),
|
|
162
|
+
labels.pinRight,
|
|
163
|
+
pinSide === "right" && /* @__PURE__ */ jsx(Check, { className: "ml-auto h-3 w-3 text-[var(--text-tertiary)]" })
|
|
164
|
+
] }),
|
|
165
|
+
showUnpinItem && /* @__PURE__ */ jsxs(DropdownMenuItem, { className: itemClass, onClick: onUnpin, children: [
|
|
166
|
+
/* @__PURE__ */ jsx(PinOff, { className: iconClass }),
|
|
167
|
+
labels.unpin
|
|
138
168
|
] })
|
|
139
169
|
] })
|
|
140
170
|
] });
|
|
@@ -19,15 +19,25 @@ function applyColumnPinningToMeta(baseMeta, pinning, options) {
|
|
|
19
19
|
for (const id of order) {
|
|
20
20
|
const meta = result[id];
|
|
21
21
|
if (meta?.sticky !== "left") continue;
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const width = columnWidthPx(id, baseMeta, options?.columnWidths);
|
|
23
|
+
if (pinnedLeft.has(id)) {
|
|
24
|
+
result[id] = { ...meta, stickyOffset: leftOffset };
|
|
25
|
+
leftOffset += width;
|
|
26
|
+
} else {
|
|
27
|
+
leftOffset = (meta.stickyOffset ?? 0) + width;
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
let rightOffset = 0;
|
|
26
31
|
for (const id of [...order].reverse()) {
|
|
27
32
|
const meta = result[id];
|
|
28
33
|
if (meta?.sticky !== "right") continue;
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
const width = columnWidthPx(id, baseMeta, options?.columnWidths);
|
|
35
|
+
if (pinnedRight.has(id)) {
|
|
36
|
+
result[id] = { ...meta, stickyOffset: rightOffset };
|
|
37
|
+
rightOffset += width;
|
|
38
|
+
} else {
|
|
39
|
+
rightOffset = (meta.stickyOffset ?? 0) + width;
|
|
40
|
+
}
|
|
31
41
|
}
|
|
32
42
|
return result;
|
|
33
43
|
}
|
package/dist/styles.css
CHANGED
|
@@ -402,6 +402,9 @@
|
|
|
402
402
|
.collapse {
|
|
403
403
|
visibility: collapse
|
|
404
404
|
}
|
|
405
|
+
.static {
|
|
406
|
+
position: static
|
|
407
|
+
}
|
|
405
408
|
.fixed {
|
|
406
409
|
position: fixed
|
|
407
410
|
}
|
|
@@ -784,6 +787,10 @@
|
|
|
784
787
|
--tw-rotate: 180deg;
|
|
785
788
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))
|
|
786
789
|
}
|
|
790
|
+
.rotate-90 {
|
|
791
|
+
--tw-rotate: 90deg;
|
|
792
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))
|
|
793
|
+
}
|
|
787
794
|
.cursor-col-resize {
|
|
788
795
|
cursor: col-resize
|
|
789
796
|
}
|
package/dist/tablewright.cjs
CHANGED
|
@@ -952,15 +952,25 @@ function applyColumnPinningToMeta(baseMeta, pinning, options) {
|
|
|
952
952
|
for (const id of order) {
|
|
953
953
|
const meta = result[id];
|
|
954
954
|
if (meta?.sticky !== "left") continue;
|
|
955
|
-
|
|
956
|
-
|
|
955
|
+
const width = columnWidthPx(id, baseMeta, options?.columnWidths);
|
|
956
|
+
if (pinnedLeft.has(id)) {
|
|
957
|
+
result[id] = { ...meta, stickyOffset: leftOffset };
|
|
958
|
+
leftOffset += width;
|
|
959
|
+
} else {
|
|
960
|
+
leftOffset = (meta.stickyOffset ?? 0) + width;
|
|
961
|
+
}
|
|
957
962
|
}
|
|
958
963
|
let rightOffset = 0;
|
|
959
964
|
for (const id of [...order].reverse()) {
|
|
960
965
|
const meta = result[id];
|
|
961
966
|
if (meta?.sticky !== "right") continue;
|
|
962
|
-
|
|
963
|
-
|
|
967
|
+
const width = columnWidthPx(id, baseMeta, options?.columnWidths);
|
|
968
|
+
if (pinnedRight.has(id)) {
|
|
969
|
+
result[id] = { ...meta, stickyOffset: rightOffset };
|
|
970
|
+
rightOffset += width;
|
|
971
|
+
} else {
|
|
972
|
+
rightOffset = (meta.stickyOffset ?? 0) + width;
|
|
973
|
+
}
|
|
964
974
|
}
|
|
965
975
|
return result;
|
|
966
976
|
}
|
|
@@ -2672,7 +2682,10 @@ const DEFAULT_LABELS$4 = {
|
|
|
2672
2682
|
ascending: "Ascending",
|
|
2673
2683
|
descending: "Descending",
|
|
2674
2684
|
filterByColumn: "Filter by this column",
|
|
2675
|
-
hideColumn: "Hide column"
|
|
2685
|
+
hideColumn: "Hide column",
|
|
2686
|
+
pinLeft: "Pin left",
|
|
2687
|
+
pinRight: "Pin right",
|
|
2688
|
+
unpin: "Unpin"
|
|
2676
2689
|
};
|
|
2677
2690
|
const sectionLabelClass = "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-[var(--text-tertiary)] first:pt-1";
|
|
2678
2691
|
const itemClass = "gap-2.5 rounded-md px-2.5 py-2";
|
|
@@ -2724,6 +2737,10 @@ function ColumnHeaderMenu({
|
|
|
2724
2737
|
hasFilter,
|
|
2725
2738
|
onFilterClick,
|
|
2726
2739
|
onHide,
|
|
2740
|
+
pinSide = false,
|
|
2741
|
+
onPinLeft,
|
|
2742
|
+
onPinRight,
|
|
2743
|
+
onUnpin,
|
|
2727
2744
|
labels: labelOverrides,
|
|
2728
2745
|
menuWidth = "w-[200px]"
|
|
2729
2746
|
}) {
|
|
@@ -2732,7 +2749,15 @@ function ColumnHeaderMenu({
|
|
|
2732
2749
|
const isStacked = !!primaryLabel;
|
|
2733
2750
|
const isSingleSortable = !!label && !!onSort;
|
|
2734
2751
|
const isSortable = isStacked || isSingleSortable;
|
|
2735
|
-
const
|
|
2752
|
+
const showFilterItem = Boolean(hasFilter && onFilterClick);
|
|
2753
|
+
const showHideItem = Boolean(onHide);
|
|
2754
|
+
const showPinLeftItem = Boolean(onPinLeft);
|
|
2755
|
+
const showPinRightItem = Boolean(onPinRight);
|
|
2756
|
+
const showUnpinItem = Boolean(onUnpin && pinSide);
|
|
2757
|
+
const hasPinSection = showPinLeftItem || showPinRightItem || showUnpinItem;
|
|
2758
|
+
const hasFilterOrHide = showFilterItem || showHideItem;
|
|
2759
|
+
const showSeparatorAfterSort = isSortable && (hasFilterOrHide || hasPinSection);
|
|
2760
|
+
const showSeparatorBeforePin = hasPinSection && hasFilterOrHide;
|
|
2736
2761
|
const labelContent = isStacked ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col leading-none", children: [
|
|
2737
2762
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-primary)]", children: [
|
|
2738
2763
|
primaryLabel,
|
|
@@ -2791,14 +2816,29 @@ function ColumnHeaderMenu({
|
|
|
2791
2816
|
labels
|
|
2792
2817
|
}
|
|
2793
2818
|
),
|
|
2794
|
-
|
|
2795
|
-
|
|
2819
|
+
showSeparatorAfterSort && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1 border-t border-[var(--border-subtle)]" }),
|
|
2820
|
+
showFilterItem && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { className: itemClass, onClick: onFilterClick, children: [
|
|
2796
2821
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListFilter, { className: iconClass }),
|
|
2797
2822
|
labels.filterByColumn
|
|
2798
2823
|
] }),
|
|
2799
|
-
|
|
2824
|
+
showHideItem && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { className: itemClass, onClick: onHide, children: [
|
|
2800
2825
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: iconClass }),
|
|
2801
2826
|
labels.hideColumn
|
|
2827
|
+
] }),
|
|
2828
|
+
showSeparatorBeforePin && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1 border-t border-[var(--border-subtle)]" }),
|
|
2829
|
+
showPinLeftItem && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { className: itemClass, onClick: onPinLeft, children: [
|
|
2830
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pin, { className: iconClass }),
|
|
2831
|
+
labels.pinLeft,
|
|
2832
|
+
pinSide === "left" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ml-auto h-3 w-3 text-[var(--text-tertiary)]" })
|
|
2833
|
+
] }),
|
|
2834
|
+
showPinRightItem && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { className: itemClass, onClick: onPinRight, children: [
|
|
2835
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pin, { className: `${iconClass} rotate-90` }),
|
|
2836
|
+
labels.pinRight,
|
|
2837
|
+
pinSide === "right" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ml-auto h-3 w-3 text-[var(--text-tertiary)]" })
|
|
2838
|
+
] }),
|
|
2839
|
+
showUnpinItem && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { className: itemClass, onClick: onUnpin, children: [
|
|
2840
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PinOff, { className: iconClass }),
|
|
2841
|
+
labels.unpin
|
|
2802
2842
|
] })
|
|
2803
2843
|
] })
|
|
2804
2844
|
] });
|
package/dist/tablewright.css
CHANGED
|
@@ -250,6 +250,9 @@
|
|
|
250
250
|
.collapse {
|
|
251
251
|
visibility: collapse
|
|
252
252
|
}
|
|
253
|
+
.static {
|
|
254
|
+
position: static
|
|
255
|
+
}
|
|
253
256
|
.fixed {
|
|
254
257
|
position: fixed
|
|
255
258
|
}
|
|
@@ -632,6 +635,10 @@
|
|
|
632
635
|
--tw-rotate: 180deg;
|
|
633
636
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))
|
|
634
637
|
}
|
|
638
|
+
.rotate-90 {
|
|
639
|
+
--tw-rotate: 90deg;
|
|
640
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))
|
|
641
|
+
}
|
|
635
642
|
.cursor-col-resize {
|
|
636
643
|
cursor: col-resize
|
|
637
644
|
}
|
|
@@ -6,6 +6,9 @@ export interface ColumnHeaderMenuLabels {
|
|
|
6
6
|
descending: string;
|
|
7
7
|
filterByColumn: string;
|
|
8
8
|
hideColumn: string;
|
|
9
|
+
pinLeft: string;
|
|
10
|
+
pinRight: string;
|
|
11
|
+
unpin: string;
|
|
9
12
|
}
|
|
10
13
|
interface ColumnHeaderMenuProps {
|
|
11
14
|
label?: string;
|
|
@@ -20,8 +23,12 @@ interface ColumnHeaderMenuProps {
|
|
|
20
23
|
hasFilter?: boolean;
|
|
21
24
|
onFilterClick?: () => void;
|
|
22
25
|
onHide?: () => void;
|
|
26
|
+
pinSide?: "left" | "right" | false;
|
|
27
|
+
onPinLeft?: () => void;
|
|
28
|
+
onPinRight?: () => void;
|
|
29
|
+
onUnpin?: () => void;
|
|
23
30
|
labels?: Partial<ColumnHeaderMenuLabels>;
|
|
24
31
|
menuWidth?: string;
|
|
25
32
|
}
|
|
26
|
-
export declare function ColumnHeaderMenu({ label, primaryLabel, secondaryLabel, sorted, onSort, primarySorted, onPrimarySort, secondarySorted, onSecondarySort, hasFilter, onFilterClick, onHide, labels: labelOverrides, menuWidth, }: ColumnHeaderMenuProps): import("react").JSX.Element;
|
|
33
|
+
export declare function ColumnHeaderMenu({ label, primaryLabel, secondaryLabel, sorted, onSort, primarySorted, onPrimarySort, secondarySorted, onSecondarySort, hasFilter, onFilterClick, onHide, pinSide, onPinLeft, onPinRight, onUnpin, labels: labelOverrides, menuWidth, }: ColumnHeaderMenuProps): import("react").JSX.Element;
|
|
27
34
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@undevy-org/tablewright",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "React data-table and application-shell components: filters, drawers, row controls, sortable and resizable columns, built on Radix UI and TanStack Table.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|