sellmate-design-system-react 9.0.0-beta.12 → 9.0.0-beta.14
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/AGENTS.md +6 -4
- package/dist/components/SCard/SCard.d.ts +1 -1
- package/dist/components/SDivider/README.md +2 -0
- package/dist/components/SGnb/gnb.config.d.ts +5 -0
- package/dist/components/SList/README.md +5 -0
- package/dist/index.cjs +90 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +90 -29
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +11 -4
- package/dist/llms.txt +6 -4
- package/dist/styles.css +21 -11
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1106,14 +1106,16 @@ const columns: STableColumn[] = [
|
|
|
1106
1106
|
|
|
1107
1107
|
- **항목 하나의 속성을 나열하는 것은 목록이 아니다.** `라벨: 값` 이 세로로 쌓이는 것은 `SKeyValueTable` 이다 (§4-4).
|
|
1108
1108
|
- `SList` 는 레이아웃만 담당한다. 펼침·단일 선택 동작이 필요하면 `SExpansionList` 다 (§3-7-7).
|
|
1109
|
-
-
|
|
1109
|
+
- **`SList` 의 자식은 `SListItem` 을 권장한다.** 다른 자식도 그대로 렌더되지만, 펼치는 항목은 `SExpansionList` + `SExpansionItem` 이, 끌어서 순서를 바꾸는 항목은 `SDraggableList` + `SDraggableItem` 이 여닫힘·선택·정렬 동작까지 함께 관리하므로 그쪽을 쓴다 (§3-7-7).
|
|
1110
|
+
- **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `useGap` 으로 띄운다 — `useGap` 을 준 목록에도 구분선은 들어가지 않는다.
|
|
1110
1111
|
- **`SListItem` 은 기본이 표시 전용이다.** 눌러서 이동·선택하게 하려면 `clickable` 을 준다 — hover·`selected`·`interaction="chevron"` 표현이 전부 여기에 딸려 있어서, `clickable` 없이 `selected` 만 주면 선택 표시가 나오지 않는다. `SExpansionList` 는 선택을 자기가 관리하므로 자식 아이템을 알아서 클릭 가능하게 만든다.
|
|
1111
1112
|
|
|
1112
1113
|
```tsx
|
|
1113
|
-
✅ <SList
|
|
1114
|
+
✅ <SList><SListItem title="일반 문의" />…</SList> {/* 줄로 구분되는 목록 — 구분선은 자동 */}
|
|
1114
1115
|
✅ <SList useGap><SListItem title="일반 문의" bordered />…</SList> {/* 카드처럼 떨어진 목록 */}
|
|
1115
1116
|
✅ <SListItem title="일반 문의" clickable selected onClick={…} /> {/* 눌러서 고르는 목록 */}
|
|
1116
|
-
❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList>
|
|
1117
|
+
❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList> {/* 구분선을 직접 붙이지 않는다 */}
|
|
1118
|
+
❌ <SList><><SListItem title="일반 문의" /><SListItem title="결제 문의" /></></SList> {/* Fragment 로 묶으면 그 안쪽은 구분되지 않는다 */}
|
|
1117
1119
|
❌ <SListItem title="일반 문의" selected /> {/* clickable 없으면 선택 표시가 안 나온다 */}
|
|
1118
1120
|
```
|
|
1119
1121
|
|
|
@@ -1125,7 +1127,7 @@ const columns: STableColumn[] = [
|
|
|
1125
1127
|
| **한 번에 하나만** 열려야 한다 (아코디언) | `SExpansionList` + `SExpansionItem` |
|
|
1126
1128
|
| **부모-자식 계층 자체**를 보여줘야 한다 (2단 이상, 연결선) | `STree` |
|
|
1127
1129
|
|
|
1128
|
-
`SExpansionList` 는 depth 별 단일 확장·선택을 관리하는 wrapper 다. 직접 `useState` 로 "열린 항목 하나"를 들고 있지 않는다. 항목 사이 구분선은 여기서도 리스트가 그린다 —
|
|
1130
|
+
`SExpansionList` 는 depth 별 단일 확장·선택을 관리하는 wrapper 다. 직접 `useState` 로 "열린 항목 하나"를 들고 있지 않는다. 항목 사이 구분선은 여기서도 리스트가 알아서 그린다 — 따로 줄 prop 이 없다 (§3-7-6).
|
|
1129
1131
|
|
|
1130
1132
|
#### 3-7-8. SCard vs SSectionHeaderCard
|
|
1131
1133
|
|
|
@@ -3,5 +3,5 @@ export interface SCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
3
3
|
/** 테두리 표시 여부 */
|
|
4
4
|
bordered?: boolean;
|
|
5
5
|
}
|
|
6
|
-
/** SCard — sd-card 포팅. 라운드 8px, 흰 배경, 옵션 테두리. */
|
|
6
|
+
/** SCard — sd-card 포팅. 라운드 8px, 흰 배경, 옵션 테두리. 콘텐츠는 라운드 경계에서 잘린다. */
|
|
7
7
|
export declare const SCard: import("react").ForwardRefExoticComponent<SCardProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
- [SCalendar](../SCalendar)
|
|
18
18
|
- [SDateRangePicker](../SDateRangePicker)
|
|
19
|
+
- [SList](../SList)
|
|
19
20
|
- [STableBar](../STableBar)
|
|
20
21
|
|
|
21
22
|
### Graph
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
graph TD;
|
|
25
26
|
SCalendar --> SDivider
|
|
26
27
|
SDateRangePicker --> SDivider
|
|
28
|
+
SList --> SDivider
|
|
27
29
|
STableBar --> SDivider
|
|
28
30
|
style SDivider fill:#f9f,stroke:#333,stroke-width:4px
|
|
29
31
|
```
|
|
@@ -162,3 +162,8 @@ export declare function findGnbRailValue(items: SGnbMenuItem[], value: string):
|
|
|
162
162
|
export declare function findGnbSiblingValues(items: SGnbMenuItem[], value: string): string[];
|
|
163
163
|
/** value 로 선택된 아이템의 조상 value 목록(자기 자신 제외)을 반환 → 자동 펼침용 */
|
|
164
164
|
export declare function findGnbAncestors(items: SGnbMenuItem[], value: string): string[];
|
|
165
|
+
/**
|
|
166
|
+
* value 를 가진 아이템 아래의 **하위 가지**(children 을 가진 자손) value 목록을 반환.
|
|
167
|
+
* 부모를 펼칠 때 그 아래 가지도 전부 함께 펼치는 용도 — 리프는 펼침 대상이 아니라 제외한다.
|
|
168
|
+
*/
|
|
169
|
+
export declare function findGnbDescendantBranchValues(items: SGnbMenuItem[], value: string): string[];
|
|
@@ -19,10 +19,15 @@
|
|
|
19
19
|
- [SDraggableList](../SDraggableList)
|
|
20
20
|
- [SExpansionList](../SExpansionList)
|
|
21
21
|
|
|
22
|
+
### Depends on
|
|
23
|
+
|
|
24
|
+
- [SDivider](../SDivider)
|
|
25
|
+
|
|
22
26
|
### Graph
|
|
23
27
|
|
|
24
28
|
```mermaid
|
|
25
29
|
graph TD;
|
|
30
|
+
SList --> SDivider
|
|
26
31
|
SDraggableList --> SList
|
|
27
32
|
SExpansionList --> SList
|
|
28
33
|
style SList fill:#f9f,stroke:#333,stroke-width:4px
|
package/dist/index.cjs
CHANGED
|
@@ -3373,7 +3373,11 @@ var SCard = /* @__PURE__ */ react.forwardRef(function SCard2({ bordered = false,
|
|
|
3373
3373
|
"div",
|
|
3374
3374
|
{
|
|
3375
3375
|
ref,
|
|
3376
|
-
className: cn(
|
|
3376
|
+
className: cn(
|
|
3377
|
+
"h-fit overflow-hidden rounded-[8px] bg-white",
|
|
3378
|
+
bordered && "border border-grey-30",
|
|
3379
|
+
className
|
|
3380
|
+
),
|
|
3377
3381
|
...rest,
|
|
3378
3382
|
children
|
|
3379
3383
|
}
|
|
@@ -3654,7 +3658,49 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3654
3658
|
] });
|
|
3655
3659
|
});
|
|
3656
3660
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3661
|
+
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, className, style, ...rest }, ref) {
|
|
3662
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3663
|
+
"hr",
|
|
3664
|
+
{
|
|
3665
|
+
ref,
|
|
3666
|
+
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
3667
|
+
className: cn(
|
|
3668
|
+
"shrink-0 border-0",
|
|
3669
|
+
vertical ? "inline-block h-auto w-px self-stretch" : "block h-px w-full",
|
|
3670
|
+
className
|
|
3671
|
+
),
|
|
3672
|
+
style: { backgroundColor: "var(--sys-color-divider-default, #E1E1E1)", ...style },
|
|
3673
|
+
...rest
|
|
3674
|
+
}
|
|
3675
|
+
);
|
|
3676
|
+
});
|
|
3677
|
+
var dividerStyle = { backgroundColor: "var(--cmp-listItem-border-default)" };
|
|
3678
|
+
function hasBorderedChild(children) {
|
|
3679
|
+
let bordered = false;
|
|
3680
|
+
react.Children.forEach(children, (child) => {
|
|
3681
|
+
if (!react.isValidElement(child)) return;
|
|
3682
|
+
if (child.props.bordered === true) {
|
|
3683
|
+
bordered = true;
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
react.Children.forEach(child.props.children, (wrapped) => {
|
|
3687
|
+
if (react.isValidElement(wrapped) && wrapped.props.bordered === true) {
|
|
3688
|
+
bordered = true;
|
|
3689
|
+
}
|
|
3690
|
+
});
|
|
3691
|
+
});
|
|
3692
|
+
return bordered;
|
|
3693
|
+
}
|
|
3694
|
+
function withDividers(children) {
|
|
3695
|
+
return react.Children.toArray(children).flatMap(
|
|
3696
|
+
(child, index) => index === 0 ? [child] : [
|
|
3697
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { "aria-hidden": "true", style: dividerStyle }, `s-list-divider-${index}`),
|
|
3698
|
+
child
|
|
3699
|
+
]
|
|
3700
|
+
);
|
|
3701
|
+
}
|
|
3657
3702
|
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, useGap = false, usePadding = false, ...rest }, ref) {
|
|
3703
|
+
const showDivider = !useGap && !hasBorderedChild(children);
|
|
3658
3704
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3659
3705
|
"div",
|
|
3660
3706
|
{
|
|
@@ -3662,11 +3708,10 @@ var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, chi
|
|
|
3662
3708
|
className: cn(
|
|
3663
3709
|
useGap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
3664
3710
|
usePadding && "p-(--cmp-list-group-padding)",
|
|
3665
|
-
"[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
|
|
3666
3711
|
className
|
|
3667
3712
|
),
|
|
3668
3713
|
...rest,
|
|
3669
|
-
children
|
|
3714
|
+
children: showDivider ? withDividers(children) : children
|
|
3670
3715
|
}
|
|
3671
3716
|
);
|
|
3672
3717
|
});
|
|
@@ -5381,22 +5426,6 @@ var SSectionHeaderCardRootImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
5381
5426
|
}
|
|
5382
5427
|
);
|
|
5383
5428
|
var SSectionHeaderCard2 = /* @__PURE__ */ withDisplayName(SSectionHeaderCardRootImpl, "SSectionHeaderCard");
|
|
5384
|
-
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, className, style, ...rest }, ref) {
|
|
5385
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5386
|
-
"hr",
|
|
5387
|
-
{
|
|
5388
|
-
ref,
|
|
5389
|
-
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
5390
|
-
className: cn(
|
|
5391
|
-
"shrink-0 border-0",
|
|
5392
|
-
vertical ? "inline-block h-auto w-px self-stretch" : "block h-px w-full",
|
|
5393
|
-
className
|
|
5394
|
-
),
|
|
5395
|
-
style: { backgroundColor: "var(--sys-color-divider-default, #E1E1E1)", ...style },
|
|
5396
|
-
...rest
|
|
5397
|
-
}
|
|
5398
|
-
);
|
|
5399
|
-
});
|
|
5400
5429
|
|
|
5401
5430
|
// src/lib/scrollbar.ts
|
|
5402
5431
|
var FIREFOX_SCROLLBAR_CLASS = "supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-width:thin] supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-color:var(--color-grey-45)_transparent]";
|
|
@@ -5479,7 +5508,7 @@ var SSplitterRoot = /* @__PURE__ */ react.forwardRef(function SSplitter({
|
|
|
5479
5508
|
vertical = false,
|
|
5480
5509
|
disabled = false,
|
|
5481
5510
|
dividerClassName,
|
|
5482
|
-
dividerStyle,
|
|
5511
|
+
dividerStyle: dividerStyle2,
|
|
5483
5512
|
className,
|
|
5484
5513
|
style,
|
|
5485
5514
|
children,
|
|
@@ -5604,7 +5633,7 @@ var SSplitterRoot = /* @__PURE__ */ react.forwardRef(function SSplitter({
|
|
|
5604
5633
|
),
|
|
5605
5634
|
style: {
|
|
5606
5635
|
...vertical ? { bottom: HIT_END, height: HIT } : { right: HIT_END, width: HIT },
|
|
5607
|
-
...
|
|
5636
|
+
...dividerStyle2
|
|
5608
5637
|
},
|
|
5609
5638
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5610
5639
|
"span",
|
|
@@ -8304,6 +8333,29 @@ function findGnbAncestors(items, value) {
|
|
|
8304
8333
|
};
|
|
8305
8334
|
return walk(items, []) ?? [];
|
|
8306
8335
|
}
|
|
8336
|
+
function findGnbDescendantBranchValues(items, value) {
|
|
8337
|
+
const find = (list) => {
|
|
8338
|
+
for (const item of list) {
|
|
8339
|
+
if (item.value === value) return item;
|
|
8340
|
+
if (item.children) {
|
|
8341
|
+
const found = find(item.children);
|
|
8342
|
+
if (found) return found;
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
return void 0;
|
|
8346
|
+
};
|
|
8347
|
+
const collect = (list, acc) => {
|
|
8348
|
+
for (const item of list) {
|
|
8349
|
+
if (item.children && item.children.length > 0) {
|
|
8350
|
+
acc.push(item.value);
|
|
8351
|
+
collect(item.children, acc);
|
|
8352
|
+
}
|
|
8353
|
+
}
|
|
8354
|
+
return acc;
|
|
8355
|
+
};
|
|
8356
|
+
const target = find(items);
|
|
8357
|
+
return target?.children ? collect(target.children, []) : [];
|
|
8358
|
+
}
|
|
8307
8359
|
var LABEL_TIP_HIDE_DELAY_MS = 100;
|
|
8308
8360
|
var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
|
|
8309
8361
|
var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
@@ -8344,8 +8396,12 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8344
8396
|
const H = GNB_HEADER[header];
|
|
8345
8397
|
const M = GNB_MENU[type];
|
|
8346
8398
|
const C = GNB_COLORS[color];
|
|
8399
|
+
const branchWithDescendants = (key) => [
|
|
8400
|
+
key,
|
|
8401
|
+
...findGnbDescendantBranchValues(items, key)
|
|
8402
|
+
];
|
|
8347
8403
|
const [expandedKeys, setExpandedKeys] = react.useState(
|
|
8348
|
-
() => new Set(findGnbAncestors(items, value))
|
|
8404
|
+
() => new Set(findGnbAncestors(items, value).flatMap(branchWithDescendants))
|
|
8349
8405
|
);
|
|
8350
8406
|
const [hoveredKey, setHoveredKey] = react.useState(null);
|
|
8351
8407
|
const [labelTip, setLabelTip] = react.useState(null);
|
|
@@ -8392,12 +8448,15 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8392
8448
|
() => findGnbRailValue(items, value) ?? items[0]?.value
|
|
8393
8449
|
);
|
|
8394
8450
|
react.useEffect(() => {
|
|
8395
|
-
const
|
|
8396
|
-
|
|
8451
|
+
const keys = findGnbAncestors(items, value).flatMap((ancestor) => [
|
|
8452
|
+
ancestor,
|
|
8453
|
+
...findGnbDescendantBranchValues(items, ancestor)
|
|
8454
|
+
]);
|
|
8455
|
+
if (keys.length === 0) return;
|
|
8397
8456
|
setExpandedKeys((prev) => {
|
|
8398
|
-
if (
|
|
8457
|
+
if (keys.every((key) => prev.has(key))) return prev;
|
|
8399
8458
|
const next = new Set(prev);
|
|
8400
|
-
|
|
8459
|
+
keys.forEach((key) => next.add(key));
|
|
8401
8460
|
return next;
|
|
8402
8461
|
});
|
|
8403
8462
|
}, [items, value]);
|
|
@@ -8414,10 +8473,12 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8414
8473
|
setExpandedKeys((prev) => {
|
|
8415
8474
|
const next = new Set(prev);
|
|
8416
8475
|
if (next.has(key)) {
|
|
8417
|
-
next.delete(
|
|
8476
|
+
branchWithDescendants(key).forEach((descendant) => next.delete(descendant));
|
|
8418
8477
|
} else {
|
|
8419
|
-
findGnbSiblingValues(items, key).forEach(
|
|
8420
|
-
|
|
8478
|
+
findGnbSiblingValues(items, key).forEach(
|
|
8479
|
+
(sibling) => branchWithDescendants(sibling).forEach((descendant) => next.delete(descendant))
|
|
8480
|
+
);
|
|
8481
|
+
branchWithDescendants(key).forEach((descendant) => next.add(descendant));
|
|
8421
8482
|
}
|
|
8422
8483
|
return next;
|
|
8423
8484
|
});
|