@3w-witim/ui 0.1.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/README.md +23 -0
- package/dist/calendar/index.css +37 -0
- package/dist/calendar/index.css.map +1 -0
- package/dist/calendar/index.d.mts +55 -0
- package/dist/calendar/index.d.ts +55 -0
- package/dist/calendar/index.js +169 -0
- package/dist/calendar/index.js.map +1 -0
- package/dist/calendar/index.mjs +143 -0
- package/dist/calendar/index.mjs.map +1 -0
- package/dist/icons/index.d.mts +229 -0
- package/dist/icons/index.d.ts +229 -0
- package/dist/icons/index.js +678 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/icons/index.mjs +568 -0
- package/dist/icons/index.mjs.map +1 -0
- package/dist/index.d.mts +971 -0
- package/dist/index.d.ts +971 -0
- package/dist/index.js +3739 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3584 -0
- package/dist/index.mjs.map +1 -0
- package/dist/tailwind-preset.cjs +134 -0
- package/dist/tokens.css +662 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @3w-witim/ui — WITIM 디자인시스템 컴포넌트 라이브러리
|
|
2
|
+
|
|
3
|
+
witim 시맨틱 토큰(`@workb/design-system`) 기반 프레젠테이션 컴포넌트 + Storybook.
|
|
4
|
+
|
|
5
|
+
## 실행
|
|
6
|
+
|
|
7
|
+
- Storybook 개발: `pnpm storybook:ui` (포트 6009)
|
|
8
|
+
- 정적 빌드: `pnpm storybook:build:ui`
|
|
9
|
+
|
|
10
|
+
## 작성 규칙 (디자이너/Claude)
|
|
11
|
+
|
|
12
|
+
- 토큰: [`docs/design-system/token-cheatsheet.md`](../../docs/design-system/token-cheatsheet.md)
|
|
13
|
+
- 스토리: [`docs/design-system/storybook-authoring-guide.md`](../../docs/design-system/storybook-authoring-guide.md)
|
|
14
|
+
- 정본 예시: `src/button.tsx` + `src/button.stories.tsx`
|
|
15
|
+
|
|
16
|
+
## 배선
|
|
17
|
+
|
|
18
|
+
- 토큰 유틸 정의: `@workb/design-system/tokens/tailwind.tokens.cjs` (Tailwind preset)
|
|
19
|
+
- CSS 변수(라이트/다크): `src/styles.css` → `@workb/design-system/tokens/tokens.css`
|
|
20
|
+
|
|
21
|
+
## 향후
|
|
22
|
+
|
|
23
|
+
- npm 공개 배포(W4), 데스크탑/웹이 이 패키지를 소비 예정.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* ../design-system/tokens/calendar-label-tokens.css */
|
|
2
|
+
:root,
|
|
3
|
+
[data-theme=light] {
|
|
4
|
+
--color-witim-amber-solid: #f59e0b;
|
|
5
|
+
--color-witim-amber-light-bg: #fef3da;
|
|
6
|
+
--color-witim-amber-light-tx: #8a5805;
|
|
7
|
+
--color-witim-amber-dark-bg: #6e4a0e;
|
|
8
|
+
--color-witim-amber-dark-tx: #f7cf86;
|
|
9
|
+
--color-witim-emerald-solid: #10b981;
|
|
10
|
+
--color-witim-emerald-light-bg: #e2f6ef;
|
|
11
|
+
--color-witim-emerald-light-tx: #07795a;
|
|
12
|
+
--color-witim-emerald-dark-bg: #11533f;
|
|
13
|
+
--color-witim-emerald-dark-tx: #9de7cd;
|
|
14
|
+
--cal-vacation-solid: var(--color-witim-amber-solid);
|
|
15
|
+
--cal-vacation-bg: var(--color-witim-amber-light-bg);
|
|
16
|
+
--cal-vacation-text: var(--color-witim-amber-light-tx);
|
|
17
|
+
--cal-project-solid: var(--color-witim-emerald-solid);
|
|
18
|
+
--cal-project-bg: var(--color-witim-emerald-light-bg);
|
|
19
|
+
--cal-project-text: var(--color-witim-emerald-light-tx);
|
|
20
|
+
--cal-mine-solid: #455fff;
|
|
21
|
+
--cal-mine-bg: #ecefff;
|
|
22
|
+
--cal-mine-text: #3142c9;
|
|
23
|
+
--cal-holiday-solid: #ef4444;
|
|
24
|
+
--cal-holiday-bg: #fdecec;
|
|
25
|
+
--cal-holiday-text: #c0392b;
|
|
26
|
+
}
|
|
27
|
+
[data-theme=dark] {
|
|
28
|
+
--cal-vacation-bg: var(--color-witim-amber-dark-bg);
|
|
29
|
+
--cal-vacation-text: var(--color-witim-amber-dark-tx);
|
|
30
|
+
--cal-project-bg: var(--color-witim-emerald-dark-bg);
|
|
31
|
+
--cal-project-text: var(--color-witim-emerald-dark-tx);
|
|
32
|
+
--cal-mine-bg: #33429e;
|
|
33
|
+
--cal-mine-text: #c5cdff;
|
|
34
|
+
--cal-holiday-bg: #7a2e2e;
|
|
35
|
+
--cal-holiday-text: #f4b4b4;
|
|
36
|
+
}
|
|
37
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../design-system/tokens/calendar-label-tokens.css"],"sourcesContent":["/* =============================================================================\n * WITIM · 캘린더 라벨 컬러 토큰 (F안 확정 · proposal3 렌더링과 동일 · 2026-06-25)\n * -----------------------------------------------------------------------------\n * ⛔ CALENDAR-ONLY — 메인 UI 절대 금지\n * amber(휴가) · emerald(프로젝트) 색은 오직 캘린더 라벨에서만 사용.\n * 버튼 · 배지 · 칩 · 아이콘 · 링크 · 텍스트 등 메인 UI 어디에도 쓰지 않음.\n * 메인 UI 색은 brand(blue) · danger(red) · gray 만 사용.\n * (위반 시 PreToolUse 훅 'calendar-color-guard' 가 편집을 차단.)\n * -----------------------------------------------------------------------------\n * Light = 연한 틴트 배경 + 진한 텍스트 / Dark = 솔리드 채움 배경 + 밝은 텍스트\n *\n * Solid·dot Light BG Light Text Dark BG Dark Text\n * 내 일정 #455FFF #ECEFFF #3142C9 #33429E #C5CDFF (blue · 시스템)\n * 휴가 #F59E0B #FEF3DA #8A5805 #6E4A0E #F7CF86 (amber · 전용)\n * 프로젝트 #10B981 #E2F6EF #07795A #11533F #9DE7CD (emerald · 전용)\n * 공휴일 #EF4444 #FDECEC #C0392B #7A2E2E #F4B4B4 (red · 시스템)\n * ============================================================================= */\n\n:root,\n[data-theme=\"light\"] {\n /* ---- primitive · CALENDAR-ONLY ---- */\n /* Amber (휴가) */\n --color-witim-amber-solid: #f59e0b; /* anchor / dot / 솔리드 */\n --color-witim-amber-light-bg: #fef3da; /* light 라벨 배경 */\n --color-witim-amber-light-tx: #8a5805; /* light 라벨 텍스트 */\n --color-witim-amber-dark-bg: #6e4a0e; /* dark 라벨 배경 (솔리드 채움) */\n --color-witim-amber-dark-tx: #f7cf86; /* dark 라벨 텍스트 */\n\n /* Emerald (프로젝트) */\n --color-witim-emerald-solid: #10b981;\n --color-witim-emerald-light-bg: #e2f6ef;\n --color-witim-emerald-light-tx: #07795a;\n --color-witim-emerald-dark-bg: #11533f;\n --color-witim-emerald-dark-tx: #9de7cd;\n\n /* ---- semantic · CALENDAR-ONLY (light = default) ---- */\n --cal-vacation-solid: var(--color-witim-amber-solid);\n --cal-vacation-bg: var(--color-witim-amber-light-bg);\n --cal-vacation-text: var(--color-witim-amber-light-tx);\n\n --cal-project-solid: var(--color-witim-emerald-solid);\n --cal-project-bg: var(--color-witim-emerald-light-bg);\n --cal-project-text: var(--color-witim-emerald-light-tx);\n\n /* 내 일정/공휴일 = 전용 토큰 신설 없이 시스템 색 재사용 */\n --cal-mine-solid: #455fff;\n --cal-mine-bg: #ecefff;\n --cal-mine-text: #3142c9;\n --cal-holiday-solid: #ef4444;\n --cal-holiday-bg: #fdecec;\n --cal-holiday-text: #c0392b;\n}\n\n/* ---- dark theme overrides · CALENDAR-ONLY ---- */\n[data-theme=\"dark\"] {\n --cal-vacation-bg: var(--color-witim-amber-dark-bg); /* #6E4A0E 솔리드 */\n --cal-vacation-text: var(--color-witim-amber-dark-tx); /* #F7CF86 */\n --cal-project-bg: var(--color-witim-emerald-dark-bg); /* #11533F 솔리드 */\n --cal-project-text: var(--color-witim-emerald-dark-tx); /* #9DE7CD */\n\n --cal-mine-bg: #33429e;\n --cal-mine-text: #c5cdff;\n --cal-holiday-bg: #7a2e2e;\n --cal-holiday-text: #f4b4b4;\n}\n\n/* ---- 사용 예시 (캘린더 라벨에서만) ----\n * .cal-label--vacation { background: var(--cal-vacation-bg); color: var(--cal-vacation-text); }\n * .cal-label--project { background: var(--cal-project-bg); color: var(--cal-project-text); }\n * .cal-dot--vacation { background: var(--cal-vacation-solid); } // #F59E0B\n * .cal-dot--project { background: var(--cal-project-solid); } // #10B981\n */\n"],"mappings":";AAkBA;AACA,CAAC;AAGC,6BAA2B;AAC3B,gCAA8B;AAC9B,gCAA8B;AAC9B,+BAA6B;AAC7B,+BAA6B;AAG7B,+BAA6B;AAC7B,kCAAgC;AAChC,kCAAgC;AAChC,iCAA+B;AAC/B,iCAA+B;AAG/B,wBAAsB,IAAI;AAC1B,qBAAmB,IAAI;AACvB,uBAAqB,IAAI;AAEzB,uBAAqB,IAAI;AACzB,oBAAkB,IAAI;AACtB,sBAAoB,IAAI;AAGxB,oBAAkB;AAClB,iBAAe;AACf,mBAAiB;AACjB,uBAAqB;AACrB,oBAAkB;AAClB,sBAAoB;AACtB;AAGA,CAAC;AACC,qBAAmB,IAAI;AACvB,uBAAqB,IAAI;AACzB,oBAAkB,IAAI;AACtB,sBAAoB,IAAI;AAExB,iBAAe;AACf,mBAAiB;AACjB,oBAAkB;AAClB,sBAAoB;AACtB;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type CalendarLabelType = "mine" | "vacation" | "project" | "holiday";
|
|
4
|
+
/** 라벨 타입 → --cal-* 토큰 클래스 맵 (색은 전부 var(--cal-*) 참조, 하드코딩 없음). */
|
|
5
|
+
declare const CALENDAR_LABELS: Record<CalendarLabelType, {
|
|
6
|
+
name: string;
|
|
7
|
+
chip: string;
|
|
8
|
+
dot: string;
|
|
9
|
+
}>;
|
|
10
|
+
interface CalendarEventChipProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
11
|
+
/** 라벨 타입 (색은 CALENDAR-ONLY 토큰에서 자동 적용, 다크 전환 포함) */
|
|
12
|
+
type: CalendarLabelType;
|
|
13
|
+
}
|
|
14
|
+
/** 캘린더 이벤트 라벨 칩. 색은 --cal-* 예외 토큰으로 캡슐화됨. */
|
|
15
|
+
declare const CalendarEventChip: React.ForwardRefExoticComponent<CalendarEventChipProps & React.RefAttributes<HTMLSpanElement>>;
|
|
16
|
+
interface CalendarLabelLegendProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
17
|
+
}
|
|
18
|
+
/** 라벨 타입 범례 (dot + 이름). */
|
|
19
|
+
declare const CalendarLabelLegend: React.ForwardRefExoticComponent<CalendarLabelLegendProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
|
|
21
|
+
/** 캘린더 한 칸에 들어가는 이벤트 하나 (라벨 텍스트 + 예외색 타입). */
|
|
22
|
+
type CalendarEvent = {
|
|
23
|
+
label: string;
|
|
24
|
+
type: CalendarLabelType;
|
|
25
|
+
};
|
|
26
|
+
/** 캘린더 한 칸(날짜) 데이터. */
|
|
27
|
+
type CalendarDayData = {
|
|
28
|
+
/** 날짜 숫자 */
|
|
29
|
+
day: number;
|
|
30
|
+
/** 해당 날짜의 이벤트 라벨들 */
|
|
31
|
+
events?: CalendarEvent[];
|
|
32
|
+
/** 당월 외 날짜(흐리게 표시) */
|
|
33
|
+
muted?: boolean;
|
|
34
|
+
};
|
|
35
|
+
interface CalendarDayCellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
36
|
+
day: number;
|
|
37
|
+
events?: CalendarEvent[];
|
|
38
|
+
muted?: boolean;
|
|
39
|
+
/** 최대 표시 이벤트 수. 초과분은 "+N 더보기"로 요약. 기본 3 */
|
|
40
|
+
maxVisible?: number;
|
|
41
|
+
/** "더보기" 클릭 콜백(선택). 넘겨진 인자는 숨겨진 이벤트 배열. */
|
|
42
|
+
onShowMore?: (hidden: CalendarEvent[], e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
43
|
+
}
|
|
44
|
+
declare const CalendarDayCell: React.ForwardRefExoticComponent<CalendarDayCellProps & React.RefAttributes<HTMLDivElement>>;
|
|
45
|
+
interface CalendarMonthGridProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
46
|
+
/** 표시할 날짜 칸들 */
|
|
47
|
+
days: CalendarDayData[];
|
|
48
|
+
/** 그리드 열 수 (기본 7 — 주 단위) */
|
|
49
|
+
columns?: number;
|
|
50
|
+
/** 상단 라벨 범례 표시 여부 */
|
|
51
|
+
showLegend?: boolean;
|
|
52
|
+
}
|
|
53
|
+
declare const CalendarMonthGrid: React.ForwardRefExoticComponent<CalendarMonthGridProps & React.RefAttributes<HTMLDivElement>>;
|
|
54
|
+
|
|
55
|
+
export { CALENDAR_LABELS, CalendarDayCell, type CalendarDayCellProps, type CalendarDayData, type CalendarEvent, CalendarEventChip, type CalendarEventChipProps, CalendarLabelLegend, type CalendarLabelLegendProps, type CalendarLabelType, CalendarMonthGrid, type CalendarMonthGridProps };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type CalendarLabelType = "mine" | "vacation" | "project" | "holiday";
|
|
4
|
+
/** 라벨 타입 → --cal-* 토큰 클래스 맵 (색은 전부 var(--cal-*) 참조, 하드코딩 없음). */
|
|
5
|
+
declare const CALENDAR_LABELS: Record<CalendarLabelType, {
|
|
6
|
+
name: string;
|
|
7
|
+
chip: string;
|
|
8
|
+
dot: string;
|
|
9
|
+
}>;
|
|
10
|
+
interface CalendarEventChipProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
11
|
+
/** 라벨 타입 (색은 CALENDAR-ONLY 토큰에서 자동 적용, 다크 전환 포함) */
|
|
12
|
+
type: CalendarLabelType;
|
|
13
|
+
}
|
|
14
|
+
/** 캘린더 이벤트 라벨 칩. 색은 --cal-* 예외 토큰으로 캡슐화됨. */
|
|
15
|
+
declare const CalendarEventChip: React.ForwardRefExoticComponent<CalendarEventChipProps & React.RefAttributes<HTMLSpanElement>>;
|
|
16
|
+
interface CalendarLabelLegendProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
17
|
+
}
|
|
18
|
+
/** 라벨 타입 범례 (dot + 이름). */
|
|
19
|
+
declare const CalendarLabelLegend: React.ForwardRefExoticComponent<CalendarLabelLegendProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
|
|
21
|
+
/** 캘린더 한 칸에 들어가는 이벤트 하나 (라벨 텍스트 + 예외색 타입). */
|
|
22
|
+
type CalendarEvent = {
|
|
23
|
+
label: string;
|
|
24
|
+
type: CalendarLabelType;
|
|
25
|
+
};
|
|
26
|
+
/** 캘린더 한 칸(날짜) 데이터. */
|
|
27
|
+
type CalendarDayData = {
|
|
28
|
+
/** 날짜 숫자 */
|
|
29
|
+
day: number;
|
|
30
|
+
/** 해당 날짜의 이벤트 라벨들 */
|
|
31
|
+
events?: CalendarEvent[];
|
|
32
|
+
/** 당월 외 날짜(흐리게 표시) */
|
|
33
|
+
muted?: boolean;
|
|
34
|
+
};
|
|
35
|
+
interface CalendarDayCellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
36
|
+
day: number;
|
|
37
|
+
events?: CalendarEvent[];
|
|
38
|
+
muted?: boolean;
|
|
39
|
+
/** 최대 표시 이벤트 수. 초과분은 "+N 더보기"로 요약. 기본 3 */
|
|
40
|
+
maxVisible?: number;
|
|
41
|
+
/** "더보기" 클릭 콜백(선택). 넘겨진 인자는 숨겨진 이벤트 배열. */
|
|
42
|
+
onShowMore?: (hidden: CalendarEvent[], e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
43
|
+
}
|
|
44
|
+
declare const CalendarDayCell: React.ForwardRefExoticComponent<CalendarDayCellProps & React.RefAttributes<HTMLDivElement>>;
|
|
45
|
+
interface CalendarMonthGridProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
46
|
+
/** 표시할 날짜 칸들 */
|
|
47
|
+
days: CalendarDayData[];
|
|
48
|
+
/** 그리드 열 수 (기본 7 — 주 단위) */
|
|
49
|
+
columns?: number;
|
|
50
|
+
/** 상단 라벨 범례 표시 여부 */
|
|
51
|
+
showLegend?: boolean;
|
|
52
|
+
}
|
|
53
|
+
declare const CalendarMonthGrid: React.ForwardRefExoticComponent<CalendarMonthGridProps & React.RefAttributes<HTMLDivElement>>;
|
|
54
|
+
|
|
55
|
+
export { CALENDAR_LABELS, CalendarDayCell, type CalendarDayCellProps, type CalendarDayData, type CalendarEvent, CalendarEventChip, type CalendarEventChipProps, CalendarLabelLegend, type CalendarLabelLegendProps, type CalendarLabelType, CalendarMonthGrid, type CalendarMonthGridProps };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var clsx = require('clsx');
|
|
5
|
+
var tailwindMerge = require('tailwind-merge');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
28
|
+
// src/calendar/calendar-label.tsx
|
|
29
|
+
function cn(...inputs) {
|
|
30
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
31
|
+
}
|
|
32
|
+
var CALENDAR_LABELS = {
|
|
33
|
+
mine: {
|
|
34
|
+
name: "\uB0B4 \uC77C\uC815",
|
|
35
|
+
chip: "bg-[var(--cal-mine-bg)] text-[var(--cal-mine-text)]",
|
|
36
|
+
dot: "bg-[var(--cal-mine-solid)]"
|
|
37
|
+
},
|
|
38
|
+
vacation: {
|
|
39
|
+
name: "\uD734\uAC00",
|
|
40
|
+
chip: "bg-[var(--cal-vacation-bg)] text-[var(--cal-vacation-text)]",
|
|
41
|
+
dot: "bg-[var(--cal-vacation-solid)]"
|
|
42
|
+
},
|
|
43
|
+
project: {
|
|
44
|
+
name: "\uD504\uB85C\uC81D\uD2B8",
|
|
45
|
+
chip: "bg-[var(--cal-project-bg)] text-[var(--cal-project-text)]",
|
|
46
|
+
dot: "bg-[var(--cal-project-solid)]"
|
|
47
|
+
},
|
|
48
|
+
holiday: {
|
|
49
|
+
name: "\uACF5\uD734\uC77C",
|
|
50
|
+
chip: "bg-[var(--cal-holiday-bg)] text-[var(--cal-holiday-text)]",
|
|
51
|
+
dot: "bg-[var(--cal-holiday-solid)]"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var CalendarEventChip = React__namespace.forwardRef(({ type, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
55
|
+
"span",
|
|
56
|
+
{
|
|
57
|
+
ref,
|
|
58
|
+
className: cn(
|
|
59
|
+
"block truncate rounded px-2 py-1 text-xs font-semibold",
|
|
60
|
+
CALENDAR_LABELS[type].chip,
|
|
61
|
+
className
|
|
62
|
+
),
|
|
63
|
+
...props,
|
|
64
|
+
children: children ?? CALENDAR_LABELS[type].name
|
|
65
|
+
}
|
|
66
|
+
));
|
|
67
|
+
CalendarEventChip.displayName = "CalendarEventChip";
|
|
68
|
+
var CalendarLabelLegend = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
ref,
|
|
72
|
+
className: cn("flex flex-wrap gap-x-3 gap-y-1.5 text-xs", className),
|
|
73
|
+
...props,
|
|
74
|
+
children: Object.keys(CALENDAR_LABELS).map((k) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-text-default", children: [
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
"span",
|
|
77
|
+
{
|
|
78
|
+
className: cn("h-2.5 w-2.5 rounded-full", CALENDAR_LABELS[k].dot)
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
CALENDAR_LABELS[k].name
|
|
82
|
+
] }, k))
|
|
83
|
+
}
|
|
84
|
+
));
|
|
85
|
+
CalendarLabelLegend.displayName = "CalendarLabelLegend";
|
|
86
|
+
var CalendarDayCell = React__namespace.forwardRef(
|
|
87
|
+
({
|
|
88
|
+
day,
|
|
89
|
+
events = [],
|
|
90
|
+
muted = false,
|
|
91
|
+
maxVisible = 3,
|
|
92
|
+
onShowMore,
|
|
93
|
+
className,
|
|
94
|
+
...props
|
|
95
|
+
}, ref) => {
|
|
96
|
+
const visible = events.slice(0, maxVisible);
|
|
97
|
+
const hidden = events.slice(maxVisible);
|
|
98
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99
|
+
"div",
|
|
100
|
+
{
|
|
101
|
+
ref,
|
|
102
|
+
className: cn(
|
|
103
|
+
"min-h-[70px] rounded-lg border border-border-subtle bg-surface-default p-2",
|
|
104
|
+
muted && "opacity-50",
|
|
105
|
+
className
|
|
106
|
+
),
|
|
107
|
+
...props,
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1.5 text-[11.5px] font-bold text-text-default", children: day }),
|
|
110
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
111
|
+
visible.map((e, i) => /* @__PURE__ */ jsxRuntime.jsx(CalendarEventChip, { type: e.type, title: e.label, children: e.label }, i)),
|
|
112
|
+
hidden.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
113
|
+
"button",
|
|
114
|
+
{
|
|
115
|
+
type: "button",
|
|
116
|
+
onClick: (e) => onShowMore?.(hidden, e),
|
|
117
|
+
className: "block w-full truncate rounded px-2 py-0.5 text-left text-xs font-medium text-text-subtle hover:bg-surface-hover",
|
|
118
|
+
children: [
|
|
119
|
+
"+",
|
|
120
|
+
hidden.length,
|
|
121
|
+
"\uAC1C \uB354\uBCF4\uAE30"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
) : null
|
|
125
|
+
] })
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
CalendarDayCell.displayName = "CalendarDayCell";
|
|
132
|
+
var CalendarMonthGrid = React__namespace.forwardRef(
|
|
133
|
+
({ days, columns = 7, showLegend = true, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
134
|
+
"div",
|
|
135
|
+
{
|
|
136
|
+
ref,
|
|
137
|
+
className: cn("rounded-lg bg-bg-base p-3.5", className),
|
|
138
|
+
...props,
|
|
139
|
+
children: [
|
|
140
|
+
showLegend ? /* @__PURE__ */ jsxRuntime.jsx(CalendarLabelLegend, { className: "mb-3" }) : null,
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
142
|
+
"div",
|
|
143
|
+
{
|
|
144
|
+
className: "grid gap-2",
|
|
145
|
+
style: { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` },
|
|
146
|
+
children: days.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
147
|
+
CalendarDayCell,
|
|
148
|
+
{
|
|
149
|
+
day: d.day,
|
|
150
|
+
events: d.events,
|
|
151
|
+
muted: d.muted
|
|
152
|
+
},
|
|
153
|
+
d.day
|
|
154
|
+
))
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
CalendarMonthGrid.displayName = "CalendarMonthGrid";
|
|
162
|
+
|
|
163
|
+
exports.CALENDAR_LABELS = CALENDAR_LABELS;
|
|
164
|
+
exports.CalendarDayCell = CalendarDayCell;
|
|
165
|
+
exports.CalendarEventChip = CalendarEventChip;
|
|
166
|
+
exports.CalendarLabelLegend = CalendarLabelLegend;
|
|
167
|
+
exports.CalendarMonthGrid = CalendarMonthGrid;
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts","../../src/calendar/calendar-label.tsx","../../src/calendar/calendar-grid.tsx"],"names":["twMerge","clsx","React","jsx","jsxs","React2"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Class name utility (clsx + tailwind-merge)\n */\n\nimport { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../utils\";\n// ⛔ CALENDAR-ONLY 예외색(amber 휴가 / emerald 프로젝트)은 이 토큰 파일에만 존재.\n// 이 컴포넌트를 통해서만 소비 → 메인 UI로 색이 새지 않도록 @3w-witim/ui/calendar 로 격리.\nimport \"../../../design-system/tokens/calendar-label-tokens.css\";\n\nexport type CalendarLabelType = \"mine\" | \"vacation\" | \"project\" | \"holiday\";\n\n/** 라벨 타입 → --cal-* 토큰 클래스 맵 (색은 전부 var(--cal-*) 참조, 하드코딩 없음). */\nexport const CALENDAR_LABELS: Record<\n CalendarLabelType,\n { name: string; chip: string; dot: string }\n> = {\n mine: {\n name: \"내 일정\",\n chip: \"bg-[var(--cal-mine-bg)] text-[var(--cal-mine-text)]\",\n dot: \"bg-[var(--cal-mine-solid)]\",\n },\n vacation: {\n name: \"휴가\",\n chip: \"bg-[var(--cal-vacation-bg)] text-[var(--cal-vacation-text)]\",\n dot: \"bg-[var(--cal-vacation-solid)]\",\n },\n project: {\n name: \"프로젝트\",\n chip: \"bg-[var(--cal-project-bg)] text-[var(--cal-project-text)]\",\n dot: \"bg-[var(--cal-project-solid)]\",\n },\n holiday: {\n name: \"공휴일\",\n chip: \"bg-[var(--cal-holiday-bg)] text-[var(--cal-holiday-text)]\",\n dot: \"bg-[var(--cal-holiday-solid)]\",\n },\n};\n\nexport interface CalendarEventChipProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** 라벨 타입 (색은 CALENDAR-ONLY 토큰에서 자동 적용, 다크 전환 포함) */\n type: CalendarLabelType;\n}\n\n/** 캘린더 이벤트 라벨 칩. 색은 --cal-* 예외 토큰으로 캡슐화됨. */\nexport const CalendarEventChip = React.forwardRef<\n HTMLSpanElement,\n CalendarEventChipProps\n>(({ type, className, children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n \"block truncate rounded px-2 py-1 text-xs font-semibold\",\n CALENDAR_LABELS[type].chip,\n className,\n )}\n {...props}\n >\n {children ?? CALENDAR_LABELS[type].name}\n </span>\n));\nCalendarEventChip.displayName = \"CalendarEventChip\";\n\nexport interface CalendarLabelLegendProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** 라벨 타입 범례 (dot + 이름). */\nexport const CalendarLabelLegend = React.forwardRef<\n HTMLDivElement,\n CalendarLabelLegendProps\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-wrap gap-x-3 gap-y-1.5 text-xs\", className)}\n {...props}\n >\n {(Object.keys(CALENDAR_LABELS) as CalendarLabelType[]).map((k) => (\n <span key={k} className=\"flex items-center gap-1.5 text-text-default\">\n <span\n className={cn(\"h-2.5 w-2.5 rounded-full\", CALENDAR_LABELS[k].dot)}\n />\n {CALENDAR_LABELS[k].name}\n </span>\n ))}\n </div>\n));\nCalendarLabelLegend.displayName = \"CalendarLabelLegend\";\n","import * as React from \"react\";\n\nimport { cn } from \"../utils\";\nimport {\n CalendarEventChip,\n CalendarLabelLegend,\n type CalendarLabelType,\n} from \"./calendar-label\";\n\n/** 캘린더 한 칸에 들어가는 이벤트 하나 (라벨 텍스트 + 예외색 타입). */\nexport type CalendarEvent = {\n label: string;\n type: CalendarLabelType;\n};\n\n/** 캘린더 한 칸(날짜) 데이터. */\nexport type CalendarDayData = {\n /** 날짜 숫자 */\n day: number;\n /** 해당 날짜의 이벤트 라벨들 */\n events?: CalendarEvent[];\n /** 당월 외 날짜(흐리게 표시) */\n muted?: boolean;\n};\n\n/* -------------------------------------------------------------------------- */\n/* CalendarDayCell — 날짜 한 칸 (숫자 + 이벤트 칩들) */\n/* -------------------------------------------------------------------------- */\n\nexport interface CalendarDayCellProps\n extends React.HTMLAttributes<HTMLDivElement> {\n day: number;\n events?: CalendarEvent[];\n muted?: boolean;\n /** 최대 표시 이벤트 수. 초과분은 \"+N 더보기\"로 요약. 기본 3 */\n maxVisible?: number;\n /** \"더보기\" 클릭 콜백(선택). 넘겨진 인자는 숨겨진 이벤트 배열. */\n onShowMore?: (\n hidden: CalendarEvent[],\n e: React.MouseEvent<HTMLButtonElement>,\n ) => void;\n}\n\nexport const CalendarDayCell = React.forwardRef<\n HTMLDivElement,\n CalendarDayCellProps\n>(\n (\n {\n day,\n events = [],\n muted = false,\n maxVisible = 3,\n onShowMore,\n className,\n ...props\n },\n ref,\n ) => {\n // 최대 maxVisible(기본 3)개만 표시, 초과분은 \"+N 더보기\"로 요약.\n const visible = events.slice(0, maxVisible);\n const hidden = events.slice(maxVisible);\n return (\n <div\n ref={ref}\n className={cn(\n \"min-h-[70px] rounded-lg border border-border-subtle bg-surface-default p-2\",\n muted && \"opacity-50\",\n className,\n )}\n {...props}\n >\n <div className=\"mb-1.5 text-[11.5px] font-bold text-text-default\">\n {day}\n </div>\n <div className=\"flex flex-col gap-1\">\n {visible.map((e, i) => (\n <CalendarEventChip key={i} type={e.type} title={e.label}>\n {e.label}\n </CalendarEventChip>\n ))}\n {hidden.length > 0 ? (\n <button\n type=\"button\"\n onClick={(e) => onShowMore?.(hidden, e)}\n className=\"block w-full truncate rounded px-2 py-0.5 text-left text-xs font-medium text-text-subtle hover:bg-surface-hover\"\n >\n +{hidden.length}개 더보기\n </button>\n ) : null}\n </div>\n </div>\n );\n },\n);\nCalendarDayCell.displayName = \"CalendarDayCell\";\n\n/* -------------------------------------------------------------------------- */\n/* CalendarMonthGrid — 범례 + 날짜 칸 그리드 */\n/* -------------------------------------------------------------------------- */\n\nexport interface CalendarMonthGridProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** 표시할 날짜 칸들 */\n days: CalendarDayData[];\n /** 그리드 열 수 (기본 7 — 주 단위) */\n columns?: number;\n /** 상단 라벨 범례 표시 여부 */\n showLegend?: boolean;\n}\n\nexport const CalendarMonthGrid = React.forwardRef<\n HTMLDivElement,\n CalendarMonthGridProps\n>(\n (\n { days, columns = 7, showLegend = true, className, ...props },\n ref,\n ) => (\n <div\n ref={ref}\n className={cn(\"rounded-lg bg-bg-base p-3.5\", className)}\n {...props}\n >\n {showLegend ? <CalendarLabelLegend className=\"mb-3\" /> : null}\n <div\n className=\"grid gap-2\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {days.map((d) => (\n <CalendarDayCell\n key={d.day}\n day={d.day}\n events={d.events}\n muted={d.muted}\n />\n ))}\n </div>\n </div>\n ),\n);\nCalendarMonthGrid.displayName = \"CalendarMonthGrid\";\n"]}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/calendar/calendar-label.tsx
|
|
7
|
+
function cn(...inputs) {
|
|
8
|
+
return twMerge(clsx(inputs));
|
|
9
|
+
}
|
|
10
|
+
var CALENDAR_LABELS = {
|
|
11
|
+
mine: {
|
|
12
|
+
name: "\uB0B4 \uC77C\uC815",
|
|
13
|
+
chip: "bg-[var(--cal-mine-bg)] text-[var(--cal-mine-text)]",
|
|
14
|
+
dot: "bg-[var(--cal-mine-solid)]"
|
|
15
|
+
},
|
|
16
|
+
vacation: {
|
|
17
|
+
name: "\uD734\uAC00",
|
|
18
|
+
chip: "bg-[var(--cal-vacation-bg)] text-[var(--cal-vacation-text)]",
|
|
19
|
+
dot: "bg-[var(--cal-vacation-solid)]"
|
|
20
|
+
},
|
|
21
|
+
project: {
|
|
22
|
+
name: "\uD504\uB85C\uC81D\uD2B8",
|
|
23
|
+
chip: "bg-[var(--cal-project-bg)] text-[var(--cal-project-text)]",
|
|
24
|
+
dot: "bg-[var(--cal-project-solid)]"
|
|
25
|
+
},
|
|
26
|
+
holiday: {
|
|
27
|
+
name: "\uACF5\uD734\uC77C",
|
|
28
|
+
chip: "bg-[var(--cal-holiday-bg)] text-[var(--cal-holiday-text)]",
|
|
29
|
+
dot: "bg-[var(--cal-holiday-solid)]"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var CalendarEventChip = React.forwardRef(({ type, className, children, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
33
|
+
"span",
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
className: cn(
|
|
37
|
+
"block truncate rounded px-2 py-1 text-xs font-semibold",
|
|
38
|
+
CALENDAR_LABELS[type].chip,
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
...props,
|
|
42
|
+
children: children ?? CALENDAR_LABELS[type].name
|
|
43
|
+
}
|
|
44
|
+
));
|
|
45
|
+
CalendarEventChip.displayName = "CalendarEventChip";
|
|
46
|
+
var CalendarLabelLegend = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
ref,
|
|
50
|
+
className: cn("flex flex-wrap gap-x-3 gap-y-1.5 text-xs", className),
|
|
51
|
+
...props,
|
|
52
|
+
children: Object.keys(CALENDAR_LABELS).map((k) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-text-default", children: [
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"span",
|
|
55
|
+
{
|
|
56
|
+
className: cn("h-2.5 w-2.5 rounded-full", CALENDAR_LABELS[k].dot)
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
CALENDAR_LABELS[k].name
|
|
60
|
+
] }, k))
|
|
61
|
+
}
|
|
62
|
+
));
|
|
63
|
+
CalendarLabelLegend.displayName = "CalendarLabelLegend";
|
|
64
|
+
var CalendarDayCell = React.forwardRef(
|
|
65
|
+
({
|
|
66
|
+
day,
|
|
67
|
+
events = [],
|
|
68
|
+
muted = false,
|
|
69
|
+
maxVisible = 3,
|
|
70
|
+
onShowMore,
|
|
71
|
+
className,
|
|
72
|
+
...props
|
|
73
|
+
}, ref) => {
|
|
74
|
+
const visible = events.slice(0, maxVisible);
|
|
75
|
+
const hidden = events.slice(maxVisible);
|
|
76
|
+
return /* @__PURE__ */ jsxs(
|
|
77
|
+
"div",
|
|
78
|
+
{
|
|
79
|
+
ref,
|
|
80
|
+
className: cn(
|
|
81
|
+
"min-h-[70px] rounded-lg border border-border-subtle bg-surface-default p-2",
|
|
82
|
+
muted && "opacity-50",
|
|
83
|
+
className
|
|
84
|
+
),
|
|
85
|
+
...props,
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1.5 text-[11.5px] font-bold text-text-default", children: day }),
|
|
88
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
89
|
+
visible.map((e, i) => /* @__PURE__ */ jsx(CalendarEventChip, { type: e.type, title: e.label, children: e.label }, i)),
|
|
90
|
+
hidden.length > 0 ? /* @__PURE__ */ jsxs(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
onClick: (e) => onShowMore?.(hidden, e),
|
|
95
|
+
className: "block w-full truncate rounded px-2 py-0.5 text-left text-xs font-medium text-text-subtle hover:bg-surface-hover",
|
|
96
|
+
children: [
|
|
97
|
+
"+",
|
|
98
|
+
hidden.length,
|
|
99
|
+
"\uAC1C \uB354\uBCF4\uAE30"
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
) : null
|
|
103
|
+
] })
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
CalendarDayCell.displayName = "CalendarDayCell";
|
|
110
|
+
var CalendarMonthGrid = React.forwardRef(
|
|
111
|
+
({ days, columns = 7, showLegend = true, className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
112
|
+
"div",
|
|
113
|
+
{
|
|
114
|
+
ref,
|
|
115
|
+
className: cn("rounded-lg bg-bg-base p-3.5", className),
|
|
116
|
+
...props,
|
|
117
|
+
children: [
|
|
118
|
+
showLegend ? /* @__PURE__ */ jsx(CalendarLabelLegend, { className: "mb-3" }) : null,
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
className: "grid gap-2",
|
|
123
|
+
style: { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` },
|
|
124
|
+
children: days.map((d) => /* @__PURE__ */ jsx(
|
|
125
|
+
CalendarDayCell,
|
|
126
|
+
{
|
|
127
|
+
day: d.day,
|
|
128
|
+
events: d.events,
|
|
129
|
+
muted: d.muted
|
|
130
|
+
},
|
|
131
|
+
d.day
|
|
132
|
+
))
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
CalendarMonthGrid.displayName = "CalendarMonthGrid";
|
|
140
|
+
|
|
141
|
+
export { CALENDAR_LABELS, CalendarDayCell, CalendarEventChip, CalendarLabelLegend, CalendarMonthGrid };
|
|
142
|
+
//# sourceMappingURL=index.mjs.map
|
|
143
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts","../../src/calendar/calendar-label.tsx","../../src/calendar/calendar-grid.tsx"],"names":["React2","jsxs","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class name utility (clsx + tailwind-merge)\n */\n\nimport { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../utils\";\n// ⛔ CALENDAR-ONLY 예외색(amber 휴가 / emerald 프로젝트)은 이 토큰 파일에만 존재.\n// 이 컴포넌트를 통해서만 소비 → 메인 UI로 색이 새지 않도록 @3w-witim/ui/calendar 로 격리.\nimport \"../../../design-system/tokens/calendar-label-tokens.css\";\n\nexport type CalendarLabelType = \"mine\" | \"vacation\" | \"project\" | \"holiday\";\n\n/** 라벨 타입 → --cal-* 토큰 클래스 맵 (색은 전부 var(--cal-*) 참조, 하드코딩 없음). */\nexport const CALENDAR_LABELS: Record<\n CalendarLabelType,\n { name: string; chip: string; dot: string }\n> = {\n mine: {\n name: \"내 일정\",\n chip: \"bg-[var(--cal-mine-bg)] text-[var(--cal-mine-text)]\",\n dot: \"bg-[var(--cal-mine-solid)]\",\n },\n vacation: {\n name: \"휴가\",\n chip: \"bg-[var(--cal-vacation-bg)] text-[var(--cal-vacation-text)]\",\n dot: \"bg-[var(--cal-vacation-solid)]\",\n },\n project: {\n name: \"프로젝트\",\n chip: \"bg-[var(--cal-project-bg)] text-[var(--cal-project-text)]\",\n dot: \"bg-[var(--cal-project-solid)]\",\n },\n holiday: {\n name: \"공휴일\",\n chip: \"bg-[var(--cal-holiday-bg)] text-[var(--cal-holiday-text)]\",\n dot: \"bg-[var(--cal-holiday-solid)]\",\n },\n};\n\nexport interface CalendarEventChipProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** 라벨 타입 (색은 CALENDAR-ONLY 토큰에서 자동 적용, 다크 전환 포함) */\n type: CalendarLabelType;\n}\n\n/** 캘린더 이벤트 라벨 칩. 색은 --cal-* 예외 토큰으로 캡슐화됨. */\nexport const CalendarEventChip = React.forwardRef<\n HTMLSpanElement,\n CalendarEventChipProps\n>(({ type, className, children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n \"block truncate rounded px-2 py-1 text-xs font-semibold\",\n CALENDAR_LABELS[type].chip,\n className,\n )}\n {...props}\n >\n {children ?? CALENDAR_LABELS[type].name}\n </span>\n));\nCalendarEventChip.displayName = \"CalendarEventChip\";\n\nexport interface CalendarLabelLegendProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** 라벨 타입 범례 (dot + 이름). */\nexport const CalendarLabelLegend = React.forwardRef<\n HTMLDivElement,\n CalendarLabelLegendProps\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-wrap gap-x-3 gap-y-1.5 text-xs\", className)}\n {...props}\n >\n {(Object.keys(CALENDAR_LABELS) as CalendarLabelType[]).map((k) => (\n <span key={k} className=\"flex items-center gap-1.5 text-text-default\">\n <span\n className={cn(\"h-2.5 w-2.5 rounded-full\", CALENDAR_LABELS[k].dot)}\n />\n {CALENDAR_LABELS[k].name}\n </span>\n ))}\n </div>\n));\nCalendarLabelLegend.displayName = \"CalendarLabelLegend\";\n","import * as React from \"react\";\n\nimport { cn } from \"../utils\";\nimport {\n CalendarEventChip,\n CalendarLabelLegend,\n type CalendarLabelType,\n} from \"./calendar-label\";\n\n/** 캘린더 한 칸에 들어가는 이벤트 하나 (라벨 텍스트 + 예외색 타입). */\nexport type CalendarEvent = {\n label: string;\n type: CalendarLabelType;\n};\n\n/** 캘린더 한 칸(날짜) 데이터. */\nexport type CalendarDayData = {\n /** 날짜 숫자 */\n day: number;\n /** 해당 날짜의 이벤트 라벨들 */\n events?: CalendarEvent[];\n /** 당월 외 날짜(흐리게 표시) */\n muted?: boolean;\n};\n\n/* -------------------------------------------------------------------------- */\n/* CalendarDayCell — 날짜 한 칸 (숫자 + 이벤트 칩들) */\n/* -------------------------------------------------------------------------- */\n\nexport interface CalendarDayCellProps\n extends React.HTMLAttributes<HTMLDivElement> {\n day: number;\n events?: CalendarEvent[];\n muted?: boolean;\n /** 최대 표시 이벤트 수. 초과분은 \"+N 더보기\"로 요약. 기본 3 */\n maxVisible?: number;\n /** \"더보기\" 클릭 콜백(선택). 넘겨진 인자는 숨겨진 이벤트 배열. */\n onShowMore?: (\n hidden: CalendarEvent[],\n e: React.MouseEvent<HTMLButtonElement>,\n ) => void;\n}\n\nexport const CalendarDayCell = React.forwardRef<\n HTMLDivElement,\n CalendarDayCellProps\n>(\n (\n {\n day,\n events = [],\n muted = false,\n maxVisible = 3,\n onShowMore,\n className,\n ...props\n },\n ref,\n ) => {\n // 최대 maxVisible(기본 3)개만 표시, 초과분은 \"+N 더보기\"로 요약.\n const visible = events.slice(0, maxVisible);\n const hidden = events.slice(maxVisible);\n return (\n <div\n ref={ref}\n className={cn(\n \"min-h-[70px] rounded-lg border border-border-subtle bg-surface-default p-2\",\n muted && \"opacity-50\",\n className,\n )}\n {...props}\n >\n <div className=\"mb-1.5 text-[11.5px] font-bold text-text-default\">\n {day}\n </div>\n <div className=\"flex flex-col gap-1\">\n {visible.map((e, i) => (\n <CalendarEventChip key={i} type={e.type} title={e.label}>\n {e.label}\n </CalendarEventChip>\n ))}\n {hidden.length > 0 ? (\n <button\n type=\"button\"\n onClick={(e) => onShowMore?.(hidden, e)}\n className=\"block w-full truncate rounded px-2 py-0.5 text-left text-xs font-medium text-text-subtle hover:bg-surface-hover\"\n >\n +{hidden.length}개 더보기\n </button>\n ) : null}\n </div>\n </div>\n );\n },\n);\nCalendarDayCell.displayName = \"CalendarDayCell\";\n\n/* -------------------------------------------------------------------------- */\n/* CalendarMonthGrid — 범례 + 날짜 칸 그리드 */\n/* -------------------------------------------------------------------------- */\n\nexport interface CalendarMonthGridProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** 표시할 날짜 칸들 */\n days: CalendarDayData[];\n /** 그리드 열 수 (기본 7 — 주 단위) */\n columns?: number;\n /** 상단 라벨 범례 표시 여부 */\n showLegend?: boolean;\n}\n\nexport const CalendarMonthGrid = React.forwardRef<\n HTMLDivElement,\n CalendarMonthGridProps\n>(\n (\n { days, columns = 7, showLegend = true, className, ...props },\n ref,\n ) => (\n <div\n ref={ref}\n className={cn(\"rounded-lg bg-bg-base p-3.5\", className)}\n {...props}\n >\n {showLegend ? <CalendarLabelLegend className=\"mb-3\" /> : null}\n <div\n className=\"grid gap-2\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {days.map((d) => (\n <CalendarDayCell\n key={d.day}\n day={d.day}\n events={d.events}\n muted={d.muted}\n />\n ))}\n </div>\n </div>\n ),\n);\nCalendarMonthGrid.displayName = \"CalendarMonthGrid\";\n"]}
|