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
package/dist/index.js
CHANGED
|
@@ -5075,7 +5075,11 @@ var STag = /* @__PURE__ */ forwardRef(function STag2({
|
|
|
5075
5075
|
...rest,
|
|
5076
5076
|
children: [
|
|
5077
5077
|
icon && iconLeft && iconNode,
|
|
5078
|
-
label &&
|
|
5078
|
+
label && // leading-none: 태그는 min-height 로 높이가 정해지고 flex 가 세로 중앙 정렬하므로
|
|
5079
|
+
// 레이블에 line-height 가 필요 없다. 오히려 line-height 를 주면 브라우저가
|
|
5080
|
+
// 폰트 ascent/descent 를 정수 px 로 반올림한 뒤 남는 half-leading 을 내림 처리해
|
|
5081
|
+
// 베이스라인이 최대 1px 위로 밀린다(xs 에서 특히 눈에 띈다).
|
|
5082
|
+
/* @__PURE__ */ jsx("span", { className: "inline-flex min-w-0 items-center justify-center leading-none", children: label }),
|
|
5079
5083
|
icon && !iconLeft && iconNode
|
|
5080
5084
|
]
|
|
5081
5085
|
}
|
|
@@ -7847,6 +7851,8 @@ var SPopup = /* @__PURE__ */ forwardRef(function SPopup2({
|
|
|
7847
7851
|
});
|
|
7848
7852
|
var DEFAULT_LABEL = { tip: "\uD65C\uC6A9 TIP", notion: "\uC0AC\uC6A9\uBC95 \uC548\uB0B4" };
|
|
7849
7853
|
var ICON = { tip: "helpOutline", notion: "notion" };
|
|
7854
|
+
var VIEWPORT_GUTTER = 24;
|
|
7855
|
+
var CLOSE_INSET = 12;
|
|
7850
7856
|
function flattenMessages(message, depth = 0) {
|
|
7851
7857
|
if (Array.isArray(message)) return message.flatMap((m) => flattenMessages(m, depth + 1));
|
|
7852
7858
|
return message !== "" ? [{ text: message, depth }] : [];
|
|
@@ -7857,13 +7863,14 @@ function SGuide({
|
|
|
7857
7863
|
message = "",
|
|
7858
7864
|
url = "",
|
|
7859
7865
|
popupTitle = "",
|
|
7860
|
-
popupWidth,
|
|
7866
|
+
popupWidth = "auto",
|
|
7861
7867
|
className,
|
|
7862
7868
|
style
|
|
7863
7869
|
}) {
|
|
7864
7870
|
const [open, setOpen] = useState(false);
|
|
7865
7871
|
const portalContainer = usePortalContainer();
|
|
7866
7872
|
const isNotion = type === "notion";
|
|
7873
|
+
const isAutoWidth = popupWidth === "auto";
|
|
7867
7874
|
const defaultLabel = DEFAULT_LABEL[type];
|
|
7868
7875
|
const iconName = ICON[type];
|
|
7869
7876
|
const messages = flattenMessages(message);
|
|
@@ -7903,30 +7910,45 @@ function SGuide({
|
|
|
7903
7910
|
side: "bottom",
|
|
7904
7911
|
align: "start",
|
|
7905
7912
|
sideOffset: 4,
|
|
7913
|
+
collisionPadding: VIEWPORT_GUTTER,
|
|
7906
7914
|
className: cn(
|
|
7907
7915
|
"relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
|
|
7908
|
-
// popupWidth(기본 426px)가 창보다 넓으면 창 폭에 맞춘다 — max-width 가 width 를 이긴다.
|
|
7909
|
-
"max-w-[var(--radix-popover-content-available-width)]",
|
|
7910
7916
|
FLOATING_SLIDE_ANIM
|
|
7911
7917
|
),
|
|
7912
7918
|
style: {
|
|
7913
|
-
width:
|
|
7919
|
+
width: isAutoWidth ? "max-content" : popupWidth,
|
|
7920
|
+
// 유일한 폭 상한. auto 든 고정 폭이든 창 좌우 여백을 먹고 들어가지 않는다.
|
|
7921
|
+
// 트리거 위치가 아니라 창 기준이라, 오른쪽 끝 트리거에서도 폭이 깎이지 않는다
|
|
7922
|
+
// (넘치면 Radix 가 왼쪽으로 민다). 100vw 는 세로 스크롤바를 포함하지만
|
|
7923
|
+
// 여백이 그보다 넉넉해 화면 밖으로 나가지 않는다.
|
|
7924
|
+
maxWidth: `calc(100vw - ${VIEWPORT_GUTTER * 2}px)`,
|
|
7914
7925
|
padding: "var(--cmp-guide-contents-paddingY) var(--cmp-guide-contents-paddingX)",
|
|
7915
7926
|
boxShadow: "4px 4px 24px 4px rgba(0,0,0,0.1)"
|
|
7916
7927
|
},
|
|
7917
7928
|
children: [
|
|
7918
|
-
/* @__PURE__ */ jsx("div", { className: "absolute
|
|
7919
|
-
/* @__PURE__ */ jsxs(
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7929
|
+
/* @__PURE__ */ jsx("div", { className: "absolute", style: { top: CLOSE_INSET, right: CLOSE_INSET }, children: /* @__PURE__ */ jsx(SGhostButton, { icon: "close", size: "sm", ariaLabel: "close", onClick: () => setOpen(false) }) }),
|
|
7930
|
+
/* @__PURE__ */ jsxs(
|
|
7931
|
+
"div",
|
|
7932
|
+
{
|
|
7933
|
+
className: "flex items-center gap-[var(--cmp-guide-contents-title-gap)]",
|
|
7934
|
+
style: {
|
|
7935
|
+
// 닫기 버튼은 absolute 라 폭 계산에 안 들어간다. 폭이 내용에 붙는 auto 에서 제목이
|
|
7936
|
+
// 버튼 밑으로 들어가지 않도록, 버튼이 콘텐츠 영역을 침범하는 만큼을 미리 비운다.
|
|
7937
|
+
paddingRight: `max(0px, calc(var(--cmp-ghostButton-sm-size) + ${CLOSE_INSET}px + var(--cmp-guide-contents-title-gap) - var(--cmp-guide-contents-paddingX)))`
|
|
7938
|
+
},
|
|
7939
|
+
children: [
|
|
7940
|
+
/* @__PURE__ */ jsx(
|
|
7941
|
+
SIcon,
|
|
7942
|
+
{
|
|
7943
|
+
name: iconName,
|
|
7944
|
+
size: 24,
|
|
7945
|
+
color: isNotion ? "var(--sys-color-fg-primary)" : "var(--cmp-guide-contents-icon)"
|
|
7946
|
+
}
|
|
7947
|
+
),
|
|
7948
|
+
/* @__PURE__ */ jsx("h3", { className: "m-0 break-keep text-[16px] font-bold leading-[26px] text-[color:var(--cmp-guide-contents-typography-color)]", children: popupTitle || defaultLabel })
|
|
7949
|
+
]
|
|
7950
|
+
}
|
|
7951
|
+
),
|
|
7930
7952
|
/* @__PURE__ */ 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__ */ jsx(
|
|
7931
7953
|
"li",
|
|
7932
7954
|
{
|
|
@@ -7937,7 +7959,7 @@ function SGuide({
|
|
|
7937
7959
|
children: /* @__PURE__ */ jsx(
|
|
7938
7960
|
"p",
|
|
7939
7961
|
{
|
|
7940
|
-
className: "m-0 w-full min-w-0 break-words",
|
|
7962
|
+
className: "m-0 w-full min-w-0 break-keep break-words text-pretty",
|
|
7941
7963
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(m.text) }
|
|
7942
7964
|
}
|
|
7943
7965
|
)
|
|
@@ -12736,6 +12758,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12736
12758
|
const dismissedByPointerRef = useRef(false);
|
|
12737
12759
|
const alignSelectedTopRef = useRef(false);
|
|
12738
12760
|
const selectedAnchorRef = useRef(-1);
|
|
12761
|
+
const rangeAnchorRef = useRef(null);
|
|
12739
12762
|
const flat = useMemo(() => flattenOptions(options), [options]);
|
|
12740
12763
|
const selectable = useMemo(() => selectableOptions(flat), [flat]);
|
|
12741
12764
|
const hasLeaf = useMemo(() => flat.some((o) => !o.isGroup), [flat]);
|
|
@@ -12836,7 +12859,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12836
12859
|
if (leafValues.length === 0) return;
|
|
12837
12860
|
items.push({ key: `__group_${i}__`, isGroup: true, leafValues });
|
|
12838
12861
|
} else {
|
|
12839
|
-
items.push({ key: o.value, value: o.value });
|
|
12862
|
+
items.push({ key: o.value, value: o.value, index: i });
|
|
12840
12863
|
}
|
|
12841
12864
|
});
|
|
12842
12865
|
return items;
|
|
@@ -12861,20 +12884,36 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12861
12884
|
emit3([]);
|
|
12862
12885
|
if (rules && rules.length > 0) setRuleError(runRules(multi ? [] : "", rules));
|
|
12863
12886
|
};
|
|
12864
|
-
const handleSelect = (nextValue) => {
|
|
12887
|
+
const handleSelect = (nextValue, index, extend = false) => {
|
|
12865
12888
|
if (multi) {
|
|
12866
|
-
const
|
|
12867
|
-
|
|
12889
|
+
const anchor = rangeAnchorRef.current;
|
|
12890
|
+
if (extend && anchor != null && anchor !== index && filtered[anchor]?.isGroup === false) {
|
|
12891
|
+
const [from, to] = anchor < index ? [anchor, index] : [index, anchor];
|
|
12892
|
+
const selectedSet = new Set(selected);
|
|
12893
|
+
const shouldSelect = selectedSet.has(filtered[anchor].value);
|
|
12894
|
+
const rangeValues = filtered.slice(from, to + 1).filter((o) => !o.isGroup && !o.disabled).map((o) => o.value);
|
|
12895
|
+
const inRange = new Set(rangeValues);
|
|
12896
|
+
emit3(
|
|
12897
|
+
shouldSelect ? [...selected, ...rangeValues.filter((v) => !selectedSet.has(v))] : selected.filter((v) => !inRange.has(v))
|
|
12898
|
+
);
|
|
12899
|
+
return;
|
|
12900
|
+
}
|
|
12901
|
+
rangeAnchorRef.current = index;
|
|
12902
|
+
emit3(
|
|
12903
|
+
selected.includes(nextValue) ? selected.filter((v) => v !== nextValue) : [...selected, nextValue]
|
|
12904
|
+
);
|
|
12868
12905
|
return;
|
|
12869
12906
|
}
|
|
12870
12907
|
emit3([nextValue]);
|
|
12871
12908
|
commitOpen(false, [nextValue]);
|
|
12872
12909
|
};
|
|
12873
12910
|
const handleSelectAll = () => {
|
|
12911
|
+
rangeAnchorRef.current = null;
|
|
12874
12912
|
emit3(allSelected ? [] : allValues);
|
|
12875
12913
|
};
|
|
12876
12914
|
const handleToggleGroup = (leafValues) => {
|
|
12877
12915
|
if (leafValues.length === 0) return;
|
|
12916
|
+
rangeAnchorRef.current = null;
|
|
12878
12917
|
const selectedSet = new Set(selected);
|
|
12879
12918
|
const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
|
|
12880
12919
|
if (allSelectedInGroup) {
|
|
@@ -12892,6 +12931,9 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12892
12931
|
const anchor = alignSelectedTopRef.current ? selectedAnchorRef.current : -1;
|
|
12893
12932
|
setFocusedIndex(anchor >= 0 ? anchor : 0);
|
|
12894
12933
|
}, [open, search, navigableItems.length]);
|
|
12934
|
+
useEffect(() => {
|
|
12935
|
+
rangeAnchorRef.current = null;
|
|
12936
|
+
}, [open, search]);
|
|
12895
12937
|
useLayoutEffect(() => {
|
|
12896
12938
|
if (!open || focusedIndex < 0 || !listEl) return;
|
|
12897
12939
|
const focusedEl = listEl.querySelector('[data-select-focused="true"]');
|
|
@@ -12919,7 +12961,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12919
12961
|
return current <= 0 ? navigableItems.length - 1 : current - 1;
|
|
12920
12962
|
});
|
|
12921
12963
|
};
|
|
12922
|
-
const selectFocusedItem = () => {
|
|
12964
|
+
const selectFocusedItem = (extend = false) => {
|
|
12923
12965
|
if (focusedIndex < 0 || focusedIndex >= navigableItems.length) return;
|
|
12924
12966
|
const focused = navigableItems[focusedIndex];
|
|
12925
12967
|
if (focused.isSelectAll) {
|
|
@@ -12930,7 +12972,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12930
12972
|
handleToggleGroup(focused.leafValues ?? []);
|
|
12931
12973
|
return;
|
|
12932
12974
|
}
|
|
12933
|
-
handleSelect(focused.value);
|
|
12975
|
+
handleSelect(focused.value, focused.index, extend);
|
|
12934
12976
|
};
|
|
12935
12977
|
const handleKeyDown = (event) => {
|
|
12936
12978
|
if (!open) {
|
|
@@ -12952,7 +12994,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12952
12994
|
}
|
|
12953
12995
|
if (event.key === "Enter") {
|
|
12954
12996
|
event.preventDefault();
|
|
12955
|
-
selectFocusedItem();
|
|
12997
|
+
selectFocusedItem(event.shiftKey);
|
|
12956
12998
|
return;
|
|
12957
12999
|
}
|
|
12958
13000
|
if (event.key === "Escape") {
|
|
@@ -13297,7 +13339,7 @@ function ItemList({
|
|
|
13297
13339
|
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
|
|
13298
13340
|
onMouseEnter: () => onHoverValue(o.value),
|
|
13299
13341
|
onMouseLeave: () => onHoverValue(null),
|
|
13300
|
-
onClick: () => onSelect(o.value),
|
|
13342
|
+
onClick: (event) => onSelect(o.value, idx, event.shiftKey),
|
|
13301
13343
|
children: [
|
|
13302
13344
|
multi && /* @__PURE__ */ jsx(
|
|
13303
13345
|
CheckboxBox,
|
|
@@ -13477,6 +13519,8 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
|
|
|
13477
13519
|
setColumnWidths(visibleCols.map(colWidthFromDef));
|
|
13478
13520
|
}, [colSignature]);
|
|
13479
13521
|
const selectedKeys = useMemo(() => new Set(selected.map((r) => r[rowKey])), [selected, rowKey]);
|
|
13522
|
+
const rangeAnchorRef = useRef(null);
|
|
13523
|
+
const shiftPressedRef = useRef(false);
|
|
13480
13524
|
const isRowSelected = useCallback(
|
|
13481
13525
|
(row) => selectedKeys.has(row[rowKey]),
|
|
13482
13526
|
[selectedKeys, rowKey]
|
|
@@ -13658,18 +13702,24 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
|
|
|
13658
13702
|
let bodyRows = rows;
|
|
13659
13703
|
let topSpacer = 0;
|
|
13660
13704
|
let bottomSpacer = 0;
|
|
13705
|
+
let rowOffset = 0;
|
|
13661
13706
|
if (virtualScroll) {
|
|
13662
13707
|
bodyRows = rows.slice(vsRange.start, vsRange.end);
|
|
13708
|
+
rowOffset = vsRange.start;
|
|
13663
13709
|
topSpacer = vsRange.start * effectiveRowHeight;
|
|
13664
13710
|
bottomSpacer = Math.max(0, (rowCount - vsRange.end) * effectiveRowHeight);
|
|
13665
13711
|
} else if (pageInfo) {
|
|
13666
13712
|
bodyRows = rows.slice(pageInfo.startIndex, pageInfo.endIndex);
|
|
13713
|
+
rowOffset = pageInfo.startIndex;
|
|
13667
13714
|
}
|
|
13668
13715
|
const isNoData = rowCount === 0 && !loading2;
|
|
13669
13716
|
const showNoDataSlot = isNoData && emptySlot != null;
|
|
13670
13717
|
const showPagination = !virtualScroll && (pagination != null || internalPagination);
|
|
13671
13718
|
const lastPage = internalPagination ? Math.max(1, Math.ceil(rowCount / (innerRowsPerPage || 1))) : pagination?.lastPage ?? Math.max(1, Math.ceil(rowCount / (pagination?.rowsPerPage ?? 10)));
|
|
13672
13719
|
const displayPage = internalPagination ? currentPage : pagination?.page ?? 1;
|
|
13720
|
+
useEffect(() => {
|
|
13721
|
+
rangeAnchorRef.current = null;
|
|
13722
|
+
}, [displayPage]);
|
|
13673
13723
|
const changePage = (p) => {
|
|
13674
13724
|
if (internalPagination) setCurrentPage(p);
|
|
13675
13725
|
onPageChange?.(p);
|
|
@@ -13684,6 +13734,7 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
|
|
|
13684
13734
|
};
|
|
13685
13735
|
const headerCheck = getIsAllChecked(bodyRows);
|
|
13686
13736
|
const toggleAll = () => {
|
|
13737
|
+
rangeAnchorRef.current = null;
|
|
13687
13738
|
if (headerCheck === true) {
|
|
13688
13739
|
const pageKeys = new Set(bodyRows.map((r) => r[rowKey]));
|
|
13689
13740
|
onSelectedChange?.(selected.filter((r) => !pageKeys.has(r[rowKey])));
|
|
@@ -13692,7 +13743,23 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
|
|
|
13692
13743
|
onSelectedChange?.([...selected, ...add]);
|
|
13693
13744
|
}
|
|
13694
13745
|
};
|
|
13695
|
-
const toggleRow = (row) => {
|
|
13746
|
+
const toggleRow = (row, index) => {
|
|
13747
|
+
const anchor = rangeAnchorRef.current;
|
|
13748
|
+
const anchorAlive = anchor != null && anchor.index !== index && rows[anchor.index]?.[rowKey] === anchor.key;
|
|
13749
|
+
if (shiftPressedRef.current && anchor != null && anchorAlive) {
|
|
13750
|
+
const [from, to] = anchor.index < index ? [anchor.index, index] : [index, anchor.index];
|
|
13751
|
+
const shouldSelect = selectedKeys.has(anchor.key);
|
|
13752
|
+
const range = rows.slice(from, to + 1);
|
|
13753
|
+
if (shouldSelect) {
|
|
13754
|
+
const add = range.filter((r) => !selectedKeys.has(r[rowKey]));
|
|
13755
|
+
onSelectedChange?.([...selected, ...add]);
|
|
13756
|
+
} else {
|
|
13757
|
+
const keys = new Set(range.map((r) => r[rowKey]));
|
|
13758
|
+
onSelectedChange?.(selected.filter((r) => !keys.has(r[rowKey])));
|
|
13759
|
+
}
|
|
13760
|
+
return;
|
|
13761
|
+
}
|
|
13762
|
+
rangeAnchorRef.current = { index, key: row[rowKey] };
|
|
13696
13763
|
if (selectedKeys.has(row[rowKey]))
|
|
13697
13764
|
onSelectedChange?.(selected.filter((r) => r[rowKey] !== row[rowKey]));
|
|
13698
13765
|
else onSelectedChange?.([...selected, row]);
|
|
@@ -14050,7 +14117,17 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
|
|
|
14050
14117
|
maxWidth: SELECTABLE_COLUMN_WIDTH
|
|
14051
14118
|
},
|
|
14052
14119
|
onClick: (e) => e.stopPropagation(),
|
|
14053
|
-
|
|
14120
|
+
onClickCapture: (e) => {
|
|
14121
|
+
shiftPressedRef.current = e.shiftKey;
|
|
14122
|
+
if (e.shiftKey) window.getSelection()?.removeAllRanges();
|
|
14123
|
+
},
|
|
14124
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex select-none items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
14125
|
+
SCheckbox,
|
|
14126
|
+
{
|
|
14127
|
+
value: isSel,
|
|
14128
|
+
onValueChange: () => toggleRow(row, rowOffset + ri)
|
|
14129
|
+
}
|
|
14130
|
+
) })
|
|
14054
14131
|
}
|
|
14055
14132
|
),
|
|
14056
14133
|
visibleCols.map((col, i) => {
|