sellmate-design-system-react 9.0.0-beta.41 → 9.0.0-beta.43
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/SGuide/README.md +1 -1
- package/dist/components/SGuide/SGuide.d.ts +5 -2
- package/dist/index.cjs +105 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +105 -28
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +1 -1
- package/dist/styles.css +6 -0
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| `message?` | `SGuideMessage` | `''` | 팝업 메시지 (배열이면 리스트, 중첩 배열이면 depth 표현) |
|
|
14
14
|
| `url?` | `string` | `''` | notion 타입 클릭 시 이동 URL |
|
|
15
15
|
| `popupTitle?` | `string` | `''` | 팝업 제목 (없으면 type 기본값) |
|
|
16
|
-
| `popupWidth?` | `number` |
|
|
16
|
+
| `popupWidth?` | `number \| 'auto'` | `'auto'` | 팝업 너비. 기본 `'auto'` 는 내용 폭에 맞춘다 — 가장 긴 줄이 곧 팝업 폭이다. 숫자(px)를 주면 그 폭으로 고정한다. 어느 쪽이든 창 좌우에 여백을 남기는 선까지만 벌어진다. |
|
|
17
17
|
| `className?` | `string` | — | |
|
|
18
18
|
| `style?` | `CSSProperties` | — | |
|
|
19
19
|
|
|
@@ -13,8 +13,11 @@ export interface SGuideProps {
|
|
|
13
13
|
url?: string;
|
|
14
14
|
/** 팝업 제목 (없으면 type 기본값) */
|
|
15
15
|
popupTitle?: string;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* 팝업 너비. 기본 `'auto'` 는 내용 폭에 맞춘다 — 가장 긴 줄이 곧 팝업 폭이다.
|
|
18
|
+
* 숫자(px)를 주면 그 폭으로 고정한다. 어느 쪽이든 창 좌우에 여백을 남기는 선까지만 벌어진다.
|
|
19
|
+
*/
|
|
20
|
+
popupWidth?: number | 'auto';
|
|
18
21
|
className?: string;
|
|
19
22
|
style?: CSSProperties;
|
|
20
23
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -5103,7 +5103,11 @@ var STag = /* @__PURE__ */ react.forwardRef(function STag2({
|
|
|
5103
5103
|
...rest,
|
|
5104
5104
|
children: [
|
|
5105
5105
|
icon && iconLeft && iconNode,
|
|
5106
|
-
label &&
|
|
5106
|
+
label && // leading-none: 태그는 min-height 로 높이가 정해지고 flex 가 세로 중앙 정렬하므로
|
|
5107
|
+
// 레이블에 line-height 가 필요 없다. 오히려 line-height 를 주면 브라우저가
|
|
5108
|
+
// 폰트 ascent/descent 를 정수 px 로 반올림한 뒤 남는 half-leading 을 내림 처리해
|
|
5109
|
+
// 베이스라인이 최대 1px 위로 밀린다(xs 에서 특히 눈에 띈다).
|
|
5110
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center leading-none", children: label }),
|
|
5107
5111
|
icon && !iconLeft && iconNode
|
|
5108
5112
|
]
|
|
5109
5113
|
}
|
|
@@ -7875,6 +7879,8 @@ var SPopup = /* @__PURE__ */ react.forwardRef(function SPopup2({
|
|
|
7875
7879
|
});
|
|
7876
7880
|
var DEFAULT_LABEL = { tip: "\uD65C\uC6A9 TIP", notion: "\uC0AC\uC6A9\uBC95 \uC548\uB0B4" };
|
|
7877
7881
|
var ICON = { tip: "helpOutline", notion: "notion" };
|
|
7882
|
+
var VIEWPORT_GUTTER = 24;
|
|
7883
|
+
var CLOSE_INSET = 12;
|
|
7878
7884
|
function flattenMessages(message, depth = 0) {
|
|
7879
7885
|
if (Array.isArray(message)) return message.flatMap((m) => flattenMessages(m, depth + 1));
|
|
7880
7886
|
return message !== "" ? [{ text: message, depth }] : [];
|
|
@@ -7885,13 +7891,14 @@ function SGuide({
|
|
|
7885
7891
|
message = "",
|
|
7886
7892
|
url = "",
|
|
7887
7893
|
popupTitle = "",
|
|
7888
|
-
popupWidth,
|
|
7894
|
+
popupWidth = "auto",
|
|
7889
7895
|
className,
|
|
7890
7896
|
style
|
|
7891
7897
|
}) {
|
|
7892
7898
|
const [open, setOpen] = react.useState(false);
|
|
7893
7899
|
const portalContainer = usePortalContainer();
|
|
7894
7900
|
const isNotion = type === "notion";
|
|
7901
|
+
const isAutoWidth = popupWidth === "auto";
|
|
7895
7902
|
const defaultLabel = DEFAULT_LABEL[type];
|
|
7896
7903
|
const iconName = ICON[type];
|
|
7897
7904
|
const messages = flattenMessages(message);
|
|
@@ -7931,30 +7938,45 @@ function SGuide({
|
|
|
7931
7938
|
side: "bottom",
|
|
7932
7939
|
align: "start",
|
|
7933
7940
|
sideOffset: 4,
|
|
7941
|
+
collisionPadding: VIEWPORT_GUTTER,
|
|
7934
7942
|
className: cn(
|
|
7935
7943
|
"relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
|
|
7936
|
-
// popupWidth(기본 426px)가 창보다 넓으면 창 폭에 맞춘다 — max-width 가 width 를 이긴다.
|
|
7937
|
-
"max-w-[var(--radix-popover-content-available-width)]",
|
|
7938
7944
|
FLOATING_SLIDE_ANIM
|
|
7939
7945
|
),
|
|
7940
7946
|
style: {
|
|
7941
|
-
width:
|
|
7947
|
+
width: isAutoWidth ? "max-content" : popupWidth,
|
|
7948
|
+
// 유일한 폭 상한. auto 든 고정 폭이든 창 좌우 여백을 먹고 들어가지 않는다.
|
|
7949
|
+
// 트리거 위치가 아니라 창 기준이라, 오른쪽 끝 트리거에서도 폭이 깎이지 않는다
|
|
7950
|
+
// (넘치면 Radix 가 왼쪽으로 민다). 100vw 는 세로 스크롤바를 포함하지만
|
|
7951
|
+
// 여백이 그보다 넉넉해 화면 밖으로 나가지 않는다.
|
|
7952
|
+
maxWidth: `calc(100vw - ${VIEWPORT_GUTTER * 2}px)`,
|
|
7942
7953
|
padding: "var(--cmp-guide-contents-paddingY) var(--cmp-guide-contents-paddingX)",
|
|
7943
7954
|
boxShadow: "4px 4px 24px 4px rgba(0,0,0,0.1)"
|
|
7944
7955
|
},
|
|
7945
7956
|
children: [
|
|
7946
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute
|
|
7947
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7957
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute", style: { top: CLOSE_INSET, right: CLOSE_INSET }, children: /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "close", size: "sm", ariaLabel: "close", onClick: () => setOpen(false) }) }),
|
|
7958
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7959
|
+
"div",
|
|
7960
|
+
{
|
|
7961
|
+
className: "flex items-center gap-[var(--cmp-guide-contents-title-gap)]",
|
|
7962
|
+
style: {
|
|
7963
|
+
// 닫기 버튼은 absolute 라 폭 계산에 안 들어간다. 폭이 내용에 붙는 auto 에서 제목이
|
|
7964
|
+
// 버튼 밑으로 들어가지 않도록, 버튼이 콘텐츠 영역을 침범하는 만큼을 미리 비운다.
|
|
7965
|
+
paddingRight: `max(0px, calc(var(--cmp-ghostButton-sm-size) + ${CLOSE_INSET}px + var(--cmp-guide-contents-title-gap) - var(--cmp-guide-contents-paddingX)))`
|
|
7966
|
+
},
|
|
7967
|
+
children: [
|
|
7968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7969
|
+
SIcon,
|
|
7970
|
+
{
|
|
7971
|
+
name: iconName,
|
|
7972
|
+
size: 24,
|
|
7973
|
+
color: isNotion ? "var(--sys-color-fg-primary)" : "var(--cmp-guide-contents-icon)"
|
|
7974
|
+
}
|
|
7975
|
+
),
|
|
7976
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "m-0 break-keep text-[16px] font-bold leading-[26px] text-[color:var(--cmp-guide-contents-typography-color)]", children: popupTitle || defaultLabel })
|
|
7977
|
+
]
|
|
7978
|
+
}
|
|
7979
|
+
),
|
|
7958
7980
|
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 mt-[var(--cmp-guide-contents-gap)] flex w-full list-none flex-col gap-[var(--cmp-guide-contents-body-gap)] p-0 text-[12px] leading-[20px] text-[color:var(--cmp-guide-contents-typography-color)]", children: messages.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7959
7981
|
"li",
|
|
7960
7982
|
{
|
|
@@ -7965,7 +7987,7 @@ function SGuide({
|
|
|
7965
7987
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7966
7988
|
"p",
|
|
7967
7989
|
{
|
|
7968
|
-
className: "m-0 w-full min-w-0 break-words",
|
|
7990
|
+
className: "m-0 w-full min-w-0 break-keep break-words text-pretty",
|
|
7969
7991
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(m.text) }
|
|
7970
7992
|
}
|
|
7971
7993
|
)
|
|
@@ -12764,6 +12786,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12764
12786
|
const dismissedByPointerRef = react.useRef(false);
|
|
12765
12787
|
const alignSelectedTopRef = react.useRef(false);
|
|
12766
12788
|
const selectedAnchorRef = react.useRef(-1);
|
|
12789
|
+
const rangeAnchorRef = react.useRef(null);
|
|
12767
12790
|
const flat = react.useMemo(() => flattenOptions(options), [options]);
|
|
12768
12791
|
const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
|
|
12769
12792
|
const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
|
|
@@ -12864,7 +12887,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12864
12887
|
if (leafValues.length === 0) return;
|
|
12865
12888
|
items.push({ key: `__group_${i}__`, isGroup: true, leafValues });
|
|
12866
12889
|
} else {
|
|
12867
|
-
items.push({ key: o.value, value: o.value });
|
|
12890
|
+
items.push({ key: o.value, value: o.value, index: i });
|
|
12868
12891
|
}
|
|
12869
12892
|
});
|
|
12870
12893
|
return items;
|
|
@@ -12889,20 +12912,36 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12889
12912
|
emit3([]);
|
|
12890
12913
|
if (rules && rules.length > 0) setRuleError(runRules(multi ? [] : "", rules));
|
|
12891
12914
|
};
|
|
12892
|
-
const handleSelect = (nextValue) => {
|
|
12915
|
+
const handleSelect = (nextValue, index, extend = false) => {
|
|
12893
12916
|
if (multi) {
|
|
12894
|
-
const
|
|
12895
|
-
|
|
12917
|
+
const anchor = rangeAnchorRef.current;
|
|
12918
|
+
if (extend && anchor != null && anchor !== index && filtered[anchor]?.isGroup === false) {
|
|
12919
|
+
const [from, to] = anchor < index ? [anchor, index] : [index, anchor];
|
|
12920
|
+
const selectedSet = new Set(selected);
|
|
12921
|
+
const shouldSelect = selectedSet.has(filtered[anchor].value);
|
|
12922
|
+
const rangeValues = filtered.slice(from, to + 1).filter((o) => !o.isGroup && !o.disabled).map((o) => o.value);
|
|
12923
|
+
const inRange = new Set(rangeValues);
|
|
12924
|
+
emit3(
|
|
12925
|
+
shouldSelect ? [...selected, ...rangeValues.filter((v) => !selectedSet.has(v))] : selected.filter((v) => !inRange.has(v))
|
|
12926
|
+
);
|
|
12927
|
+
return;
|
|
12928
|
+
}
|
|
12929
|
+
rangeAnchorRef.current = index;
|
|
12930
|
+
emit3(
|
|
12931
|
+
selected.includes(nextValue) ? selected.filter((v) => v !== nextValue) : [...selected, nextValue]
|
|
12932
|
+
);
|
|
12896
12933
|
return;
|
|
12897
12934
|
}
|
|
12898
12935
|
emit3([nextValue]);
|
|
12899
12936
|
commitOpen(false, [nextValue]);
|
|
12900
12937
|
};
|
|
12901
12938
|
const handleSelectAll = () => {
|
|
12939
|
+
rangeAnchorRef.current = null;
|
|
12902
12940
|
emit3(allSelected ? [] : allValues);
|
|
12903
12941
|
};
|
|
12904
12942
|
const handleToggleGroup = (leafValues) => {
|
|
12905
12943
|
if (leafValues.length === 0) return;
|
|
12944
|
+
rangeAnchorRef.current = null;
|
|
12906
12945
|
const selectedSet = new Set(selected);
|
|
12907
12946
|
const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
|
|
12908
12947
|
if (allSelectedInGroup) {
|
|
@@ -12920,6 +12959,9 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12920
12959
|
const anchor = alignSelectedTopRef.current ? selectedAnchorRef.current : -1;
|
|
12921
12960
|
setFocusedIndex(anchor >= 0 ? anchor : 0);
|
|
12922
12961
|
}, [open, search, navigableItems.length]);
|
|
12962
|
+
react.useEffect(() => {
|
|
12963
|
+
rangeAnchorRef.current = null;
|
|
12964
|
+
}, [open, search]);
|
|
12923
12965
|
react.useLayoutEffect(() => {
|
|
12924
12966
|
if (!open || focusedIndex < 0 || !listEl) return;
|
|
12925
12967
|
const focusedEl = listEl.querySelector('[data-select-focused="true"]');
|
|
@@ -12947,7 +12989,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12947
12989
|
return current <= 0 ? navigableItems.length - 1 : current - 1;
|
|
12948
12990
|
});
|
|
12949
12991
|
};
|
|
12950
|
-
const selectFocusedItem = () => {
|
|
12992
|
+
const selectFocusedItem = (extend = false) => {
|
|
12951
12993
|
if (focusedIndex < 0 || focusedIndex >= navigableItems.length) return;
|
|
12952
12994
|
const focused = navigableItems[focusedIndex];
|
|
12953
12995
|
if (focused.isSelectAll) {
|
|
@@ -12958,7 +13000,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12958
13000
|
handleToggleGroup(focused.leafValues ?? []);
|
|
12959
13001
|
return;
|
|
12960
13002
|
}
|
|
12961
|
-
handleSelect(focused.value);
|
|
13003
|
+
handleSelect(focused.value, focused.index, extend);
|
|
12962
13004
|
};
|
|
12963
13005
|
const handleKeyDown = (event) => {
|
|
12964
13006
|
if (!open) {
|
|
@@ -12980,7 +13022,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
12980
13022
|
}
|
|
12981
13023
|
if (event.key === "Enter") {
|
|
12982
13024
|
event.preventDefault();
|
|
12983
|
-
selectFocusedItem();
|
|
13025
|
+
selectFocusedItem(event.shiftKey);
|
|
12984
13026
|
return;
|
|
12985
13027
|
}
|
|
12986
13028
|
if (event.key === "Escape") {
|
|
@@ -13325,7 +13367,7 @@ function ItemList({
|
|
|
13325
13367
|
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
|
|
13326
13368
|
onMouseEnter: () => onHoverValue(o.value),
|
|
13327
13369
|
onMouseLeave: () => onHoverValue(null),
|
|
13328
|
-
onClick: () => onSelect(o.value),
|
|
13370
|
+
onClick: (event) => onSelect(o.value, idx, event.shiftKey),
|
|
13329
13371
|
children: [
|
|
13330
13372
|
multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13331
13373
|
CheckboxBox,
|
|
@@ -13505,6 +13547,8 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
13505
13547
|
setColumnWidths(visibleCols.map(colWidthFromDef));
|
|
13506
13548
|
}, [colSignature]);
|
|
13507
13549
|
const selectedKeys = react.useMemo(() => new Set(selected.map((r) => r[rowKey])), [selected, rowKey]);
|
|
13550
|
+
const rangeAnchorRef = react.useRef(null);
|
|
13551
|
+
const shiftPressedRef = react.useRef(false);
|
|
13508
13552
|
const isRowSelected = react.useCallback(
|
|
13509
13553
|
(row) => selectedKeys.has(row[rowKey]),
|
|
13510
13554
|
[selectedKeys, rowKey]
|
|
@@ -13686,18 +13730,24 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
13686
13730
|
let bodyRows = rows;
|
|
13687
13731
|
let topSpacer = 0;
|
|
13688
13732
|
let bottomSpacer = 0;
|
|
13733
|
+
let rowOffset = 0;
|
|
13689
13734
|
if (virtualScroll) {
|
|
13690
13735
|
bodyRows = rows.slice(vsRange.start, vsRange.end);
|
|
13736
|
+
rowOffset = vsRange.start;
|
|
13691
13737
|
topSpacer = vsRange.start * effectiveRowHeight;
|
|
13692
13738
|
bottomSpacer = Math.max(0, (rowCount - vsRange.end) * effectiveRowHeight);
|
|
13693
13739
|
} else if (pageInfo) {
|
|
13694
13740
|
bodyRows = rows.slice(pageInfo.startIndex, pageInfo.endIndex);
|
|
13741
|
+
rowOffset = pageInfo.startIndex;
|
|
13695
13742
|
}
|
|
13696
13743
|
const isNoData = rowCount === 0 && !loading2;
|
|
13697
13744
|
const showNoDataSlot = isNoData && emptySlot != null;
|
|
13698
13745
|
const showPagination = !virtualScroll && (pagination != null || internalPagination);
|
|
13699
13746
|
const lastPage = internalPagination ? Math.max(1, Math.ceil(rowCount / (innerRowsPerPage || 1))) : pagination?.lastPage ?? Math.max(1, Math.ceil(rowCount / (pagination?.rowsPerPage ?? 10)));
|
|
13700
13747
|
const displayPage = internalPagination ? currentPage : pagination?.page ?? 1;
|
|
13748
|
+
react.useEffect(() => {
|
|
13749
|
+
rangeAnchorRef.current = null;
|
|
13750
|
+
}, [displayPage]);
|
|
13701
13751
|
const changePage = (p) => {
|
|
13702
13752
|
if (internalPagination) setCurrentPage(p);
|
|
13703
13753
|
onPageChange?.(p);
|
|
@@ -13712,6 +13762,7 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
13712
13762
|
};
|
|
13713
13763
|
const headerCheck = getIsAllChecked(bodyRows);
|
|
13714
13764
|
const toggleAll = () => {
|
|
13765
|
+
rangeAnchorRef.current = null;
|
|
13715
13766
|
if (headerCheck === true) {
|
|
13716
13767
|
const pageKeys = new Set(bodyRows.map((r) => r[rowKey]));
|
|
13717
13768
|
onSelectedChange?.(selected.filter((r) => !pageKeys.has(r[rowKey])));
|
|
@@ -13720,7 +13771,23 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
13720
13771
|
onSelectedChange?.([...selected, ...add]);
|
|
13721
13772
|
}
|
|
13722
13773
|
};
|
|
13723
|
-
const toggleRow = (row) => {
|
|
13774
|
+
const toggleRow = (row, index) => {
|
|
13775
|
+
const anchor = rangeAnchorRef.current;
|
|
13776
|
+
const anchorAlive = anchor != null && anchor.index !== index && rows[anchor.index]?.[rowKey] === anchor.key;
|
|
13777
|
+
if (shiftPressedRef.current && anchor != null && anchorAlive) {
|
|
13778
|
+
const [from, to] = anchor.index < index ? [anchor.index, index] : [index, anchor.index];
|
|
13779
|
+
const shouldSelect = selectedKeys.has(anchor.key);
|
|
13780
|
+
const range = rows.slice(from, to + 1);
|
|
13781
|
+
if (shouldSelect) {
|
|
13782
|
+
const add = range.filter((r) => !selectedKeys.has(r[rowKey]));
|
|
13783
|
+
onSelectedChange?.([...selected, ...add]);
|
|
13784
|
+
} else {
|
|
13785
|
+
const keys = new Set(range.map((r) => r[rowKey]));
|
|
13786
|
+
onSelectedChange?.(selected.filter((r) => !keys.has(r[rowKey])));
|
|
13787
|
+
}
|
|
13788
|
+
return;
|
|
13789
|
+
}
|
|
13790
|
+
rangeAnchorRef.current = { index, key: row[rowKey] };
|
|
13724
13791
|
if (selectedKeys.has(row[rowKey]))
|
|
13725
13792
|
onSelectedChange?.(selected.filter((r) => r[rowKey] !== row[rowKey]));
|
|
13726
13793
|
else onSelectedChange?.([...selected, row]);
|
|
@@ -14078,7 +14145,17 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
14078
14145
|
maxWidth: SELECTABLE_COLUMN_WIDTH
|
|
14079
14146
|
},
|
|
14080
14147
|
onClick: (e) => e.stopPropagation(),
|
|
14081
|
-
|
|
14148
|
+
onClickCapture: (e) => {
|
|
14149
|
+
shiftPressedRef.current = e.shiftKey;
|
|
14150
|
+
if (e.shiftKey) window.getSelection()?.removeAllRanges();
|
|
14151
|
+
},
|
|
14152
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex select-none items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14153
|
+
SCheckbox,
|
|
14154
|
+
{
|
|
14155
|
+
value: isSel,
|
|
14156
|
+
onValueChange: () => toggleRow(row, rowOffset + ri)
|
|
14157
|
+
}
|
|
14158
|
+
) })
|
|
14082
14159
|
}
|
|
14083
14160
|
),
|
|
14084
14161
|
visibleCols.map((col, i) => {
|