@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 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"]}