sellmate-design-system-react 9.0.0-beta.67 → 9.0.0-beta.68
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 +36 -5
- package/dist/components/SCalendarBoard/CalendarDayCard.d.ts +7 -0
- package/dist/components/SCalendarBoard/CalendarEventButton.d.ts +3 -1
- package/dist/components/SCalendarBoard/CalendarMoreButton.d.ts +5 -0
- package/dist/components/SCalendarBoard/README.md +1 -0
- package/dist/components/SCalendarBoard/SCalendarBoard.d.ts +13 -1
- package/dist/components/SCalendarBoard/calendar-board-layout.d.ts +11 -1
- package/dist/components/SCalendarBoard/calendarBoard.config.d.ts +5 -0
- package/dist/components/SCard/README.md +1 -0
- package/dist/components/SCard/SCard.d.ts +10 -1
- package/dist/components/SFooter/README.md +16 -2
- package/dist/components/SFooter/SFooter.d.ts +13 -3
- package/dist/components/SFooter/index.d.ts +1 -1
- package/dist/components/SSectionHeaderCard/README.md +1 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.d.ts +10 -1
- package/dist/index.cjs +61 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +61 -14
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +55 -7
- package/dist/llms.txt +36 -5
- package/dist/styles.css +3 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -837,7 +837,7 @@ SModal.create({ component: OrderModal, componentProps: { orderId } })
|
|
|
837
837
|
|
|
838
838
|
**하단 버튼을 본문(children)에 직접 두지 않는다.** 주 액션은 `button`, 보조 버튼은 `footerLeft` 로 넘긴다 — 푸터 배경·여백·양끝 분리가 컴포넌트 규칙대로 잡히는 자리다. `button` 은 클릭해도 **모달을 닫지 않으므로**(`onClick` 만 발화) 저장 API 응답을 보고 `modalRef.ok()` 로 닫으면 되고, 그 때문에 본문에 버튼을 따로 둘 이유가 없다. `footerLeft` 는 슬롯이라 `SButton` 을 직접 배치하며 `size="md"` 를 명시한다(§3-5-2).
|
|
839
839
|
|
|
840
|
-
**`button` 은 `SButton` 의 prop 을 그대로 받는다** — `icon`·`rightIcon`·`outline`·`disabled` 등을 함께 넘길 수 있다. 단 **`size` 는 타입에 없다**:
|
|
840
|
+
**`button` 은 `SButton` 의 prop 을 그대로 받는다** — `icon`·`rightIcon`·`outline`·`disabled` 등을 함께 넘길 수 있다. 단 **`size` 는 타입에 없다**: 버튼 크기는 놓이는 자리가 정하므로(§3-5-2) 푸터가 준다. 모달·드로어·팝업의 푸터는 **언제나 `md`** 라 받을 것이 없다 — 크기를 고를 수 있는 것은 카드 둘뿐이다(§3-7-8 `footerSize`). **`color` 는 주지 않는 것이 기본**이다 — 주지 않으면 주 액션 규칙대로 `primary` 가 되고, 그 버튼이 파괴적 액션일 때만 §3-5-3 에 따라 `danger` 를 준다. 카드(§3-7-8)의 `button` 도 같다.
|
|
841
841
|
|
|
842
842
|
**확인 모달은 확인 버튼 하나로 세우는 것이 기본이다 — `subButtonLabel` 을 주지 않는다.** 비워 두면 서브 버튼이 아예 서지 않는다. 답하지 않고 나가는 길은 **X 버튼이 이미 맡고**(늘 서 있다), `persistent` 를 켜지 않았으면 백드롭·ESC 로도 닫힌다(§3-3-5).
|
|
843
843
|
|
|
@@ -1339,12 +1339,16 @@ tableRef.current.scrollToRow(row); // 복원
|
|
|
1339
1339
|
| --- | --- |
|
|
1340
1340
|
| 테이블 **행 내부** 인라인 액션 | `xs` |
|
|
1341
1341
|
| 화면·목록 액션 (툴바, `STableBar`) | `sm` |
|
|
1342
|
-
|
|
|
1342
|
+
| **모달·드로어·팝업 푸터** | `md` (고정) |
|
|
1343
1343
|
| **페이지 하단 실행 버튼** (폼 저장·상세 수정 등) | `md` |
|
|
1344
|
+
| **카드 푸터** — 카드가 화면의 주 액션을 쥔 경우 | `md` (`footerSize` 기본값) |
|
|
1345
|
+
| **카드 푸터** — 한 화면에서 부분만 확정하는 카드 | `sm` (`footerSize="sm"`) |
|
|
1344
1346
|
| 스크롤 시 헤더로 승격된 버튼 | `sm` (최대) |
|
|
1345
1347
|
|
|
1346
1348
|
`lg` 는 현재 사용처가 없다. 페이지 골격에서 쓰지 않는다.
|
|
1347
1349
|
|
|
1350
|
+
**푸터 버튼의 크기는 버튼이 아니라 푸터가 정한다.** 모달·드로어·팝업은 예외가 없어 타입에 `size` 가 없고, 카드 둘(`SCard`·`SSectionHeaderCard`)만 `footerSize` 로 고른다 — 자세한 기준은 §3-7-8. **`footerLeft` 슬롯에 직접 배치하는 `SButton` 은 그 푸터와 같은 크기를 명시한다**(모달이면 `size="md"`, `footerSize="sm"` 인 카드면 `size="sm"`). 슬롯까지는 타입이 못 막으므로 어긋나면 좌우 버튼 높이가 갈린다.
|
|
1351
|
+
|
|
1348
1352
|
#### 3-5-3. 파괴적 액션의 채움 / outline
|
|
1349
1353
|
|
|
1350
1354
|
물리적 위치가 아니라 **적용 범위 + 위험도**로 가른다.
|
|
@@ -1805,6 +1809,7 @@ useEffect(() => {
|
|
|
1805
1809
|
- **칸 본문을 통째로 바꾸려면 `dayContent` 다.** 일정으로 표현되지 않는 그날치 요약(재고·매출 같은)을 칸에 얹을 때 쓴다. **슬롯을 준 날짜는 그 날짜의 `events` 를 그리지 않고 목록 판도 열지 않는다** — 한 칸에 둘을 겹쳐 담지 않는다. 일정과 요약을 함께 보여야 하면 요약을 일정 한 건(`events[]`)으로 넣는다.
|
|
1806
1810
|
- **`SCalendarBoard` 는 높이를 부모에게서 받는다.** 행이 그 높이를 균등하게 나눠 갖고, 칸 높이가 다시 "한 칸에 몇 줄이 보일지" 를 정한다. 그래서 **놓는 자리에 높이를 준다** — 페이지 본문의 남은 높이를 채우려면 `SPage` 안에서 스택을 `flex-1 min-h-0` 으로 두고 판에 `h-full` 을 준다. 높이를 주지 않으면 칸이 최소 높이로 주저앉아 한두 줄만 보인다.
|
|
1807
1811
|
- **한 칸에 몇 줄을 펼칠지는 컴포넌트가 잰다.** 조절하는 prop 이 없다 — 칸 높이에서 나오는 값이라 따로 정할 것이 아니다. 줄이 넘치면 마지막 한 줄을 "N개 더보기" 에 내주므로 **접히든 아니든 칸 높이가 같다.** 기간 막대가 접히면 **걸친 날마다 한 건으로** 세므로 날짜별 "N개" 가 서로 다를 수 있다. **소비 앱이 `events` 를 미리 잘라 넘기지 않는다.** 잘라 넘기면 "N개 더보기" 의 수가 실제 건수와 어긋나고, 눌러도 나머지가 나오지 않는다.
|
|
1812
|
+
- **판 밖의 것에 손이 닿았을 때 그에 맞는 일정을 짚어 주려면 `focusedEventId` 다.** 지목한 일정만 또렷하게 남고 나머지 일정과 "N개 더보기" 는 물러난다. **지목한 일정이 "N개 더보기" 에 접혀 있으면 그 더보기 자리에 대신 그려져** 지목하는 동안만 드러나고, 보이던 일정들의 줄 배정은 어느 쪽이든 달라지지 않는다 — 지목이 오가도 판이 출렁이지 않는다. 자리를 내준 칸은 그동안 "더보기" 를 그리지 않으므로, 거기 남은 일정은 칸을 눌러 목록 판으로 본다. **물러나게 하는 것을 앱에서 직접 하지 않는다** — 접혀 있다 드러난 막대는 앱의 CSS 가 닿지 않아 그 하나만 어긋난다. `events[].id` 가 없는 일정은 지목할 수 없다. 호버·포커스를 **감지**하는 것은 앱 몫이고, 판은 "지금 어느 일정인가" 만 받는다.
|
|
1808
1813
|
- **`events[].label` 은 필수다** — 일정이 무엇인지 알리는 부분이라 비워 두지 않는다. 인라인 HTML 을 받으므로 부분 강조가 필요할 때만 태그를 쓰고, 나머지는 `description`·`value` 로 나눠 담는다. 칸이 좁아지면 `label`+`description` 이 한 덩어리로 말줄임되고 `value` 만 끝에 온전히 남는다 — **금액·수량은 반드시 `value` 에 담는다.** `description` 에 넣으면 잘린다.
|
|
1809
1814
|
- `SDatePickerYearListbox`·`SDatePickerMonthListbox` 는 `SDatePicker` 의 mode listbox 조각만 떼어낸 컴포넌트다. 일반 폼 입력에는 `SDatePicker mode="year" | "month"` 를 우선 쓰고, 다른 트리거·팝오버 안에 리스트만 끼워 넣을 때만 직접 쓴다.
|
|
1810
1815
|
|
|
@@ -1929,7 +1934,7 @@ const [selectedId, setSelectedId] = useState<string>();
|
|
|
1929
1934
|
- **카드 안에 카드를 겹치지 않는다.** 섹션 안을 더 나눠야 하면 `SDivider` 로 끊거나(§3-6) 섹션을 둘로 분리한다.
|
|
1930
1935
|
- 안쪽 여백은 `SSectionHeaderCard` 의 `padding` prop 으로 준다 — `p-sd-*` 를 직접 주지 않는다 (§2-2).
|
|
1931
1936
|
|
|
1932
|
-
**카드가 자기 안에서 확정하는 액션을 가지면 하단 버튼을 `children` 에 직접 두지 않는다.** 두 카드 모두 모달·드로어와 같은 하단 액션 영역을 갖는다 — 주 액션은 `button`, 보조 버튼은 `footerLeft` 로 넘긴다(§3-3-4 와 같은 규칙). 배경·상단 구분선·좌우 여백·양끝 분리가 컴포넌트 규칙대로 잡히고, 좌우 끝이 헤더·본문과 맞는다. `footerLeft` 는 슬롯이라 `SButton` 을 직접 배치하며
|
|
1937
|
+
**카드가 자기 안에서 확정하는 액션을 가지면 하단 버튼을 `children` 에 직접 두지 않는다.** 두 카드 모두 모달·드로어와 같은 하단 액션 영역을 갖는다 — 주 액션은 `button`, 보조 버튼은 `footerLeft` 로 넘긴다(§3-3-4 와 같은 규칙). 배경·상단 구분선·좌우 여백·양끝 분리가 컴포넌트 규칙대로 잡히고, 좌우 끝이 헤더·본문과 맞는다. `footerLeft` 는 슬롯이라 `SButton` 을 직접 배치하며 푸터와 같은 크기를 명시한다(§3-5-2).
|
|
1933
1938
|
|
|
1934
1939
|
```tsx
|
|
1935
1940
|
{/* 섹션 안에서 바로 수정·저장하는 인라인 폼 섹션 (§4-4) */}
|
|
@@ -1943,6 +1948,30 @@ const [selectedId, setSelectedId] = useState<string>();
|
|
|
1943
1948
|
</SSectionHeaderCard>
|
|
1944
1949
|
```
|
|
1945
1950
|
|
|
1951
|
+
**카드 푸터만 크기를 고른다 — `footerSize`.** 모달·드로어·팝업의 푸터는 `md` 고정이지만(§3-5-2), 카드는 화면에서 차지하는 자리가 둘로 갈린다.
|
|
1952
|
+
|
|
1953
|
+
| 카드가 놓인 자리 | `footerSize` |
|
|
1954
|
+
| --- | --- |
|
|
1955
|
+
| 카드가 **화면의 주 액션**을 쥔다 (한 폭을 차지하는 상세·폼 섹션) | `md` — 기본값이라 주지 않는다 |
|
|
1956
|
+
| 한 화면에서 **부분만 확정한다** (옆 패널·분할 영역처럼 화면의 일부를 맡는 카드) | `sm` |
|
|
1957
|
+
|
|
1958
|
+
- **`sm` 은 카드에만 있다.** 그 카드가 모달·팝업 안에 들어 있어도 같다 — 모달 자신의 푸터는 여전히 `md` 다.
|
|
1959
|
+
- **`footerSize="sm"` 이면 `footerLeft` 슬롯 버튼도 `size="sm"` 으로 맞춘다.** 슬롯은 타입이 못 막아서, 한쪽만 `md` 로 남으면 좌우 버튼 높이가 갈린 푸터가 된다.
|
|
1960
|
+
- 여백은 `md`·`sm` 이 같다 — 푸터 패딩 토큰이 한 벌이라 **바뀌는 것은 버튼 크기뿐**이다. 여백을 직접 주지 않는다.
|
|
1961
|
+
|
|
1962
|
+
```tsx
|
|
1963
|
+
{/* 화면 오른쪽 패널만 확정하는 카드 — 좌우 버튼 크기를 footerSize 에 맞춘다 */}
|
|
1964
|
+
<SSectionHeaderCard
|
|
1965
|
+
title="옵션 템플릿"
|
|
1966
|
+
marker
|
|
1967
|
+
footerSize="sm"
|
|
1968
|
+
footerLeft={<SButton color="danger" outline size="sm" icon="remove" label="템플릿 삭제" onClick={remove} />}
|
|
1969
|
+
button={{ label: '저장', onClick: save }}
|
|
1970
|
+
>
|
|
1971
|
+
…
|
|
1972
|
+
</SSectionHeaderCard>
|
|
1973
|
+
```
|
|
1974
|
+
|
|
1946
1975
|
**페이지 전체를 확정하는 액션은 카드 푸터가 아니라 페이지 하단에 둔다.** 카드 푸터는 **그 카드 안에서 닫히는 액션**의 자리다 — 여러 섹션을 한 번에 저장하는 버튼을 마지막 카드의 푸터에 넣으면 그 카드에만 걸리는 액션으로 읽힌다. 이때는 §4-4 처럼 카드 밖 하단 줄에 둔다.
|
|
1947
1976
|
|
|
1948
1977
|
#### 3-7-9. SLinearProgress vs SCircleProgress
|
|
@@ -2869,9 +2898,10 @@ export default function ProductDetailPage() {
|
|
|
2869
2898
|
| Prop (Footer) | 용도 |
|
|
2870
2899
|
| --- | --- |
|
|
2871
2900
|
| `button` | 하단 액션 영역 우측 주 액션 (§3-7-8) |
|
|
2872
|
-
| `footerLeft` | 하단 액션 영역 좌측 슬롯 — 보조 버튼. `SButton` 에 `
|
|
2901
|
+
| `footerLeft` | 하단 액션 영역 좌측 슬롯 — 보조 버튼. `SButton` 에 `footerSize` 와 같은 크기를 명시한다 |
|
|
2902
|
+
| `footerSize` | 하단 액션 영역 크기 — `'md'`(기본) / `'sm'`. 판정은 §3-7-8 |
|
|
2873
2903
|
|
|
2874
|
-
|
|
2904
|
+
`button`·`footerLeft` 중 하나라도 주면 하단 액션 영역이 렌더된다. 회색 바탕 + 상단 구분선이며 좌우 끝은 헤더에 맞는다 — 배경·여백을 직접 주지 않는다.
|
|
2875
2905
|
|
|
2876
2906
|
**한 페이지에 섹션 카드가 둘 이상이면 `marker` 를 켠다.** 점은 섹션을 서로 구분할 대상이 여럿일 때만 의미가 있어, 카드가 하나뿐인 페이지에서는 켜지 않는다. 한 페이지 안에서는 켜거나 끄거나 전부 같게 간다.
|
|
2877
2907
|
|
|
@@ -3186,6 +3216,7 @@ export default function ExcelFilePopupPage() {
|
|
|
3186
3216
|
- [ ] 하단 버튼이 양끝 분리(`justify-between`)이고, 되돌리기가 왼쪽 끝 · 실행이 오른쪽 끝인가 (되돌리는 액션이 없어도 양끝 분리는 그대로 — 오른쪽에 모으지 않고 위계가 낮은 쪽을 왼쪽 끝에 둔다)
|
|
3187
3217
|
- [ ] 페이지에 `color="primary"` 채움 버튼이 **1개뿐**인가 (`danger` 채움도 1개, `SDropdownButton` 포함)
|
|
3188
3218
|
- [ ] 버튼 `size` 가 위치 규칙과 맞는가 (행 내부 `xs` / 화면 액션 `sm` / 모달 푸터 `md`)
|
|
3219
|
+
- [ ] 카드 `footerSize` 가 카드가 놓인 자리와 맞고(화면의 주 액션 `md` / 부분만 확정 `sm`, §3-7-8), `footerLeft` 슬롯 버튼의 `size` 를 그 값에 맞췄는가
|
|
3189
3220
|
- [ ] 파괴 액션의 채움/outline 이 **적용 범위 + 위험도** 기준과 맞는가
|
|
3190
3221
|
- [ ] `SGhostButton` 이 아이콘만으로 뜻이 통하는 부가 위치(표·모달 헤더·카드)에만 쓰였고, `ariaLabel` 이 전부 있는가 (라벨이 필요하면 `SButton`)
|
|
3191
3222
|
- [ ] `SGhostButton` 의 `intent` 가 조작 성격과 맞는가 (되돌릴 수 없는 삭제만 `danger`, 진입·추가는 `action`, 나머지는 `default`)
|
|
@@ -36,6 +36,13 @@ export declare const CalendarDayCard: import("react").ForwardRefExoticComponent<
|
|
|
36
36
|
hiddenCount: number;
|
|
37
37
|
/** "더보기" 가 앉는 줄. 접힌 것이 없는 주는 -1 */
|
|
38
38
|
moreLane: number;
|
|
39
|
+
/** "더보기" 자리를 집중된 일정에 내줬는지 — 내준 칸은 "더보기" 를 그리지 않는다 */
|
|
40
|
+
moreReplaced: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 집중할 일정의 `id` (SCalendarBoard 의 `focusedEventId`).
|
|
43
|
+
* 주면 그 일정만 또렷하게 남고 이 칸의 나머지 일정과 "더보기" 는 흐려진다.
|
|
44
|
+
*/
|
|
45
|
+
focusedEventId?: string | null;
|
|
39
46
|
/** 이 칸의 일정 목록 판이 열려 있는지 */
|
|
40
47
|
isOpen: boolean;
|
|
41
48
|
moreLabel?: string;
|
|
@@ -6,13 +6,15 @@ import type { SCalendarBoardEvent } from './types';
|
|
|
6
6
|
* 점 → 레이블(강조) → 설명 → `/` → 값 순서로 한 줄에 눕는다.
|
|
7
7
|
* 가운데 레이블 묶음만 줄어들고 값은 끝에 고정되므로, 좁은 칸에서도 금액이 잘리지 않는다.
|
|
8
8
|
*/
|
|
9
|
-
export declare function CalendarEventButton({ event, onSelect, flatStart, flatEnd, className, style, }: {
|
|
9
|
+
export declare function CalendarEventButton({ event, onSelect, flatStart, flatEnd, dimmed, className, style, }: {
|
|
10
10
|
event: SCalendarBoardEvent;
|
|
11
11
|
onSelect?: (event: SCalendarBoardEvent, e: MouseEvent<HTMLButtonElement>) => void;
|
|
12
12
|
/** 왼쪽 끝이 잘린 조각 — 앞 주에서 이어지므로 모서리를 평평하게 한다 */
|
|
13
13
|
flatStart?: boolean;
|
|
14
14
|
/** 오른쪽 끝이 잘린 조각 — 다음 주로 이어진다 */
|
|
15
15
|
flatEnd?: boolean;
|
|
16
|
+
/** 다른 일정에 집중하는 동안 물러나 있다 — 흐려질 뿐 계속 눌린다 */
|
|
17
|
+
dimmed?: boolean;
|
|
16
18
|
className?: string;
|
|
17
19
|
style?: CSSProperties;
|
|
18
20
|
}): import("react").JSX.Element;
|
|
@@ -7,6 +7,11 @@ export declare const CalendarMoreButton: import("react").ForwardRefExoticCompone
|
|
|
7
7
|
count: number;
|
|
8
8
|
/** 개수 뒤에 붙는 말 */
|
|
9
9
|
label?: string;
|
|
10
|
+
/**
|
|
11
|
+
* 어느 일정에 집중하는 동안 물러나 있다. 여기 남아 있다는 것은 접힌 것 중에
|
|
12
|
+
* 집중 대상이 없다는 뜻이라(있었다면 이 자리를 내줬다) 함께 흐려진다.
|
|
13
|
+
*/
|
|
14
|
+
dimmed?: boolean;
|
|
10
15
|
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
|
|
11
16
|
className?: string;
|
|
12
17
|
style?: CSSProperties;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
| `events?` | `SCalendarBoardEvent[]` | — | 일정 목록. `date`(시작)로 칸에 배분되고, `endDate` 를 주면 그날까지 **하나의 막대로 이어져** 칸 경계를 넘어 그려진다. |
|
|
18
18
|
| `dayColors?` | `Record<string, SCalendarBoardDayColor>` | — | 날짜별 칸 배경. 키는 `YYYY-MM-DD`, 없는 날짜는 `'default'` 다. 그날의 성격(마감·완료·휴무 등)을 칸 전체로 알릴 때 쓴다 — 일정 하나의 색은 `events[].color` 다. |
|
|
19
19
|
| `dayContent?` | `Record<string, ReactNode>` | — | 날짜별 칸 본문. 키는 `YYYY-MM-DD`, 준 날짜는 **일정 자리를 통째로 이 내용이 차지한다** — 그날의 `events` 는 그리지 않고 목록 판도 열리지 않는다. 일정으로 표현되지 않는 것(재고 현황· 매출 요약 같은 그날치 요약)을 칸에 그대로 얹을 때 쓴다. |
|
|
20
|
+
| `focusedEventId?` | `string \| null` | — | 집중할 일정의 `id`. 그 일정만 또렷하게 남고 **나머지 일정과 "N개 더보기" 는 흐려진다** — 판 밖의 무언가(목록의 행 등)에 손이 닿았을 때 판에서 그에 대응하는 일정을 짚어 주는 데 쓴다. 그 일정이 칸에 담기는 줄 수를 넘겨 **"N개 더보기" 에 접혀 있으면, 그 "더보기" 자리에 대신 그려져** 집중하는 동안만 드러난다. 이미 보이고 있으면 자리는 그대로다 — 어느 쪽이든 다른 일정의 줄 배정은 달라지지 않으므로, 집중이 오가도 판이 출렁이지 않는다. 자리를 내준 칸은 그 동안 "더보기" 를 그리지 않는다(한 줄에 둘을 넣을 수 없다). 거기 남은 일정은 칸을 눌러 목록 판으로 본다. `id` 가 없는 일정은 지목할 수 없다. |
|
|
20
21
|
| `todayLabel?` | `string` | `'오늘'` | 헤더 오른쪽 "오늘" 버튼 레이블. 빈 문자열이면 버튼을 그리지 않는다 |
|
|
21
22
|
| `moreLabel?` | `string` | — | "N개" 뒤에 붙는 말 |
|
|
22
23
|
| `headerRight?` | `ReactNode` | — | 헤더 오른쪽 끝에 붙일 추가 컨트롤 |
|
|
@@ -38,6 +38,18 @@ export interface SCalendarBoardProps {
|
|
|
38
38
|
* 매출 요약 같은 그날치 요약)을 칸에 그대로 얹을 때 쓴다.
|
|
39
39
|
*/
|
|
40
40
|
dayContent?: Record<string, ReactNode>;
|
|
41
|
+
/**
|
|
42
|
+
* 집중할 일정의 `id`. 그 일정만 또렷하게 남고 **나머지 일정과 "N개 더보기" 는 흐려진다** —
|
|
43
|
+
* 판 밖의 무언가(목록의 행 등)에 손이 닿았을 때 판에서 그에 대응하는 일정을 짚어 주는 데 쓴다.
|
|
44
|
+
*
|
|
45
|
+
* 그 일정이 칸에 담기는 줄 수를 넘겨 **"N개 더보기" 에 접혀 있으면, 그 "더보기" 자리에 대신
|
|
46
|
+
* 그려져** 집중하는 동안만 드러난다. 이미 보이고 있으면 자리는 그대로다 — 어느 쪽이든 다른
|
|
47
|
+
* 일정의 줄 배정은 달라지지 않으므로, 집중이 오가도 판이 출렁이지 않는다.
|
|
48
|
+
*
|
|
49
|
+
* 자리를 내준 칸은 그 동안 "더보기" 를 그리지 않는다(한 줄에 둘을 넣을 수 없다). 거기 남은
|
|
50
|
+
* 일정은 칸을 눌러 목록 판으로 본다. `id` 가 없는 일정은 지목할 수 없다.
|
|
51
|
+
*/
|
|
52
|
+
focusedEventId?: string | null;
|
|
41
53
|
/** 일정 클릭 */
|
|
42
54
|
onEventClick?: (event: SCalendarBoardEvent, e: MouseEvent<HTMLButtonElement>) => void;
|
|
43
55
|
/**
|
|
@@ -68,4 +80,4 @@ export interface SCalendarBoardProps {
|
|
|
68
80
|
* 보일지" 를 정한다 — 그래서 놓는 자리에 높이를 주어야 한다 (`<div className="h-[640px]">` ·
|
|
69
81
|
* `SPage` 본문의 남은 높이 등). 높이를 주지 않으면 칸이 `dayCard.minHeight` 로 주저앉는다.
|
|
70
82
|
*/
|
|
71
|
-
export declare function SCalendarBoard({ year, month, defaultYear, defaultMonth, onViewChange, selectable, value, onValueChange, events, dayColors, dayContent, onEventClick, onMoreClick, todayLabel, moreLabel, headerRight, className, style, }: SCalendarBoardProps): import("react").JSX.Element;
|
|
83
|
+
export declare function SCalendarBoard({ year, month, defaultYear, defaultMonth, onViewChange, selectable, value, onValueChange, events, dayColors, dayContent, focusedEventId, onEventClick, onMoreClick, todayLabel, moreLabel, headerRight, className, style, }: SCalendarBoardProps): import("react").JSX.Element;
|
|
@@ -36,14 +36,24 @@ export interface CalendarBoardLayout {
|
|
|
36
36
|
hiddenCountByCell: number[];
|
|
37
37
|
/** 주별로 "N개 더보기" 가 앉는 줄. 접힌 것이 없는 주는 -1 */
|
|
38
38
|
moreLaneByWeek: number[];
|
|
39
|
+
/**
|
|
40
|
+
* 칸별로, "더보기" 자리를 집중된 일정(`focusedEventId`)에 내줬는지.
|
|
41
|
+
* 내준 칸은 그 줄에 막대가 앉았으므로 "더보기" 를 그리지 않는다 — 한 줄에 둘을 넣을 수 없다.
|
|
42
|
+
*/
|
|
43
|
+
moreReplacedByCell: boolean[];
|
|
39
44
|
}
|
|
40
45
|
/** 일정의 마지막 날. `endDate` 가 없거나 시작보다 앞서면 하루짜리로 본다 */
|
|
41
46
|
export declare function eventEndDate(event: SCalendarBoardEvent): string;
|
|
42
|
-
export declare function layoutCalendarBoard({ cells, events, rowCapacity, blockedDates, }: {
|
|
47
|
+
export declare function layoutCalendarBoard({ cells, events, rowCapacity, blockedDates, focusedEventId, }: {
|
|
43
48
|
cells: readonly DayCell[];
|
|
44
49
|
events: readonly SCalendarBoardEvent[];
|
|
45
50
|
/** 칸 하나에 담기는 줄 수 */
|
|
46
51
|
rowCapacity: number;
|
|
47
52
|
/** 일정을 그리지 않는 날짜 (`dayContent` 를 받은 칸) */
|
|
48
53
|
blockedDates: ReadonlySet<string>;
|
|
54
|
+
/**
|
|
55
|
+
* 집중할 일정의 `id`. 그 일정이 접혀 있으면 "더보기" 가 예약한 줄을 대신 차지해 노출된다 —
|
|
56
|
+
* 이미 보이고 있으면 아무것도 달라지지 않는다. 줄 배정 자체는 이 값과 무관하다.
|
|
57
|
+
*/
|
|
58
|
+
focusedEventId?: string | null;
|
|
49
59
|
}): CalendarBoardLayout;
|
|
@@ -23,6 +23,11 @@ export declare const CALENDAR_BOARD_EVENT_PRESETS: Record<SCalendarBoardEventCol
|
|
|
23
23
|
* 그래서 이 값을 조절하는 prop 은 없다.
|
|
24
24
|
*/
|
|
25
25
|
export declare const CALENDAR_BOARD_MAX_VISIBLE_EVENTS = 4;
|
|
26
|
+
/**
|
|
27
|
+
* 집중하지 않은 것(다른 일정과 "N개 더보기")이 물러나는 투명도.
|
|
28
|
+
* 대응 토큰이 없어 디자인 값을 그대로 쓴다 — 토큰이 생기면 여기만 갈아끼운다.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CALENDAR_BOARD_DIM_OPACITY = 0.4;
|
|
26
31
|
/** 날짜 칸 배경 — 그날의 성격을 칸 전체로 알린다 */
|
|
27
32
|
export declare const CALENDAR_BOARD_DAY_COLORS: readonly ["default", "danger", "accent", "complete", "dim"];
|
|
28
33
|
export type SCalendarBoardDayColor = (typeof CALENDAR_BOARD_DAY_COLORS)[number];
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
| `bordered?` | `boolean` | `false` | 테두리 표시 여부 |
|
|
12
12
|
| `footerLeft?` | `ReactNode` | — | 하단 액션 영역 좌측 슬롯. 보조 버튼(취소·목록 등)이 오는 자리다. `footerLeft` 또는 `button` 중 하나라도 있으면 하단 액션 영역이 렌더된다. |
|
|
13
13
|
| `button?` | `SFooterButton` | — | 하단 액션 영역 우측 주 액션 버튼 |
|
|
14
|
+
| `footerSize?` | `SFooterSize` | `'md'` | 하단 액션 영역 크기. 기본은 `md`. 한 화면 안에서 **부분만 확정하는 카드**(옆 패널·분할 영역처럼 화면의 일부를 맡는 카드)일 때만 `sm`. 카드가 화면의 주 액션을 쥐고 있으면 모달·페이지와 같은 `md` 다 (AGENTS.md §3-5-2). `footerLeft` 슬롯의 버튼도 같이 맞춘다 — `sm` 이면 슬롯 버튼도 `size="sm"`. |
|
|
14
15
|
| `footerClassName?` | `string` | — | 하단 액션 영역 클래스 |
|
|
15
16
|
|
|
16
17
|
## Dependencies
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
-
import { type SFooterButton } from '../SFooter';
|
|
2
|
+
import { type SFooterButton, type SFooterSize } from '../SFooter';
|
|
3
3
|
export interface SCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
4
|
/** 테두리 표시 여부 */
|
|
5
5
|
bordered?: boolean;
|
|
@@ -10,6 +10,15 @@ export interface SCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
10
10
|
footerLeft?: ReactNode;
|
|
11
11
|
/** 하단 액션 영역 우측 주 액션 버튼 */
|
|
12
12
|
button?: SFooterButton;
|
|
13
|
+
/**
|
|
14
|
+
* 하단 액션 영역 크기. 기본은 `md`.
|
|
15
|
+
*
|
|
16
|
+
* 한 화면 안에서 **부분만 확정하는 카드**(옆 패널·분할 영역처럼 화면의 일부를 맡는 카드)일 때만
|
|
17
|
+
* `sm`. 카드가 화면의 주 액션을 쥐고 있으면 모달·페이지와 같은 `md` 다 (AGENTS.md §3-5-2).
|
|
18
|
+
*
|
|
19
|
+
* `footerLeft` 슬롯의 버튼도 같이 맞춘다 — `sm` 이면 슬롯 버튼도 `size="sm"`.
|
|
20
|
+
*/
|
|
21
|
+
footerSize?: SFooterSize;
|
|
13
22
|
/** 하단 액션 영역 클래스 */
|
|
14
23
|
footerClassName?: string;
|
|
15
24
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| Prop | Type | Default | Description |
|
|
10
10
|
|------|------|---------|-------------|
|
|
11
11
|
| `bg?` | `SFooterBg` | `'white'` | 배경색 |
|
|
12
|
+
| `size?` | `SFooterSize` | `'md'` | 크기. 기본은 `md` — 오버레이 하단 액션 영역의 크기다 |
|
|
12
13
|
| `left?` | `ReactNode` | — | footer 좌측 slot |
|
|
13
14
|
| `children?` | `ReactNode` | — | footer 좌측 slot. left와 함께 쓰면 left 뒤에 렌더된다 |
|
|
14
15
|
| `button?` | `SFooterButton` | — | 우측 기본 액션 버튼 |
|
|
@@ -24,6 +25,19 @@
|
|
|
24
25
|
export type SFooterBg = 'white' | 'grey';
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
### SFooterSize
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
/**
|
|
32
|
+
* footer 크기. 버튼 크기가 여기에 딸려 온다 — `md` 는 `SButton size="md"`, `sm` 은 `"sm"`.
|
|
33
|
+
*
|
|
34
|
+
* 버튼 크기를 따로 받지 않고 footer 자체를 분기하는 이유: 크기를 정하는 것은 버튼이 아니라
|
|
35
|
+
* **버튼이 놓인 자리**이기 때문이다 (AGENTS.md §3-5-2). 좌측 슬롯 버튼까지 한 벌로 맞춰야
|
|
36
|
+
* 하는데, 우측 버튼만 크기를 받으면 좌우가 어긋난 footer 를 만들 길이 열린다.
|
|
37
|
+
*/
|
|
38
|
+
export type SFooterSize = 'sm' | 'md';
|
|
39
|
+
```
|
|
40
|
+
|
|
27
41
|
### SFooterButton
|
|
28
42
|
|
|
29
43
|
```ts
|
|
@@ -33,8 +47,8 @@ export type SFooterBg = 'white' | 'grey';
|
|
|
33
47
|
* 골라 담은 부분집합으로 두지 않는 이유: `SButton` 에 prop 이 늘 때마다 이 목록만 조용히
|
|
34
48
|
* 뒤처져, 아이콘 하나 붙이려 해도 footer 에서는 길이 없는 상태가 된다.
|
|
35
49
|
*
|
|
36
|
-
* **`size` 만 뺀다.** 버튼 크기는 놓이는 위치가
|
|
37
|
-
* (AGENTS.md §3-5-2 —
|
|
50
|
+
* **`size` 만 뺀다.** 버튼 크기는 놓이는 위치가 정하므로 footer 의 `size` 가 정한다
|
|
51
|
+
* (AGENTS.md §3-5-2) — 버튼이 자기 크기를 따로 주장할 자리가 아니다.
|
|
38
52
|
*
|
|
39
53
|
* `label`·`color` 는 주지 않으면 footer 가 주 액션 기본값(`'확인'`·`'primary'`)으로 잡는다.
|
|
40
54
|
* 파괴적 액션이라 `danger` 가 필요한 경우는 열어 둔다 (§3-5-3).
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
2
|
import { type SButtonProps } from '../SButton';
|
|
3
3
|
export type SFooterBg = 'white' | 'grey';
|
|
4
|
+
/**
|
|
5
|
+
* footer 크기. 버튼 크기가 여기에 딸려 온다 — `md` 는 `SButton size="md"`, `sm` 은 `"sm"`.
|
|
6
|
+
*
|
|
7
|
+
* 버튼 크기를 따로 받지 않고 footer 자체를 분기하는 이유: 크기를 정하는 것은 버튼이 아니라
|
|
8
|
+
* **버튼이 놓인 자리**이기 때문이다 (AGENTS.md §3-5-2). 좌측 슬롯 버튼까지 한 벌로 맞춰야
|
|
9
|
+
* 하는데, 우측 버튼만 크기를 받으면 좌우가 어긋난 footer 를 만들 길이 열린다.
|
|
10
|
+
*/
|
|
11
|
+
export type SFooterSize = 'sm' | 'md';
|
|
4
12
|
/**
|
|
5
13
|
* footer 우측 기본 액션 버튼 설정 — `SButton` 의 prop 을 그대로 받는다.
|
|
6
14
|
*
|
|
7
15
|
* 골라 담은 부분집합으로 두지 않는 이유: `SButton` 에 prop 이 늘 때마다 이 목록만 조용히
|
|
8
16
|
* 뒤처져, 아이콘 하나 붙이려 해도 footer 에서는 길이 없는 상태가 된다.
|
|
9
17
|
*
|
|
10
|
-
* **`size` 만 뺀다.** 버튼 크기는 놓이는 위치가
|
|
11
|
-
* (AGENTS.md §3-5-2 —
|
|
18
|
+
* **`size` 만 뺀다.** 버튼 크기는 놓이는 위치가 정하므로 footer 의 `size` 가 정한다
|
|
19
|
+
* (AGENTS.md §3-5-2) — 버튼이 자기 크기를 따로 주장할 자리가 아니다.
|
|
12
20
|
*
|
|
13
21
|
* `label`·`color` 는 주지 않으면 footer 가 주 액션 기본값(`'확인'`·`'primary'`)으로 잡는다.
|
|
14
22
|
* 파괴적 액션이라 `danger` 가 필요한 경우는 열어 둔다 (§3-5-3).
|
|
@@ -21,6 +29,8 @@ export type SFooterButton = Omit<SButtonProps, 'size'>;
|
|
|
21
29
|
export interface SFooterProps {
|
|
22
30
|
/** 배경색 */
|
|
23
31
|
bg?: SFooterBg;
|
|
32
|
+
/** 크기. 기본은 `md` — 오버레이 하단 액션 영역의 크기다 */
|
|
33
|
+
size?: SFooterSize;
|
|
24
34
|
/** footer 좌측 slot */
|
|
25
35
|
left?: ReactNode;
|
|
26
36
|
/** footer 좌측 slot. left와 함께 쓰면 left 뒤에 렌더된다 */
|
|
@@ -39,4 +49,4 @@ export interface SFooterProps {
|
|
|
39
49
|
* 공통화한다. 소비자는 호스트 컴포넌트의 `footerLeft`·`button` prop 으로만 닿는다 —
|
|
40
50
|
* 패키지 public export 에 추가하지 말 것.
|
|
41
51
|
*/
|
|
42
|
-
export declare function SFooter({ bg, left, button, children, className, leftClassName, style, }: SFooterProps): import("react").JSX.Element;
|
|
52
|
+
export declare function SFooter({ bg, size, left, button, children, className, leftClassName, style, }: SFooterProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { SFooter, type SFooterBg, type SFooterButton, type SFooterProps } from './SFooter';
|
|
1
|
+
export { SFooter, type SFooterBg, type SFooterButton, type SFooterProps, type SFooterSize, } from './SFooter';
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| `background?` | `SSectionHeaderCardBodyBackground` | — | 본문 배경. 기본은 `frame` — 카드가 깐 흰 면을 그대로 쓴다. `neutral` 은 바탕을 한 단계 눌러앉혀, 흰 면 덩어리(표·리스트)가 여럿일 때 그것들이 **"면 위에 놓인 객체"로 읽히게** 한다. 위계를 한 단계 더 주고 싶을 때 고르는 선택지이며, **기본값이 틀린 것은 아니다** — 표·리스트는 테두리·라운드·헤더 줄과 간격을 이미 갖고 있어 흰 바탕에서도 경계가 읽힌다. 깔아도 **효과가 없는** 자리가 있다 — 덩어리가 가장자리까지 차는 경우(`padding="none"` 으로 표를 채우면 바탕이 완전히 가려진다), 덩어리에 회색 면이 섞인 경우(그 덩어리가 바탕에 묻힌다), 맨 텍스트나 폼 컨트롤만 있는 본문(떠오를 흰 면이 없다). |
|
|
22
22
|
| `footerLeft?` | `ReactNode` | — | 하단 액션 영역 좌측 슬롯. 보조 버튼(취소·목록 등)이 오는 자리다. `footerLeft` 또는 `button` 중 하나라도 있으면 하단 액션 영역이 렌더된다. |
|
|
23
23
|
| `button?` | `SFooterButton` | — | 하단 액션 영역 우측 주 액션 버튼 |
|
|
24
|
+
| `footerSize?` | `SFooterSize` | `'md'` | 하단 액션 영역 크기. 기본은 `md`. 한 화면 안에서 **부분만 확정하는 카드**(옆 패널·분할 영역처럼 화면의 일부를 맡는 카드)일 때만 `sm`. 카드가 화면의 주 액션을 쥐고 있으면 모달·페이지와 같은 `md` 다 (AGENTS.md §3-5-2). `footerLeft` 슬롯의 버튼도 같이 맞춘다 — `sm` 이면 슬롯 버튼도 `size="sm"`. |
|
|
24
25
|
| `footerClassName?` | `string` | — | 하단 액션 영역 클래스 |
|
|
25
26
|
| `children?` | `SSectionHeaderCardChildren` | — | 바디 콘텐츠. 특정 컴포넌트 타입으로 제한하지 않습니다. |
|
|
26
27
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
-
import { type SFooterButton } from '../SFooter';
|
|
2
|
+
import { type SFooterButton, type SFooterSize } from '../SFooter';
|
|
3
3
|
export type SSectionHeaderCardBodyChildren = ReactNode;
|
|
4
4
|
export type SSectionHeaderCardChildren = ReactNode;
|
|
5
5
|
export type SSectionHeaderCardThickness = false | 'default' | 'accent';
|
|
@@ -50,6 +50,15 @@ export interface SSectionHeaderCardProps extends Omit<HTMLAttributes<HTMLDivElem
|
|
|
50
50
|
footerLeft?: ReactNode;
|
|
51
51
|
/** 하단 액션 영역 우측 주 액션 버튼 */
|
|
52
52
|
button?: SFooterButton;
|
|
53
|
+
/**
|
|
54
|
+
* 하단 액션 영역 크기. 기본은 `md`.
|
|
55
|
+
*
|
|
56
|
+
* 한 화면 안에서 **부분만 확정하는 카드**(옆 패널·분할 영역처럼 화면의 일부를 맡는 카드)일 때만
|
|
57
|
+
* `sm`. 카드가 화면의 주 액션을 쥐고 있으면 모달·페이지와 같은 `md` 다 (AGENTS.md §3-5-2).
|
|
58
|
+
*
|
|
59
|
+
* `footerLeft` 슬롯의 버튼도 같이 맞춘다 — `sm` 이면 슬롯 버튼도 `size="sm"`.
|
|
60
|
+
*/
|
|
61
|
+
footerSize?: SFooterSize;
|
|
53
62
|
/** 하단 액션 영역 클래스 */
|
|
54
63
|
footerClassName?: string;
|
|
55
64
|
/** 바디 콘텐츠. 특정 컴포넌트 타입으로 제한하지 않습니다. */
|
package/dist/index.cjs
CHANGED
|
@@ -4310,6 +4310,7 @@ var SButton = /* @__PURE__ */ react.forwardRef(function SButton2({
|
|
|
4310
4310
|
});
|
|
4311
4311
|
function SFooter({
|
|
4312
4312
|
bg = "white",
|
|
4313
|
+
size = "md",
|
|
4313
4314
|
left,
|
|
4314
4315
|
button,
|
|
4315
4316
|
children,
|
|
@@ -4346,7 +4347,7 @@ function SFooter({
|
|
|
4346
4347
|
SButton,
|
|
4347
4348
|
{
|
|
4348
4349
|
...button,
|
|
4349
|
-
size
|
|
4350
|
+
size,
|
|
4350
4351
|
color: button.color ?? "primary",
|
|
4351
4352
|
label: button.label ?? "\uD655\uC778"
|
|
4352
4353
|
}
|
|
@@ -4355,7 +4356,16 @@ function SFooter({
|
|
|
4355
4356
|
}
|
|
4356
4357
|
);
|
|
4357
4358
|
}
|
|
4358
|
-
var SCard = /* @__PURE__ */ react.forwardRef(function SCard2({
|
|
4359
|
+
var SCard = /* @__PURE__ */ react.forwardRef(function SCard2({
|
|
4360
|
+
bordered = false,
|
|
4361
|
+
footerLeft,
|
|
4362
|
+
button,
|
|
4363
|
+
footerSize = "md",
|
|
4364
|
+
footerClassName,
|
|
4365
|
+
className,
|
|
4366
|
+
children,
|
|
4367
|
+
...rest
|
|
4368
|
+
}, ref) {
|
|
4359
4369
|
const hasFooter = footerLeft != null || button != null;
|
|
4360
4370
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4361
4371
|
"div",
|
|
@@ -4373,6 +4383,7 @@ var SCard = /* @__PURE__ */ react.forwardRef(function SCard2({ bordered = false,
|
|
|
4373
4383
|
SFooter,
|
|
4374
4384
|
{
|
|
4375
4385
|
bg: "grey",
|
|
4386
|
+
size: footerSize,
|
|
4376
4387
|
left: footerLeft,
|
|
4377
4388
|
button,
|
|
4378
4389
|
className: cn("px-(--sys-space-panel-padding-default)", footerClassName)
|
|
@@ -7660,6 +7671,7 @@ var SSectionHeaderCardRootImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
7660
7671
|
background,
|
|
7661
7672
|
footerLeft,
|
|
7662
7673
|
button,
|
|
7674
|
+
footerSize = "md",
|
|
7663
7675
|
footerClassName,
|
|
7664
7676
|
className,
|
|
7665
7677
|
children,
|
|
@@ -7696,6 +7708,7 @@ var SSectionHeaderCardRootImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
7696
7708
|
SFooter,
|
|
7697
7709
|
{
|
|
7698
7710
|
bg: "grey",
|
|
7711
|
+
size: footerSize,
|
|
7699
7712
|
left: footerLeft,
|
|
7700
7713
|
button,
|
|
7701
7714
|
className: cn("px-(--cmp-sectionHeaderCard-header-paddingX)", footerClassName)
|
|
@@ -14004,7 +14017,8 @@ function layoutCalendarBoard({
|
|
|
14004
14017
|
cells,
|
|
14005
14018
|
events,
|
|
14006
14019
|
rowCapacity,
|
|
14007
|
-
blockedDates
|
|
14020
|
+
blockedDates,
|
|
14021
|
+
focusedEventId
|
|
14008
14022
|
}) {
|
|
14009
14023
|
const count = cells.length;
|
|
14010
14024
|
const weekCount = Math.ceil(count / 7);
|
|
@@ -14012,6 +14026,7 @@ function layoutCalendarBoard({
|
|
|
14012
14026
|
const eventsByCell = Array.from({ length: count }, () => []);
|
|
14013
14027
|
const hiddenCountByCell = new Array(count).fill(0);
|
|
14014
14028
|
const moreLaneByWeek = new Array(weekCount).fill(-1);
|
|
14029
|
+
const moreReplacedByCell = new Array(count).fill(false);
|
|
14015
14030
|
const runs = [];
|
|
14016
14031
|
events.forEach((event, order) => {
|
|
14017
14032
|
const start = event.date;
|
|
@@ -14069,9 +14084,15 @@ function layoutCalendarBoard({
|
|
|
14069
14084
|
const week = Math.floor(run.startIndex / 7);
|
|
14070
14085
|
const moreLane = moreLaneByWeek[week];
|
|
14071
14086
|
const limit = moreLane < 0 ? rowCapacity : moreLane;
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14087
|
+
let lane = run.lane;
|
|
14088
|
+
if (lane >= limit) {
|
|
14089
|
+
const focused = focusedEventId != null && run.event.id === focusedEventId && moreLane >= 0;
|
|
14090
|
+
if (!focused) {
|
|
14091
|
+
for (let i = run.startIndex; i <= run.endIndex; i++) hiddenCountByCell[i] += 1;
|
|
14092
|
+
continue;
|
|
14093
|
+
}
|
|
14094
|
+
lane = moreLane;
|
|
14095
|
+
for (let i = run.startIndex; i <= run.endIndex; i++) moreReplacedByCell[i] = true;
|
|
14075
14096
|
}
|
|
14076
14097
|
const { event } = run;
|
|
14077
14098
|
segmentsByCell[run.startIndex].push({
|
|
@@ -14079,12 +14100,18 @@ function layoutCalendarBoard({
|
|
|
14079
14100
|
key: `${event.id ?? `${event.date}-${run.order}`}-${run.startIndex}`,
|
|
14080
14101
|
startIndex: run.startIndex,
|
|
14081
14102
|
span: run.endIndex - run.startIndex + 1,
|
|
14082
|
-
lane
|
|
14103
|
+
lane,
|
|
14083
14104
|
startsHere: cells[run.startIndex].date === event.date,
|
|
14084
14105
|
endsHere: cells[run.endIndex].date === eventEndDate(event)
|
|
14085
14106
|
});
|
|
14086
14107
|
}
|
|
14087
|
-
return {
|
|
14108
|
+
return {
|
|
14109
|
+
segmentsByCell,
|
|
14110
|
+
eventsByCell,
|
|
14111
|
+
hiddenCountByCell,
|
|
14112
|
+
moreLaneByWeek,
|
|
14113
|
+
moreReplacedByCell
|
|
14114
|
+
};
|
|
14088
14115
|
}
|
|
14089
14116
|
|
|
14090
14117
|
// src/components/SCalendarBoard/calendarBoard.config.ts
|
|
@@ -14114,6 +14141,7 @@ var CALENDAR_BOARD_EVENT_PRESETS = {
|
|
|
14114
14141
|
white: { bg: BG("white"), dot: "grey" }
|
|
14115
14142
|
};
|
|
14116
14143
|
var CALENDAR_BOARD_MAX_VISIBLE_EVENTS = 4;
|
|
14144
|
+
var CALENDAR_BOARD_DIM_OPACITY = 0.4;
|
|
14117
14145
|
var CALENDAR_BOARD_DAY_COLORS = [
|
|
14118
14146
|
"default",
|
|
14119
14147
|
"danger",
|
|
@@ -14133,6 +14161,7 @@ function CalendarEventButton({
|
|
|
14133
14161
|
onSelect,
|
|
14134
14162
|
flatStart = false,
|
|
14135
14163
|
flatEnd = false,
|
|
14164
|
+
dimmed = false,
|
|
14136
14165
|
className,
|
|
14137
14166
|
style
|
|
14138
14167
|
}) {
|
|
@@ -14160,7 +14189,11 @@ function CalendarEventButton({
|
|
|
14160
14189
|
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
14161
14190
|
className
|
|
14162
14191
|
),
|
|
14163
|
-
style: {
|
|
14192
|
+
style: {
|
|
14193
|
+
...style,
|
|
14194
|
+
"--ceb-bg": preset.bg,
|
|
14195
|
+
...dimmed && { opacity: CALENDAR_BOARD_DIM_OPACITY }
|
|
14196
|
+
},
|
|
14164
14197
|
onClick: (e) => {
|
|
14165
14198
|
if (disabled) return;
|
|
14166
14199
|
onSelect?.(event, e);
|
|
@@ -14204,7 +14237,7 @@ function CalendarEventButton({
|
|
|
14204
14237
|
}
|
|
14205
14238
|
);
|
|
14206
14239
|
}
|
|
14207
|
-
var CalendarMoreButton = /* @__PURE__ */ react.forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", onClick, className, style }, ref) {
|
|
14240
|
+
var CalendarMoreButton = /* @__PURE__ */ react.forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", dimmed = false, onClick, className, style }, ref) {
|
|
14208
14241
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14209
14242
|
"button",
|
|
14210
14243
|
{
|
|
@@ -14217,7 +14250,7 @@ var CalendarMoreButton = /* @__PURE__ */ react.forwardRef(function CalendarMoreB
|
|
|
14217
14250
|
"bg-(--cmp-calendarBoard-moreButton-bg)",
|
|
14218
14251
|
className
|
|
14219
14252
|
),
|
|
14220
|
-
style,
|
|
14253
|
+
style: dimmed ? { ...style, opacity: CALENDAR_BOARD_DIM_OPACITY } : style,
|
|
14221
14254
|
onClick,
|
|
14222
14255
|
children: [
|
|
14223
14256
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14252,6 +14285,8 @@ var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2
|
|
|
14252
14285
|
body,
|
|
14253
14286
|
hiddenCount,
|
|
14254
14287
|
moreLane,
|
|
14288
|
+
moreReplaced,
|
|
14289
|
+
focusedEventId,
|
|
14255
14290
|
isOpen,
|
|
14256
14291
|
moreLabel,
|
|
14257
14292
|
onDaySelect,
|
|
@@ -14259,6 +14294,7 @@ var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2
|
|
|
14259
14294
|
onOpenEvents,
|
|
14260
14295
|
...rest
|
|
14261
14296
|
}, ref) {
|
|
14297
|
+
const focusing = focusedEventId != null;
|
|
14262
14298
|
const hasEvents = dayEventCount > 0;
|
|
14263
14299
|
const interactive = selectable || hasEvents;
|
|
14264
14300
|
const activate = () => {
|
|
@@ -14320,6 +14356,7 @@ var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2
|
|
|
14320
14356
|
event: segment.event,
|
|
14321
14357
|
flatStart: !segment.startsHere,
|
|
14322
14358
|
flatEnd: !segment.endsHere,
|
|
14359
|
+
dimmed: focusing && segment.event.id !== focusedEventId,
|
|
14323
14360
|
className: "absolute z-10",
|
|
14324
14361
|
style: {
|
|
14325
14362
|
top: laneTop(segment.lane),
|
|
@@ -14333,11 +14370,12 @@ var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2
|
|
|
14333
14370
|
},
|
|
14334
14371
|
segment.key
|
|
14335
14372
|
)),
|
|
14336
|
-
body == null && hiddenCount > 0 && moreLane >= 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14373
|
+
body == null && hiddenCount > 0 && moreLane >= 0 && !moreReplaced && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14337
14374
|
CalendarMoreButton,
|
|
14338
14375
|
{
|
|
14339
14376
|
count: hiddenCount,
|
|
14340
14377
|
label: moreLabel,
|
|
14378
|
+
dimmed: focusing,
|
|
14341
14379
|
className: "absolute z-10",
|
|
14342
14380
|
style: {
|
|
14343
14381
|
top: laneTop(moreLane),
|
|
@@ -14435,6 +14473,7 @@ function SCalendarBoard({
|
|
|
14435
14473
|
events,
|
|
14436
14474
|
dayColors,
|
|
14437
14475
|
dayContent,
|
|
14476
|
+
focusedEventId,
|
|
14438
14477
|
onEventClick,
|
|
14439
14478
|
onMoreClick,
|
|
14440
14479
|
todayLabel = "\uC624\uB298",
|
|
@@ -14485,8 +14524,14 @@ function SCalendarBoard({
|
|
|
14485
14524
|
const blockedDates = new Set(
|
|
14486
14525
|
cells.filter((cell) => dayContent?.[cell.date] != null).map((cell) => cell.date)
|
|
14487
14526
|
);
|
|
14488
|
-
return layoutCalendarBoard({
|
|
14489
|
-
|
|
14527
|
+
return layoutCalendarBoard({
|
|
14528
|
+
cells,
|
|
14529
|
+
events: events ?? [],
|
|
14530
|
+
rowCapacity,
|
|
14531
|
+
blockedDates,
|
|
14532
|
+
focusedEventId
|
|
14533
|
+
});
|
|
14534
|
+
}, [cells, events, rowCapacity, dayContent, focusedEventId]);
|
|
14490
14535
|
const openIndex = openDate == null ? -1 : cells.findIndex((cell) => cell.date === openDate);
|
|
14491
14536
|
const openEvents = openIndex < 0 ? [] : layout.eventsByCell[openIndex];
|
|
14492
14537
|
react.useLayoutEffect(() => {
|
|
@@ -14647,6 +14692,8 @@ function SCalendarBoard({
|
|
|
14647
14692
|
body: content,
|
|
14648
14693
|
hiddenCount: layout.hiddenCountByCell[index],
|
|
14649
14694
|
moreLane: layout.moreLaneByWeek[Math.floor(index / 7)],
|
|
14695
|
+
moreReplaced: layout.moreReplacedByCell[index],
|
|
14696
|
+
focusedEventId,
|
|
14650
14697
|
isOpen: openDate === cell.date,
|
|
14651
14698
|
moreLabel,
|
|
14652
14699
|
onDaySelect: (date) => onValueChange?.(date, list),
|