@ceed/ads 1.28.1 → 1.29.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/components/DataTable/components.d.ts +3 -2
- package/dist/components/DataTable/hooks.d.ts +2 -0
- package/dist/components/DataTable/styled.d.ts +1 -1
- package/dist/components/DataTable/utils.d.ts +5 -0
- package/dist/index.browser.js +4 -4
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +191 -17
- package/dist/index.js +191 -17
- package/dist/libs/text-measurer.d.ts +8 -0
- package/framer/index.js +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2089,6 +2089,36 @@ var CurrencyInput_default = CurrencyInput;
|
|
|
2089
2089
|
var import_react28 = __toESM(require("react"));
|
|
2090
2090
|
var import_react_virtual2 = require("@tanstack/react-virtual");
|
|
2091
2091
|
|
|
2092
|
+
// src/libs/text-measurer.ts
|
|
2093
|
+
var TextMeasurer = class {
|
|
2094
|
+
constructor(font) {
|
|
2095
|
+
const canvas = document.createElement("canvas");
|
|
2096
|
+
this.ctx = canvas.getContext("2d");
|
|
2097
|
+
if (this.ctx && font) this.ctx.font = font;
|
|
2098
|
+
}
|
|
2099
|
+
setFont(font) {
|
|
2100
|
+
if (this.ctx) this.ctx.font = font;
|
|
2101
|
+
return this;
|
|
2102
|
+
}
|
|
2103
|
+
setFontFromElement(el) {
|
|
2104
|
+
if (this.ctx) this.ctx.font = getComputedStyle(el).font;
|
|
2105
|
+
return this;
|
|
2106
|
+
}
|
|
2107
|
+
measureText(text) {
|
|
2108
|
+
if (!this.ctx) return 0;
|
|
2109
|
+
return this.ctx.measureText(text).width;
|
|
2110
|
+
}
|
|
2111
|
+
measureMaxWidth(values) {
|
|
2112
|
+
if (!this.ctx) return 0;
|
|
2113
|
+
let max = 0;
|
|
2114
|
+
for (let i = 0; i < values.length; i++) {
|
|
2115
|
+
const w = this.ctx.measureText(values[i]).width;
|
|
2116
|
+
if (w > max) max = w;
|
|
2117
|
+
}
|
|
2118
|
+
return max;
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2092
2122
|
// src/components/DataTable/utils.ts
|
|
2093
2123
|
function extractFieldsFromGroupingModel(items) {
|
|
2094
2124
|
const fields = /* @__PURE__ */ new Set();
|
|
@@ -2210,6 +2240,71 @@ function getTextAlign(props) {
|
|
|
2210
2240
|
return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
|
|
2211
2241
|
}
|
|
2212
2242
|
var numberFormatter = (value) => "Intl" in window ? new Intl.NumberFormat().format(value) : value;
|
|
2243
|
+
function computeHeaderWidth(headerEl) {
|
|
2244
|
+
const thStyle = getComputedStyle(headerEl);
|
|
2245
|
+
const paddingX = parseFloat(thStyle.paddingLeft) + parseFloat(thStyle.paddingRight);
|
|
2246
|
+
const borderX = parseFloat(thStyle.borderLeftWidth) + parseFloat(thStyle.borderRightWidth);
|
|
2247
|
+
const stack = headerEl.firstElementChild;
|
|
2248
|
+
if (!stack) return paddingX;
|
|
2249
|
+
const stackStyle = getComputedStyle(stack);
|
|
2250
|
+
const gap = parseFloat(stackStyle.gap) || parseFloat(stackStyle.columnGap) || 0;
|
|
2251
|
+
let totalChildWidth = 0;
|
|
2252
|
+
let visibleChildCount = 0;
|
|
2253
|
+
for (const child of Array.from(stack.children)) {
|
|
2254
|
+
const el = child;
|
|
2255
|
+
if (!el.offsetWidth && !el.offsetHeight) continue;
|
|
2256
|
+
visibleChildCount++;
|
|
2257
|
+
const textEl = el.querySelector?.('[data-slot="header-text"]') || (el.dataset?.slot === "header-text" ? el : null);
|
|
2258
|
+
if (textEl) {
|
|
2259
|
+
const htmlEl = textEl;
|
|
2260
|
+
const isMultiLine = getComputedStyle(htmlEl).display === "-webkit-box";
|
|
2261
|
+
if (isMultiLine) {
|
|
2262
|
+
const measurer = new TextMeasurer();
|
|
2263
|
+
measurer.setFontFromElement(htmlEl);
|
|
2264
|
+
totalChildWidth += measurer.measureText(htmlEl.textContent || "");
|
|
2265
|
+
} else {
|
|
2266
|
+
totalChildWidth += htmlEl.scrollWidth;
|
|
2267
|
+
}
|
|
2268
|
+
} else {
|
|
2269
|
+
totalChildWidth += el.offsetWidth;
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
const totalGaps = visibleChildCount > 1 ? (visibleChildCount - 1) * gap : 0;
|
|
2273
|
+
return totalChildWidth + totalGaps + paddingX + borderX;
|
|
2274
|
+
}
|
|
2275
|
+
function computeBodyWidth(headerEl, table, field, dataInPage) {
|
|
2276
|
+
const headId = headerEl.id;
|
|
2277
|
+
const sampleTd = headId ? table.querySelector(`tbody td[headers="${CSS.escape(headId)}"]`) : null;
|
|
2278
|
+
const styleSource = sampleTd || headerEl;
|
|
2279
|
+
const tdStyle = getComputedStyle(styleSource);
|
|
2280
|
+
const bodyPaddingX = parseFloat(tdStyle.paddingLeft) + parseFloat(tdStyle.paddingRight);
|
|
2281
|
+
const bodyBorderX = parseFloat(tdStyle.borderLeftWidth) + parseFloat(tdStyle.borderRightWidth);
|
|
2282
|
+
const measurer = new TextMeasurer();
|
|
2283
|
+
measurer.setFont(tdStyle.font);
|
|
2284
|
+
const texts = [];
|
|
2285
|
+
for (let i = 0; i < dataInPage.length; i++) {
|
|
2286
|
+
const val = dataInPage[i][field];
|
|
2287
|
+
texts.push(val == null ? "" : String(val));
|
|
2288
|
+
}
|
|
2289
|
+
const maxTextWidth = measurer.measureMaxWidth(texts);
|
|
2290
|
+
return maxTextWidth + bodyPaddingX + bodyBorderX;
|
|
2291
|
+
}
|
|
2292
|
+
function computeAutoFitWidth(params) {
|
|
2293
|
+
const { headerEl, field, dataInPage } = params;
|
|
2294
|
+
const table = headerEl.closest("table");
|
|
2295
|
+
if (!table) return null;
|
|
2296
|
+
const headerWidth = computeHeaderWidth(headerEl);
|
|
2297
|
+
const bodyWidth = computeBodyWidth(headerEl, table, field, dataInPage);
|
|
2298
|
+
let finalWidth = Math.ceil(Math.max(headerWidth, bodyWidth));
|
|
2299
|
+
const thStyle = getComputedStyle(headerEl);
|
|
2300
|
+
const resolvedMin = thStyle.minWidth;
|
|
2301
|
+
const resolvedMax = thStyle.maxWidth;
|
|
2302
|
+
const minPx = resolvedMin !== "none" ? parseFloat(resolvedMin) : NaN;
|
|
2303
|
+
const maxPx = resolvedMax !== "none" ? parseFloat(resolvedMax) : NaN;
|
|
2304
|
+
if (!isNaN(minPx) && minPx > 0) finalWidth = Math.max(finalWidth, minPx);
|
|
2305
|
+
if (!isNaN(maxPx) && maxPx > 0) finalWidth = Math.min(finalWidth, maxPx);
|
|
2306
|
+
return finalWidth;
|
|
2307
|
+
}
|
|
2213
2308
|
|
|
2214
2309
|
// src/components/DataTable/styled.tsx
|
|
2215
2310
|
var import_react19 = __toESM(require("react"));
|
|
@@ -2320,7 +2415,7 @@ var StyledTd = (0, import_joy25.styled)("td")(({ theme }) => ({
|
|
|
2320
2415
|
var MotionSortIcon = (0, import_framer_motion17.motion)(import_ArrowUpwardRounded.default);
|
|
2321
2416
|
var DefaultLoadingOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.LinearProgress, { value: 8, variant: "plain" });
|
|
2322
2417
|
var DefaultNoRowsOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.Typography, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
|
|
2323
|
-
var Resizer = (ref, targetRef = ref, onResizeStateChange) => /* @__PURE__ */ import_react19.default.createElement(
|
|
2418
|
+
var Resizer = (ref, targetRef = ref, onResizeStateChange, onAutoFit) => /* @__PURE__ */ import_react19.default.createElement(
|
|
2324
2419
|
Box_default,
|
|
2325
2420
|
{
|
|
2326
2421
|
sx: {
|
|
@@ -2328,24 +2423,67 @@ var Resizer = (ref, targetRef = ref, onResizeStateChange) => /* @__PURE__ */ imp
|
|
|
2328
2423
|
top: 0,
|
|
2329
2424
|
right: 0,
|
|
2330
2425
|
bottom: 0,
|
|
2331
|
-
width: "
|
|
2332
|
-
cursor: "col-resize"
|
|
2426
|
+
width: "7px",
|
|
2427
|
+
cursor: "col-resize",
|
|
2428
|
+
"&::after": {
|
|
2429
|
+
content: '""',
|
|
2430
|
+
position: "absolute",
|
|
2431
|
+
top: 0,
|
|
2432
|
+
bottom: 0,
|
|
2433
|
+
right: 0,
|
|
2434
|
+
width: "2px",
|
|
2435
|
+
bgcolor: "transparent",
|
|
2436
|
+
transition: "background-color 150ms ease"
|
|
2437
|
+
},
|
|
2438
|
+
"&:hover::after": {
|
|
2439
|
+
bgcolor: "primary.300"
|
|
2440
|
+
},
|
|
2441
|
+
"&[data-resizing]::after": {
|
|
2442
|
+
bgcolor: "primary.500"
|
|
2443
|
+
}
|
|
2333
2444
|
},
|
|
2334
2445
|
onClick: (e) => e.stopPropagation(),
|
|
2446
|
+
onDoubleClick: (e) => {
|
|
2447
|
+
e.stopPropagation();
|
|
2448
|
+
e.preventDefault();
|
|
2449
|
+
onAutoFit?.();
|
|
2450
|
+
},
|
|
2335
2451
|
onMouseDown: (e) => {
|
|
2452
|
+
if (e.detail >= 2) return;
|
|
2453
|
+
const resizerEl = e.currentTarget;
|
|
2454
|
+
resizerEl.dataset.resizing = "";
|
|
2336
2455
|
const initialX = e.clientX;
|
|
2337
2456
|
const initialWidth = ref.current?.getBoundingClientRect().width;
|
|
2338
|
-
|
|
2457
|
+
let activated = false;
|
|
2458
|
+
const DRAG_THRESHOLD = 3;
|
|
2459
|
+
const thStyle = ref.current ? getComputedStyle(ref.current) : null;
|
|
2460
|
+
const minW = thStyle ? parseFloat(thStyle.minWidth) : NaN;
|
|
2461
|
+
const maxW = thStyle ? parseFloat(thStyle.maxWidth) : NaN;
|
|
2339
2462
|
const onMouseMove = (e2) => {
|
|
2340
|
-
if (initialWidth
|
|
2341
|
-
|
|
2342
|
-
|
|
2463
|
+
if (!initialWidth) return;
|
|
2464
|
+
const delta = e2.clientX - initialX;
|
|
2465
|
+
if (!activated) {
|
|
2466
|
+
if (Math.abs(delta) < DRAG_THRESHOLD) return;
|
|
2467
|
+
activated = true;
|
|
2468
|
+
onResizeStateChange?.(true);
|
|
2343
2469
|
}
|
|
2470
|
+
if (!ref.current || !targetRef.current) {
|
|
2471
|
+
onMouseUp();
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
let newWidth = initialWidth + delta;
|
|
2475
|
+
if (!isNaN(minW) && minW > 0) newWidth = Math.max(newWidth, minW);
|
|
2476
|
+
if (!isNaN(maxW) && maxW > 0) newWidth = Math.min(newWidth, maxW);
|
|
2477
|
+
ref.current.style.width = `${newWidth}px`;
|
|
2478
|
+
targetRef.current.style.width = `${newWidth}px`;
|
|
2344
2479
|
};
|
|
2345
2480
|
const onMouseUp = () => {
|
|
2481
|
+
resizerEl.removeAttribute("data-resizing");
|
|
2346
2482
|
document.removeEventListener("mousemove", onMouseMove);
|
|
2347
2483
|
document.removeEventListener("mouseup", onMouseUp);
|
|
2348
|
-
|
|
2484
|
+
if (activated) {
|
|
2485
|
+
requestAnimationFrame(() => onResizeStateChange?.(false));
|
|
2486
|
+
}
|
|
2349
2487
|
};
|
|
2350
2488
|
document.addEventListener("mousemove", onMouseMove);
|
|
2351
2489
|
document.addEventListener("mouseup", onMouseUp);
|
|
@@ -2918,7 +3056,11 @@ function InfoSign(props) {
|
|
|
2918
3056
|
var InfoSign_default = InfoSign;
|
|
2919
3057
|
|
|
2920
3058
|
// src/components/DataTable/components.tsx
|
|
2921
|
-
var TextEllipsis = ({
|
|
3059
|
+
var TextEllipsis = ({
|
|
3060
|
+
children,
|
|
3061
|
+
lineClamp,
|
|
3062
|
+
...rest
|
|
3063
|
+
}) => {
|
|
2922
3064
|
const textRef = (0, import_react24.useRef)(null);
|
|
2923
3065
|
const [showTooltip, setShowTooltip] = (0, import_react24.useState)(false);
|
|
2924
3066
|
(0, import_react24.useLayoutEffect)(() => {
|
|
@@ -2933,7 +3075,7 @@ var TextEllipsis = ({ children, lineClamp }) => {
|
|
|
2933
3075
|
ro.observe(element);
|
|
2934
3076
|
return () => ro.disconnect();
|
|
2935
3077
|
}, [children, lineClamp]);
|
|
2936
|
-
return /* @__PURE__ */ import_react24.default.createElement(Tooltip_default, { title: showTooltip ? children : "", placement: "top" }, /* @__PURE__ */ import_react24.default.createElement(EllipsisDiv, { ref: textRef, lineClamp }, children));
|
|
3078
|
+
return /* @__PURE__ */ import_react24.default.createElement(Tooltip_default, { title: showTooltip ? children : "", placement: "top" }, /* @__PURE__ */ import_react24.default.createElement(EllipsisDiv, { ref: textRef, lineClamp, ...rest }, children));
|
|
2937
3079
|
};
|
|
2938
3080
|
var CellTextEllipsis = ({ children }) => {
|
|
2939
3081
|
const textRef = (0, import_react24.useRef)(null);
|
|
@@ -2985,11 +3127,16 @@ var HeadCell = (props) => {
|
|
|
2985
3127
|
headerRef,
|
|
2986
3128
|
tableColRef,
|
|
2987
3129
|
headerClassName,
|
|
2988
|
-
headerLineClamp
|
|
3130
|
+
headerLineClamp,
|
|
3131
|
+
onAutoFit
|
|
2989
3132
|
} = props;
|
|
2990
3133
|
const theme = (0, import_joy32.useTheme)();
|
|
2991
3134
|
const ref = headerRef;
|
|
2992
3135
|
const colRef = tableColRef;
|
|
3136
|
+
const localRef = (0, import_react24.useRef)(null);
|
|
3137
|
+
(0, import_react24.useLayoutEffect)(() => {
|
|
3138
|
+
ref.current = localRef.current;
|
|
3139
|
+
}, [ref]);
|
|
2993
3140
|
const [isHovered, setIsHovered] = (0, import_react24.useState)(false);
|
|
2994
3141
|
const sortable = type === "actions" ? false : _sortable;
|
|
2995
3142
|
const headId = (0, import_react24.useMemo)(
|
|
@@ -2998,10 +3145,15 @@ var HeadCell = (props) => {
|
|
|
2998
3145
|
);
|
|
2999
3146
|
const isResizingRef = (0, import_react24.useRef)(false);
|
|
3000
3147
|
const resizer = (0, import_react24.useMemo)(
|
|
3001
|
-
() => resizable ?? true ? Resizer(
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3148
|
+
() => resizable ?? true ? Resizer(
|
|
3149
|
+
ref,
|
|
3150
|
+
colRef,
|
|
3151
|
+
(isResizing) => {
|
|
3152
|
+
isResizingRef.current = isResizing;
|
|
3153
|
+
},
|
|
3154
|
+
onAutoFit ? () => onAutoFit(field) : void 0
|
|
3155
|
+
) : null,
|
|
3156
|
+
[resizable, ref, colRef, onAutoFit, field]
|
|
3005
3157
|
);
|
|
3006
3158
|
const style = (0, import_react24.useMemo)(
|
|
3007
3159
|
() => ({
|
|
@@ -3072,7 +3224,7 @@ var HeadCell = (props) => {
|
|
|
3072
3224
|
id: headId,
|
|
3073
3225
|
"aria-label": headerName ?? field,
|
|
3074
3226
|
"aria-sort": sort ? { asc: "ascending", desc: "descending" }[sort] : "none",
|
|
3075
|
-
ref,
|
|
3227
|
+
ref: localRef,
|
|
3076
3228
|
key: field,
|
|
3077
3229
|
style,
|
|
3078
3230
|
onClick: (0, import_react24.useCallback)(
|
|
@@ -3089,7 +3241,7 @@ var HeadCell = (props) => {
|
|
|
3089
3241
|
initial: "initial",
|
|
3090
3242
|
className: computedHeaderClassName
|
|
3091
3243
|
},
|
|
3092
|
-
/* @__PURE__ */ import_react24.default.createElement(Stack_default, { gap: 1, direction: "row", justifyContent: textAlign, alignItems: "center", sx: { minWidth: 0 } }, textAlign === "end" && sortIcon, textAlign === "end" && infoSign, /* @__PURE__ */ import_react24.default.createElement(TextEllipsis, { lineClamp: headerLineClamp }, headerName ?? field, editMode && required && /* @__PURE__ */ import_react24.default.createElement(Asterisk, null, "*")), textAlign === "start" && infoSign, textAlign === "start" && sortIcon),
|
|
3244
|
+
/* @__PURE__ */ import_react24.default.createElement(Stack_default, { gap: 1, direction: "row", justifyContent: textAlign, alignItems: "center", sx: { minWidth: 0 } }, textAlign === "end" && sortIcon, textAlign === "end" && infoSign, /* @__PURE__ */ import_react24.default.createElement(TextEllipsis, { lineClamp: headerLineClamp, "data-slot": "header-text" }, headerName ?? field, editMode && required && /* @__PURE__ */ import_react24.default.createElement(Asterisk, null, "*")), textAlign === "start" && infoSign, textAlign === "start" && sortIcon),
|
|
3093
3245
|
resizer
|
|
3094
3246
|
);
|
|
3095
3247
|
};
|
|
@@ -3636,6 +3788,25 @@ function useDataTableRenderer({
|
|
|
3636
3788
|
prevRowsRef.current = _rows;
|
|
3637
3789
|
}
|
|
3638
3790
|
}, [_rows]);
|
|
3791
|
+
const handleAutoFit = (0, import_react25.useCallback)(
|
|
3792
|
+
(field) => {
|
|
3793
|
+
const colDef = visibleColumnsByField[field];
|
|
3794
|
+
if (!colDef?.headerRef.current) return;
|
|
3795
|
+
const column = allColumnsByField[field];
|
|
3796
|
+
const columnType = column && "type" in column ? column.type : void 0;
|
|
3797
|
+
if (columnType === "actions") return;
|
|
3798
|
+
const optimalWidth = computeAutoFitWidth({
|
|
3799
|
+
headerEl: colDef.headerRef.current,
|
|
3800
|
+
field,
|
|
3801
|
+
dataInPage
|
|
3802
|
+
});
|
|
3803
|
+
if (optimalWidth == null) return;
|
|
3804
|
+
const widthPx = `${optimalWidth}px`;
|
|
3805
|
+
colDef.headerRef.current.style.width = widthPx;
|
|
3806
|
+
if (colDef.tableColRef.current) colDef.tableColRef.current.style.width = widthPx;
|
|
3807
|
+
},
|
|
3808
|
+
[visibleColumnsByField, allColumnsByField, dataInPage]
|
|
3809
|
+
);
|
|
3639
3810
|
return {
|
|
3640
3811
|
rowCount,
|
|
3641
3812
|
selectableRowCount,
|
|
@@ -3647,6 +3818,7 @@ function useDataTableRenderer({
|
|
|
3647
3818
|
BodyRow,
|
|
3648
3819
|
dataInPage,
|
|
3649
3820
|
handleSortChange,
|
|
3821
|
+
handleAutoFit,
|
|
3650
3822
|
isAllSelected,
|
|
3651
3823
|
isTotalSelected,
|
|
3652
3824
|
isSelectedRow: (0, import_react25.useCallback)((model) => selectedModelSet.has(model), [selectedModelSet]),
|
|
@@ -4077,6 +4249,7 @@ function Component(props, apiRef) {
|
|
|
4077
4249
|
pageSize,
|
|
4078
4250
|
onPaginationModelChange,
|
|
4079
4251
|
handleSortChange,
|
|
4252
|
+
handleAutoFit,
|
|
4080
4253
|
dataInPage,
|
|
4081
4254
|
isTotalSelected,
|
|
4082
4255
|
focusedRowId,
|
|
@@ -4355,6 +4528,7 @@ function Component(props, apiRef) {
|
|
|
4355
4528
|
stickyHeader: props.stickyHeader,
|
|
4356
4529
|
editMode: !!c.isCellEditable,
|
|
4357
4530
|
onSortChange: handleSortChange,
|
|
4531
|
+
onAutoFit: handleAutoFit,
|
|
4358
4532
|
...c
|
|
4359
4533
|
}
|
|
4360
4534
|
)
|
package/dist/index.js
CHANGED
|
@@ -1955,6 +1955,36 @@ import React25, {
|
|
|
1955
1955
|
} from "react";
|
|
1956
1956
|
import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
|
|
1957
1957
|
|
|
1958
|
+
// src/libs/text-measurer.ts
|
|
1959
|
+
var TextMeasurer = class {
|
|
1960
|
+
constructor(font) {
|
|
1961
|
+
const canvas = document.createElement("canvas");
|
|
1962
|
+
this.ctx = canvas.getContext("2d");
|
|
1963
|
+
if (this.ctx && font) this.ctx.font = font;
|
|
1964
|
+
}
|
|
1965
|
+
setFont(font) {
|
|
1966
|
+
if (this.ctx) this.ctx.font = font;
|
|
1967
|
+
return this;
|
|
1968
|
+
}
|
|
1969
|
+
setFontFromElement(el) {
|
|
1970
|
+
if (this.ctx) this.ctx.font = getComputedStyle(el).font;
|
|
1971
|
+
return this;
|
|
1972
|
+
}
|
|
1973
|
+
measureText(text) {
|
|
1974
|
+
if (!this.ctx) return 0;
|
|
1975
|
+
return this.ctx.measureText(text).width;
|
|
1976
|
+
}
|
|
1977
|
+
measureMaxWidth(values) {
|
|
1978
|
+
if (!this.ctx) return 0;
|
|
1979
|
+
let max = 0;
|
|
1980
|
+
for (let i = 0; i < values.length; i++) {
|
|
1981
|
+
const w = this.ctx.measureText(values[i]).width;
|
|
1982
|
+
if (w > max) max = w;
|
|
1983
|
+
}
|
|
1984
|
+
return max;
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
|
|
1958
1988
|
// src/components/DataTable/utils.ts
|
|
1959
1989
|
function extractFieldsFromGroupingModel(items) {
|
|
1960
1990
|
const fields = /* @__PURE__ */ new Set();
|
|
@@ -2076,6 +2106,71 @@ function getTextAlign(props) {
|
|
|
2076
2106
|
return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
|
|
2077
2107
|
}
|
|
2078
2108
|
var numberFormatter = (value) => "Intl" in window ? new Intl.NumberFormat().format(value) : value;
|
|
2109
|
+
function computeHeaderWidth(headerEl) {
|
|
2110
|
+
const thStyle = getComputedStyle(headerEl);
|
|
2111
|
+
const paddingX = parseFloat(thStyle.paddingLeft) + parseFloat(thStyle.paddingRight);
|
|
2112
|
+
const borderX = parseFloat(thStyle.borderLeftWidth) + parseFloat(thStyle.borderRightWidth);
|
|
2113
|
+
const stack = headerEl.firstElementChild;
|
|
2114
|
+
if (!stack) return paddingX;
|
|
2115
|
+
const stackStyle = getComputedStyle(stack);
|
|
2116
|
+
const gap = parseFloat(stackStyle.gap) || parseFloat(stackStyle.columnGap) || 0;
|
|
2117
|
+
let totalChildWidth = 0;
|
|
2118
|
+
let visibleChildCount = 0;
|
|
2119
|
+
for (const child of Array.from(stack.children)) {
|
|
2120
|
+
const el = child;
|
|
2121
|
+
if (!el.offsetWidth && !el.offsetHeight) continue;
|
|
2122
|
+
visibleChildCount++;
|
|
2123
|
+
const textEl = el.querySelector?.('[data-slot="header-text"]') || (el.dataset?.slot === "header-text" ? el : null);
|
|
2124
|
+
if (textEl) {
|
|
2125
|
+
const htmlEl = textEl;
|
|
2126
|
+
const isMultiLine = getComputedStyle(htmlEl).display === "-webkit-box";
|
|
2127
|
+
if (isMultiLine) {
|
|
2128
|
+
const measurer = new TextMeasurer();
|
|
2129
|
+
measurer.setFontFromElement(htmlEl);
|
|
2130
|
+
totalChildWidth += measurer.measureText(htmlEl.textContent || "");
|
|
2131
|
+
} else {
|
|
2132
|
+
totalChildWidth += htmlEl.scrollWidth;
|
|
2133
|
+
}
|
|
2134
|
+
} else {
|
|
2135
|
+
totalChildWidth += el.offsetWidth;
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
const totalGaps = visibleChildCount > 1 ? (visibleChildCount - 1) * gap : 0;
|
|
2139
|
+
return totalChildWidth + totalGaps + paddingX + borderX;
|
|
2140
|
+
}
|
|
2141
|
+
function computeBodyWidth(headerEl, table, field, dataInPage) {
|
|
2142
|
+
const headId = headerEl.id;
|
|
2143
|
+
const sampleTd = headId ? table.querySelector(`tbody td[headers="${CSS.escape(headId)}"]`) : null;
|
|
2144
|
+
const styleSource = sampleTd || headerEl;
|
|
2145
|
+
const tdStyle = getComputedStyle(styleSource);
|
|
2146
|
+
const bodyPaddingX = parseFloat(tdStyle.paddingLeft) + parseFloat(tdStyle.paddingRight);
|
|
2147
|
+
const bodyBorderX = parseFloat(tdStyle.borderLeftWidth) + parseFloat(tdStyle.borderRightWidth);
|
|
2148
|
+
const measurer = new TextMeasurer();
|
|
2149
|
+
measurer.setFont(tdStyle.font);
|
|
2150
|
+
const texts = [];
|
|
2151
|
+
for (let i = 0; i < dataInPage.length; i++) {
|
|
2152
|
+
const val = dataInPage[i][field];
|
|
2153
|
+
texts.push(val == null ? "" : String(val));
|
|
2154
|
+
}
|
|
2155
|
+
const maxTextWidth = measurer.measureMaxWidth(texts);
|
|
2156
|
+
return maxTextWidth + bodyPaddingX + bodyBorderX;
|
|
2157
|
+
}
|
|
2158
|
+
function computeAutoFitWidth(params) {
|
|
2159
|
+
const { headerEl, field, dataInPage } = params;
|
|
2160
|
+
const table = headerEl.closest("table");
|
|
2161
|
+
if (!table) return null;
|
|
2162
|
+
const headerWidth = computeHeaderWidth(headerEl);
|
|
2163
|
+
const bodyWidth = computeBodyWidth(headerEl, table, field, dataInPage);
|
|
2164
|
+
let finalWidth = Math.ceil(Math.max(headerWidth, bodyWidth));
|
|
2165
|
+
const thStyle = getComputedStyle(headerEl);
|
|
2166
|
+
const resolvedMin = thStyle.minWidth;
|
|
2167
|
+
const resolvedMax = thStyle.maxWidth;
|
|
2168
|
+
const minPx = resolvedMin !== "none" ? parseFloat(resolvedMin) : NaN;
|
|
2169
|
+
const maxPx = resolvedMax !== "none" ? parseFloat(resolvedMax) : NaN;
|
|
2170
|
+
if (!isNaN(minPx) && minPx > 0) finalWidth = Math.max(finalWidth, minPx);
|
|
2171
|
+
if (!isNaN(maxPx) && maxPx > 0) finalWidth = Math.min(finalWidth, maxPx);
|
|
2172
|
+
return finalWidth;
|
|
2173
|
+
}
|
|
2079
2174
|
|
|
2080
2175
|
// src/components/DataTable/styled.tsx
|
|
2081
2176
|
import React17 from "react";
|
|
@@ -2186,7 +2281,7 @@ var StyledTd = styled8("td")(({ theme }) => ({
|
|
|
2186
2281
|
var MotionSortIcon = motion17(SortIcon);
|
|
2187
2282
|
var DefaultLoadingOverlay = () => /* @__PURE__ */ React17.createElement(LinearProgress, { value: 8, variant: "plain" });
|
|
2188
2283
|
var DefaultNoRowsOverlay = () => /* @__PURE__ */ React17.createElement(Typography3, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
|
|
2189
|
-
var Resizer = (ref, targetRef = ref, onResizeStateChange) => /* @__PURE__ */ React17.createElement(
|
|
2284
|
+
var Resizer = (ref, targetRef = ref, onResizeStateChange, onAutoFit) => /* @__PURE__ */ React17.createElement(
|
|
2190
2285
|
Box_default,
|
|
2191
2286
|
{
|
|
2192
2287
|
sx: {
|
|
@@ -2194,24 +2289,67 @@ var Resizer = (ref, targetRef = ref, onResizeStateChange) => /* @__PURE__ */ Rea
|
|
|
2194
2289
|
top: 0,
|
|
2195
2290
|
right: 0,
|
|
2196
2291
|
bottom: 0,
|
|
2197
|
-
width: "
|
|
2198
|
-
cursor: "col-resize"
|
|
2292
|
+
width: "7px",
|
|
2293
|
+
cursor: "col-resize",
|
|
2294
|
+
"&::after": {
|
|
2295
|
+
content: '""',
|
|
2296
|
+
position: "absolute",
|
|
2297
|
+
top: 0,
|
|
2298
|
+
bottom: 0,
|
|
2299
|
+
right: 0,
|
|
2300
|
+
width: "2px",
|
|
2301
|
+
bgcolor: "transparent",
|
|
2302
|
+
transition: "background-color 150ms ease"
|
|
2303
|
+
},
|
|
2304
|
+
"&:hover::after": {
|
|
2305
|
+
bgcolor: "primary.300"
|
|
2306
|
+
},
|
|
2307
|
+
"&[data-resizing]::after": {
|
|
2308
|
+
bgcolor: "primary.500"
|
|
2309
|
+
}
|
|
2199
2310
|
},
|
|
2200
2311
|
onClick: (e) => e.stopPropagation(),
|
|
2312
|
+
onDoubleClick: (e) => {
|
|
2313
|
+
e.stopPropagation();
|
|
2314
|
+
e.preventDefault();
|
|
2315
|
+
onAutoFit?.();
|
|
2316
|
+
},
|
|
2201
2317
|
onMouseDown: (e) => {
|
|
2318
|
+
if (e.detail >= 2) return;
|
|
2319
|
+
const resizerEl = e.currentTarget;
|
|
2320
|
+
resizerEl.dataset.resizing = "";
|
|
2202
2321
|
const initialX = e.clientX;
|
|
2203
2322
|
const initialWidth = ref.current?.getBoundingClientRect().width;
|
|
2204
|
-
|
|
2323
|
+
let activated = false;
|
|
2324
|
+
const DRAG_THRESHOLD = 3;
|
|
2325
|
+
const thStyle = ref.current ? getComputedStyle(ref.current) : null;
|
|
2326
|
+
const minW = thStyle ? parseFloat(thStyle.minWidth) : NaN;
|
|
2327
|
+
const maxW = thStyle ? parseFloat(thStyle.maxWidth) : NaN;
|
|
2205
2328
|
const onMouseMove = (e2) => {
|
|
2206
|
-
if (initialWidth
|
|
2207
|
-
|
|
2208
|
-
|
|
2329
|
+
if (!initialWidth) return;
|
|
2330
|
+
const delta = e2.clientX - initialX;
|
|
2331
|
+
if (!activated) {
|
|
2332
|
+
if (Math.abs(delta) < DRAG_THRESHOLD) return;
|
|
2333
|
+
activated = true;
|
|
2334
|
+
onResizeStateChange?.(true);
|
|
2209
2335
|
}
|
|
2336
|
+
if (!ref.current || !targetRef.current) {
|
|
2337
|
+
onMouseUp();
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
let newWidth = initialWidth + delta;
|
|
2341
|
+
if (!isNaN(minW) && minW > 0) newWidth = Math.max(newWidth, minW);
|
|
2342
|
+
if (!isNaN(maxW) && maxW > 0) newWidth = Math.min(newWidth, maxW);
|
|
2343
|
+
ref.current.style.width = `${newWidth}px`;
|
|
2344
|
+
targetRef.current.style.width = `${newWidth}px`;
|
|
2210
2345
|
};
|
|
2211
2346
|
const onMouseUp = () => {
|
|
2347
|
+
resizerEl.removeAttribute("data-resizing");
|
|
2212
2348
|
document.removeEventListener("mousemove", onMouseMove);
|
|
2213
2349
|
document.removeEventListener("mouseup", onMouseUp);
|
|
2214
|
-
|
|
2350
|
+
if (activated) {
|
|
2351
|
+
requestAnimationFrame(() => onResizeStateChange?.(false));
|
|
2352
|
+
}
|
|
2215
2353
|
};
|
|
2216
2354
|
document.addEventListener("mousemove", onMouseMove);
|
|
2217
2355
|
document.addEventListener("mouseup", onMouseUp);
|
|
@@ -2793,7 +2931,11 @@ function InfoSign(props) {
|
|
|
2793
2931
|
var InfoSign_default = InfoSign;
|
|
2794
2932
|
|
|
2795
2933
|
// src/components/DataTable/components.tsx
|
|
2796
|
-
var TextEllipsis = ({
|
|
2934
|
+
var TextEllipsis = ({
|
|
2935
|
+
children,
|
|
2936
|
+
lineClamp,
|
|
2937
|
+
...rest
|
|
2938
|
+
}) => {
|
|
2797
2939
|
const textRef = useRef5(null);
|
|
2798
2940
|
const [showTooltip, setShowTooltip] = useState8(false);
|
|
2799
2941
|
useLayoutEffect(() => {
|
|
@@ -2808,7 +2950,7 @@ var TextEllipsis = ({ children, lineClamp }) => {
|
|
|
2808
2950
|
ro.observe(element);
|
|
2809
2951
|
return () => ro.disconnect();
|
|
2810
2952
|
}, [children, lineClamp]);
|
|
2811
|
-
return /* @__PURE__ */ React22.createElement(Tooltip_default, { title: showTooltip ? children : "", placement: "top" }, /* @__PURE__ */ React22.createElement(EllipsisDiv, { ref: textRef, lineClamp }, children));
|
|
2953
|
+
return /* @__PURE__ */ React22.createElement(Tooltip_default, { title: showTooltip ? children : "", placement: "top" }, /* @__PURE__ */ React22.createElement(EllipsisDiv, { ref: textRef, lineClamp, ...rest }, children));
|
|
2812
2954
|
};
|
|
2813
2955
|
var CellTextEllipsis = ({ children }) => {
|
|
2814
2956
|
const textRef = useRef5(null);
|
|
@@ -2860,11 +3002,16 @@ var HeadCell = (props) => {
|
|
|
2860
3002
|
headerRef,
|
|
2861
3003
|
tableColRef,
|
|
2862
3004
|
headerClassName,
|
|
2863
|
-
headerLineClamp
|
|
3005
|
+
headerLineClamp,
|
|
3006
|
+
onAutoFit
|
|
2864
3007
|
} = props;
|
|
2865
3008
|
const theme = useTheme();
|
|
2866
3009
|
const ref = headerRef;
|
|
2867
3010
|
const colRef = tableColRef;
|
|
3011
|
+
const localRef = useRef5(null);
|
|
3012
|
+
useLayoutEffect(() => {
|
|
3013
|
+
ref.current = localRef.current;
|
|
3014
|
+
}, [ref]);
|
|
2868
3015
|
const [isHovered, setIsHovered] = useState8(false);
|
|
2869
3016
|
const sortable = type === "actions" ? false : _sortable;
|
|
2870
3017
|
const headId = useMemo8(
|
|
@@ -2873,10 +3020,15 @@ var HeadCell = (props) => {
|
|
|
2873
3020
|
);
|
|
2874
3021
|
const isResizingRef = useRef5(false);
|
|
2875
3022
|
const resizer = useMemo8(
|
|
2876
|
-
() => resizable ?? true ? Resizer(
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
3023
|
+
() => resizable ?? true ? Resizer(
|
|
3024
|
+
ref,
|
|
3025
|
+
colRef,
|
|
3026
|
+
(isResizing) => {
|
|
3027
|
+
isResizingRef.current = isResizing;
|
|
3028
|
+
},
|
|
3029
|
+
onAutoFit ? () => onAutoFit(field) : void 0
|
|
3030
|
+
) : null,
|
|
3031
|
+
[resizable, ref, colRef, onAutoFit, field]
|
|
2880
3032
|
);
|
|
2881
3033
|
const style = useMemo8(
|
|
2882
3034
|
() => ({
|
|
@@ -2947,7 +3099,7 @@ var HeadCell = (props) => {
|
|
|
2947
3099
|
id: headId,
|
|
2948
3100
|
"aria-label": headerName ?? field,
|
|
2949
3101
|
"aria-sort": sort ? { asc: "ascending", desc: "descending" }[sort] : "none",
|
|
2950
|
-
ref,
|
|
3102
|
+
ref: localRef,
|
|
2951
3103
|
key: field,
|
|
2952
3104
|
style,
|
|
2953
3105
|
onClick: useCallback9(
|
|
@@ -2964,7 +3116,7 @@ var HeadCell = (props) => {
|
|
|
2964
3116
|
initial: "initial",
|
|
2965
3117
|
className: computedHeaderClassName
|
|
2966
3118
|
},
|
|
2967
|
-
/* @__PURE__ */ React22.createElement(Stack_default, { gap: 1, direction: "row", justifyContent: textAlign, alignItems: "center", sx: { minWidth: 0 } }, textAlign === "end" && sortIcon, textAlign === "end" && infoSign, /* @__PURE__ */ React22.createElement(TextEllipsis, { lineClamp: headerLineClamp }, headerName ?? field, editMode && required && /* @__PURE__ */ React22.createElement(Asterisk, null, "*")), textAlign === "start" && infoSign, textAlign === "start" && sortIcon),
|
|
3119
|
+
/* @__PURE__ */ React22.createElement(Stack_default, { gap: 1, direction: "row", justifyContent: textAlign, alignItems: "center", sx: { minWidth: 0 } }, textAlign === "end" && sortIcon, textAlign === "end" && infoSign, /* @__PURE__ */ React22.createElement(TextEllipsis, { lineClamp: headerLineClamp, "data-slot": "header-text" }, headerName ?? field, editMode && required && /* @__PURE__ */ React22.createElement(Asterisk, null, "*")), textAlign === "start" && infoSign, textAlign === "start" && sortIcon),
|
|
2968
3120
|
resizer
|
|
2969
3121
|
);
|
|
2970
3122
|
};
|
|
@@ -3511,6 +3663,25 @@ function useDataTableRenderer({
|
|
|
3511
3663
|
prevRowsRef.current = _rows;
|
|
3512
3664
|
}
|
|
3513
3665
|
}, [_rows]);
|
|
3666
|
+
const handleAutoFit = useCallback10(
|
|
3667
|
+
(field) => {
|
|
3668
|
+
const colDef = visibleColumnsByField[field];
|
|
3669
|
+
if (!colDef?.headerRef.current) return;
|
|
3670
|
+
const column = allColumnsByField[field];
|
|
3671
|
+
const columnType = column && "type" in column ? column.type : void 0;
|
|
3672
|
+
if (columnType === "actions") return;
|
|
3673
|
+
const optimalWidth = computeAutoFitWidth({
|
|
3674
|
+
headerEl: colDef.headerRef.current,
|
|
3675
|
+
field,
|
|
3676
|
+
dataInPage
|
|
3677
|
+
});
|
|
3678
|
+
if (optimalWidth == null) return;
|
|
3679
|
+
const widthPx = `${optimalWidth}px`;
|
|
3680
|
+
colDef.headerRef.current.style.width = widthPx;
|
|
3681
|
+
if (colDef.tableColRef.current) colDef.tableColRef.current.style.width = widthPx;
|
|
3682
|
+
},
|
|
3683
|
+
[visibleColumnsByField, allColumnsByField, dataInPage]
|
|
3684
|
+
);
|
|
3514
3685
|
return {
|
|
3515
3686
|
rowCount,
|
|
3516
3687
|
selectableRowCount,
|
|
@@ -3522,6 +3693,7 @@ function useDataTableRenderer({
|
|
|
3522
3693
|
BodyRow,
|
|
3523
3694
|
dataInPage,
|
|
3524
3695
|
handleSortChange,
|
|
3696
|
+
handleAutoFit,
|
|
3525
3697
|
isAllSelected,
|
|
3526
3698
|
isTotalSelected,
|
|
3527
3699
|
isSelectedRow: useCallback10((model) => selectedModelSet.has(model), [selectedModelSet]),
|
|
@@ -3952,6 +4124,7 @@ function Component(props, apiRef) {
|
|
|
3952
4124
|
pageSize,
|
|
3953
4125
|
onPaginationModelChange,
|
|
3954
4126
|
handleSortChange,
|
|
4127
|
+
handleAutoFit,
|
|
3955
4128
|
dataInPage,
|
|
3956
4129
|
isTotalSelected,
|
|
3957
4130
|
focusedRowId,
|
|
@@ -4230,6 +4403,7 @@ function Component(props, apiRef) {
|
|
|
4230
4403
|
stickyHeader: props.stickyHeader,
|
|
4231
4404
|
editMode: !!c.isCellEditable,
|
|
4232
4405
|
onSortChange: handleSortChange,
|
|
4406
|
+
onAutoFit: handleAutoFit,
|
|
4233
4407
|
...c
|
|
4234
4408
|
}
|
|
4235
4409
|
)
|