@wipco/sdui 0.2.0 → 0.3.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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +27 -0
  3. package/dist/chunk-4SU2KYPU.js +59 -0
  4. package/dist/chunk-56KKWLNI.js +186 -0
  5. package/dist/chunk-7Y4J7EOK.js +115 -0
  6. package/dist/chunk-APCXOCAO.js +110 -0
  7. package/dist/chunk-AROOQ5W6.js +119 -0
  8. package/dist/chunk-DGPRX4MU.js +251 -0
  9. package/dist/chunk-IL2KS4WS.js +25 -0
  10. package/dist/chunk-KADFN76X.js +541 -0
  11. package/dist/chunk-KBHI3IUR.js +40 -0
  12. package/dist/chunk-LZJTKVMO.js +767 -0
  13. package/dist/chunk-MOIU7MUA.js +282 -0
  14. package/dist/chunk-MSAV4J4I.js +77 -0
  15. package/dist/chunk-OOHHW4K4.js +159 -0
  16. package/dist/chunk-Q6SBH63R.js +190 -0
  17. package/dist/chunk-QZQDHSMD.js +78 -0
  18. package/dist/chunk-RH7ESUE6.js +309 -0
  19. package/dist/chunk-SEBPBUZR.js +260 -0
  20. package/dist/chunk-USKRM22W.js +39 -0
  21. package/dist/chunk-WNYWTFGW.js +61 -0
  22. package/dist/chunk-WVRCIVAD.js +72 -0
  23. package/dist/chunk-YJMD6MOE.js +404 -0
  24. package/dist/chunk-ZNITJ4KK.js +433 -0
  25. package/dist/chunk-ZQR3ULVH.js +193 -0
  26. package/dist/{chunk-QJHD6HVQ.js → chunk-ZUCI34QY.js} +106 -390
  27. package/dist/index.d.ts +306 -53
  28. package/dist/index.js +276 -720
  29. package/dist/meta.d.ts +8 -0
  30. package/dist/meta.js +147 -8
  31. package/dist/rich.js +3 -2
  32. package/dist/styles.css +246 -0
  33. package/dist/widgets/AutocompleteField.d.ts +96 -0
  34. package/dist/widgets/AutocompleteField.js +3 -0
  35. package/dist/widgets/ColumnBoard.d.ts +47 -0
  36. package/dist/widgets/ColumnBoard.js +2 -0
  37. package/dist/widgets/DiffView.d.ts +30 -0
  38. package/dist/widgets/DiffView.js +2 -0
  39. package/dist/widgets/Disclosure.d.ts +20 -0
  40. package/dist/widgets/Disclosure.js +2 -0
  41. package/dist/widgets/EventCalendar.d.ts +59 -0
  42. package/dist/widgets/EventCalendar.js +2 -0
  43. package/dist/widgets/ImageLightbox.d.ts +25 -0
  44. package/dist/widgets/ImageLightbox.js +2 -0
  45. package/dist/widgets/InlineEdit.d.ts +23 -0
  46. package/dist/widgets/InlineEdit.js +2 -0
  47. package/dist/widgets/JsonField.d.ts +24 -0
  48. package/dist/widgets/JsonField.js +2 -0
  49. package/dist/widgets/LiveClock.d.ts +21 -0
  50. package/dist/widgets/LiveClock.js +1 -0
  51. package/dist/widgets/OrgChart.d.ts +32 -0
  52. package/dist/widgets/OrgChart.js +2 -0
  53. package/dist/widgets/PeriodFilter.d.ts +48 -0
  54. package/dist/widgets/PeriodFilter.js +2 -0
  55. package/dist/widgets/PrintSheet.d.ts +23 -0
  56. package/dist/widgets/PrintSheet.js +2 -0
  57. package/dist/widgets/SearchableMultiPicker.d.ts +29 -0
  58. package/dist/widgets/SearchableMultiPicker.js +3 -0
  59. package/dist/widgets/SecureScreen.d.ts +25 -0
  60. package/dist/widgets/SecureScreen.js +2 -0
  61. package/dist/widgets/StackedMeter.d.ts +26 -0
  62. package/dist/widgets/StackedMeter.js +1 -0
  63. package/dist/widgets/Strip.d.ts +20 -0
  64. package/dist/widgets/Strip.js +1 -0
  65. package/dist/widgets/SummaryTable.d.ts +31 -0
  66. package/dist/widgets/SummaryTable.js +1 -0
  67. package/dist/widgets/TagMultiSelect.d.ts +25 -0
  68. package/dist/widgets/TagMultiSelect.js +2 -0
  69. package/dist/widgets/Timeline.d.ts +30 -0
  70. package/dist/widgets/Timeline.js +3 -0
  71. package/dist/widgets/TreePicker.d.ts +21 -0
  72. package/dist/widgets/TreePicker.js +3 -0
  73. package/dist/widgets/TreeView.d.ts +26 -0
  74. package/dist/widgets/TreeView.js +2 -0
  75. package/dist/widgets/index.d.ts +76 -0
  76. package/dist/widgets/index.js +69 -0
  77. package/package.json +93 -3
@@ -0,0 +1,767 @@
1
+ import { SegmentedControl, IconButton, Button, Tag, EmptyState, Icon, Badge } from './chunk-ZUCI34QY.js';
2
+ import { useState, useMemo } from 'react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ var DAY_MS = 864e5;
6
+ var WEEKDAYS = ["\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0", "\uC77C"];
7
+ var todayTs = () => {
8
+ const d = /* @__PURE__ */ new Date();
9
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
10
+ };
11
+ var parseISO = (value) => {
12
+ if (value) {
13
+ const m = /^(\d{4})-(\d{1,2})-(\d{1,2})/.exec(value.trim());
14
+ if (m) {
15
+ const ts = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])).getTime();
16
+ if (!Number.isNaN(ts)) return ts;
17
+ }
18
+ }
19
+ return todayTs();
20
+ };
21
+ var fmtISO = (ts) => {
22
+ const d = new Date(ts);
23
+ const pad = (n) => String(n).padStart(2, "0");
24
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
25
+ };
26
+ var addDays = (ts, amount) => {
27
+ const d = new Date(ts);
28
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate() + amount).getTime();
29
+ };
30
+ var addMonths = (ts, amount) => {
31
+ const d = new Date(ts);
32
+ return new Date(d.getFullYear(), d.getMonth() + amount, 1).getTime();
33
+ };
34
+ var mondayStart = (ts) => addDays(ts, -((new Date(ts).getDay() + 6) % 7));
35
+ var weekdayName = (ts) => WEEKDAYS[(new Date(ts).getDay() + 6) % 7];
36
+ var fmtMonthDay = (ts) => {
37
+ const d = new Date(ts);
38
+ return `${d.getMonth() + 1}\uC6D4 ${d.getDate()}\uC77C`;
39
+ };
40
+ var fmtRange = (startTs, endTs) => endTs > startTs ? `${fmtMonthDay(startTs)} \u2013 ${fmtMonthDay(endTs)}` : fmtMonthDay(startTs);
41
+ var buildColorMap = (events, types) => {
42
+ const map = /* @__PURE__ */ new Map();
43
+ let cursor = 0;
44
+ const assign = (key, explicit) => {
45
+ if (map.has(key)) return;
46
+ map.set(key, explicit ?? `var(--wp-series-${cursor % 8 + 1})`);
47
+ cursor += 1;
48
+ };
49
+ for (const t of types ?? []) assign(t.value, t.color);
50
+ for (const e of events) assign(e.type ?? "", void 0);
51
+ return map;
52
+ };
53
+ var normalizeEvents = (events, types) => {
54
+ const colorMap = buildColorMap(events, types);
55
+ const labelMap = new Map((types ?? []).map((t) => [t.value, t.label]));
56
+ return events.map((e) => {
57
+ const dayStart = parseISO(e.start);
58
+ const type = e.type ?? "";
59
+ return {
60
+ source: e,
61
+ id: e.id,
62
+ title: e.title,
63
+ dayStart,
64
+ dayEnd: Math.max(dayStart, e.end ? parseISO(e.end) : dayStart),
65
+ type,
66
+ typeLabel: labelMap.get(type) ?? type,
67
+ status: e.status,
68
+ color: e.color ?? colorMap.get(type) ?? "var(--wp-series-1)"
69
+ };
70
+ });
71
+ };
72
+ var packWeek = (events, weekStart) => {
73
+ const weekEnd = addDays(weekStart, 6);
74
+ const segments = [];
75
+ for (const event of events) {
76
+ if (event.dayStart > weekEnd || event.dayEnd < weekStart) continue;
77
+ const start = Math.max(event.dayStart, weekStart);
78
+ const end = Math.min(event.dayEnd, weekEnd);
79
+ segments.push({
80
+ event,
81
+ col: Math.round((start - weekStart) / DAY_MS),
82
+ span: Math.round((end - start) / DAY_MS) + 1,
83
+ clipL: event.dayStart < weekStart,
84
+ clipR: event.dayEnd > weekEnd,
85
+ lane: 0
86
+ });
87
+ }
88
+ segments.sort(
89
+ (a, b) => a.col - b.col || b.span - a.span || a.event.id.localeCompare(b.event.id)
90
+ );
91
+ const laneEnd = [];
92
+ let lanes = 0;
93
+ for (const seg of segments) {
94
+ let lane = 0;
95
+ while (laneEnd[lane] !== void 0 && laneEnd[lane] >= seg.col) lane += 1;
96
+ laneEnd[lane] = seg.col + seg.span - 1;
97
+ seg.lane = lane;
98
+ lanes = Math.max(lanes, lane + 1);
99
+ }
100
+ return { segments, lanes };
101
+ };
102
+ var statusTone = (status) => {
103
+ if (/완료|반납|승인됨/.test(status)) return "success";
104
+ if (/진행|수리중|대기/.test(status)) return "warning";
105
+ if (/연체|반려|취소|분실/.test(status)) return "danger";
106
+ if (/예정|대여중|승인/.test(status)) return "info";
107
+ return "neutral";
108
+ };
109
+ var MONTH_LANE_H = 22;
110
+ var MONTH_BAR_TOP = 32;
111
+ var MONTH_MAX_LANES = 3;
112
+ var WEEK_LANE_H = 30;
113
+ var EventBar = ({ segment, selected, tall = false, onSelect }) => {
114
+ const { event, col, span, clipL, clipR, lane } = segment;
115
+ const singleDay = event.dayStart === event.dayEnd;
116
+ const radius = "var(--wp-radius-sm)";
117
+ const barHeight = tall ? WEEK_LANE_H - 6 : MONTH_LANE_H - 4;
118
+ const style = {
119
+ border: "none",
120
+ gridColumn: `${col + 1} / span ${span}`,
121
+ gridRow: `${lane + 1}`,
122
+ pointerEvents: "auto",
123
+ display: "flex",
124
+ alignItems: "center",
125
+ gap: "var(--wp-space-half)",
126
+ height: barHeight,
127
+ alignSelf: "center",
128
+ marginLeft: clipL ? 0 : "var(--wp-space-half)",
129
+ marginRight: clipR ? 0 : "var(--wp-space-half)",
130
+ padding: singleDay ? "0 var(--wp-space-2)" : "0 var(--wp-space-2) 0 var(--wp-space-1)",
131
+ borderRadius: singleDay ? "var(--wp-radius-pill)" : `${clipL ? "0" : radius} ${clipR ? "0" : radius} ${clipR ? "0" : radius} ${clipL ? "0" : radius}`,
132
+ // 여러 날 막대: 색 틴트 배경 + 왼쪽 실선 모서리. 선택되면 원색으로 채움.
133
+ background: selected ? event.color : `color-mix(in srgb, ${event.color} 18%, var(--wp-surface-card))`,
134
+ borderLeft: singleDay ? void 0 : `3px solid ${clipL ? "transparent" : event.color}`,
135
+ color: selected ? "var(--wp-text-inverse)" : "var(--wp-text-strong)",
136
+ fontSize: tall ? 13 : 12,
137
+ fontWeight: 600,
138
+ lineHeight: 1,
139
+ overflow: "hidden",
140
+ whiteSpace: "nowrap",
141
+ cursor: "pointer",
142
+ textAlign: "left",
143
+ minWidth: 0,
144
+ transition: "background var(--wp-duration-fast)"
145
+ };
146
+ return /* @__PURE__ */ jsxs(
147
+ "button",
148
+ {
149
+ type: "button",
150
+ title: event.title,
151
+ "aria-pressed": selected,
152
+ style,
153
+ onClick: (e) => onSelect(event, e),
154
+ children: [
155
+ singleDay && /* @__PURE__ */ jsx(
156
+ "span",
157
+ {
158
+ "aria-hidden": true,
159
+ style: {
160
+ width: 7,
161
+ height: 7,
162
+ flex: "none",
163
+ borderRadius: "var(--wp-radius-pill)",
164
+ background: selected ? "var(--wp-text-inverse)" : event.color
165
+ }
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: event.title })
169
+ ]
170
+ }
171
+ );
172
+ };
173
+ var VIEW_ITEMS = [
174
+ { value: "month", label: "\uC6D4" },
175
+ { value: "week", label: "\uC8FC" },
176
+ { value: "day", label: "\uC77C" },
177
+ { value: "agenda", label: "\uC77C\uC815" }
178
+ ];
179
+ var VIEW_VALUES = ["month", "week", "day", "agenda"];
180
+ function normalizeViews(views) {
181
+ if (!Array.isArray(views)) return VIEW_ITEMS;
182
+ const seen = /* @__PURE__ */ new Set();
183
+ const items = [];
184
+ for (const raw of views) {
185
+ const value = typeof raw === "string" ? raw : raw?.value;
186
+ if (!VIEW_VALUES.includes(value) || seen.has(value)) continue;
187
+ seen.add(value);
188
+ const preset = VIEW_ITEMS.find((item) => item.value === value);
189
+ const given = typeof raw === "string" ? void 0 : raw;
190
+ items.push({ value, label: given?.label ?? preset?.label, icon: given?.icon });
191
+ }
192
+ return items.length > 0 ? items : VIEW_ITEMS;
193
+ }
194
+ var cellBorder = "1px solid var(--wp-border-subtle)";
195
+ var EventCalendar = ({
196
+ events,
197
+ view,
198
+ onViewChange,
199
+ views,
200
+ date,
201
+ onDateChange,
202
+ types,
203
+ onEventClick,
204
+ selectedId
205
+ }) => {
206
+ const [internalView, setInternalView] = useState(view ?? "month");
207
+ const [internalDate, setInternalDate] = useState(() => date ?? fmtISO(todayTs()));
208
+ const [internalSelected, setInternalSelected] = useState(null);
209
+ const [hiddenTypes, setHiddenTypes] = useState(/* @__PURE__ */ new Set());
210
+ const [today] = useState(todayTs);
211
+ const viewItems = useMemo(() => normalizeViews(views), [views]);
212
+ const requestedView = view ?? internalView;
213
+ const activeView = viewItems.some((item) => item.value === requestedView) ? requestedView : viewItems[0].value;
214
+ const anchor = parseISO(date ?? internalDate);
215
+ const activeSelected = selectedId !== void 0 ? selectedId : internalSelected;
216
+ const setView = (next) => {
217
+ setInternalView(next);
218
+ onViewChange?.(next);
219
+ };
220
+ const setDate = (ts) => {
221
+ const iso = fmtISO(ts);
222
+ setInternalDate(iso);
223
+ onDateChange?.(iso);
224
+ };
225
+ const openDay = (ts) => {
226
+ setDate(ts);
227
+ setView("day");
228
+ };
229
+ const selectEvent = (event, e) => {
230
+ e.stopPropagation();
231
+ setInternalSelected(event.id);
232
+ onEventClick?.(event.source);
233
+ };
234
+ const toggleType = (value) => {
235
+ setHiddenTypes((prev) => {
236
+ const next = new Set(prev);
237
+ if (next.has(value)) next.delete(value);
238
+ else next.add(value);
239
+ return next;
240
+ });
241
+ };
242
+ const dayEvents = useMemo(() => normalizeEvents(events, types), [events, types]);
243
+ const visibleEvents = useMemo(
244
+ () => dayEvents.filter((e) => !hiddenTypes.has(e.type)),
245
+ [dayEvents, hiddenTypes]
246
+ );
247
+ const move = (dir) => {
248
+ if (activeView === "week") setDate(addDays(anchor, dir * 7));
249
+ else if (activeView === "day") setDate(addDays(anchor, dir));
250
+ else setDate(addMonths(anchor, dir));
251
+ };
252
+ const headline = (() => {
253
+ const d = new Date(anchor);
254
+ if (activeView === "week") {
255
+ const ws = mondayStart(anchor);
256
+ return `${fmtMonthDay(ws)} \u2013 ${fmtMonthDay(addDays(ws, 6))}`;
257
+ }
258
+ if (activeView === "day") {
259
+ return `${d.getFullYear()}\uB144 ${d.getMonth() + 1}\uC6D4 ${d.getDate()}\uC77C (${weekdayName(anchor)})`;
260
+ }
261
+ return `${d.getFullYear()}\uB144 ${d.getMonth() + 1}\uC6D4`;
262
+ })();
263
+ const monthWeeks = useMemo(() => {
264
+ if (activeView !== "month") return [];
265
+ const d = new Date(anchor);
266
+ const month = d.getMonth();
267
+ const gridStart = mondayStart(new Date(d.getFullYear(), month, 1).getTime());
268
+ return Array.from({ length: 6 }, (_, w) => {
269
+ const weekStart = addDays(gridStart, w * 7);
270
+ const { segments, lanes } = packWeek(visibleEvents, weekStart);
271
+ const shown = segments.filter((s) => s.lane < MONTH_MAX_LANES);
272
+ const hidden = segments.filter((s) => s.lane >= MONTH_MAX_LANES);
273
+ const overflow = Array.from(
274
+ { length: 7 },
275
+ (_2, i) => hidden.filter((s) => s.col <= i && i < s.col + s.span).length
276
+ );
277
+ const days = Array.from({ length: 7 }, (_2, i) => {
278
+ const ts = addDays(weekStart, i);
279
+ const dd = new Date(ts);
280
+ return {
281
+ ts,
282
+ num: dd.getDate(),
283
+ inMonth: dd.getMonth() === month,
284
+ isToday: ts === today,
285
+ isSunday: dd.getDay() === 0
286
+ };
287
+ });
288
+ const visLanes = Math.min(lanes, MONTH_MAX_LANES);
289
+ return {
290
+ weekStart,
291
+ days,
292
+ segments: shown,
293
+ overflow,
294
+ hasOverflow: hidden.length > 0,
295
+ rowHeight: Math.max(
296
+ 96,
297
+ MONTH_BAR_TOP + visLanes * MONTH_LANE_H + (hidden.length > 0 ? 20 : 0) + 6
298
+ )
299
+ };
300
+ });
301
+ }, [activeView, anchor, visibleEvents, today]);
302
+ const week = useMemo(() => {
303
+ if (activeView !== "week") return null;
304
+ const weekStart = mondayStart(anchor);
305
+ const { segments, lanes } = packWeek(visibleEvents, weekStart);
306
+ const days = Array.from({ length: 7 }, (_, i) => {
307
+ const ts = addDays(weekStart, i);
308
+ return {
309
+ ts,
310
+ label: WEEKDAYS[i],
311
+ num: new Date(ts).getDate(),
312
+ isToday: ts === today,
313
+ isSunday: new Date(ts).getDay() === 0
314
+ };
315
+ });
316
+ return { days, segments, bodyHeight: Math.max(200, 16 + lanes * WEEK_LANE_H + 16) };
317
+ }, [activeView, anchor, visibleEvents, today]);
318
+ const dayItems = useMemo(() => {
319
+ if (activeView !== "day") return [];
320
+ return visibleEvents.filter((e) => e.dayStart <= anchor && e.dayEnd >= anchor).sort((a, b) => a.dayStart - b.dayStart || a.title.localeCompare(b.title));
321
+ }, [activeView, anchor, visibleEvents]);
322
+ const agendaGroups = useMemo(() => {
323
+ if (activeView !== "agenda") return [];
324
+ const upcoming = visibleEvents.filter((e) => e.dayEnd >= anchor).sort((a, b) => a.dayStart - b.dayStart || a.title.localeCompare(b.title));
325
+ const groups = [];
326
+ for (const event of upcoming) {
327
+ const ts = Math.max(event.dayStart, anchor);
328
+ const last = groups[groups.length - 1];
329
+ if (last && last.ts === ts) last.items.push(event);
330
+ else groups.push({ ts, items: [event] });
331
+ }
332
+ return groups;
333
+ }, [activeView, anchor, visibleEvents]);
334
+ const dayNumber = (opts) => /* @__PURE__ */ jsx(
335
+ "span",
336
+ {
337
+ style: {
338
+ display: "inline-flex",
339
+ alignItems: "center",
340
+ justifyContent: "center",
341
+ minWidth: 24,
342
+ height: 24,
343
+ padding: "0 var(--wp-space-half)",
344
+ borderRadius: "var(--wp-radius-pill)",
345
+ fontSize: 13,
346
+ fontWeight: opts.isToday ? 700 : 500,
347
+ color: opts.isToday ? "var(--wp-text-brand)" : opts.inMonth === false ? "var(--wp-text-disabled)" : opts.isSunday ? "var(--wp-text-danger)" : "var(--wp-text-default)",
348
+ background: opts.isToday ? "var(--wp-surface-brand-tint)" : void 0,
349
+ boxShadow: opts.isToday ? "0 0 0 1.5px var(--wp-border-focus)" : void 0
350
+ },
351
+ children: opts.num
352
+ }
353
+ );
354
+ const laneGridStyle = (top, laneHeight) => ({
355
+ position: "absolute",
356
+ left: 0,
357
+ right: 0,
358
+ top,
359
+ display: "grid",
360
+ gridTemplateColumns: "repeat(7, 1fr)",
361
+ gridAutoRows: laneHeight,
362
+ pointerEvents: "none"
363
+ });
364
+ const eventRow = (event) => {
365
+ const selected = event.id === activeSelected;
366
+ return /* @__PURE__ */ jsxs(
367
+ "button",
368
+ {
369
+ type: "button",
370
+ "aria-pressed": selected,
371
+ onClick: (e) => selectEvent(event, e),
372
+ style: {
373
+ display: "flex",
374
+ alignItems: "center",
375
+ gap: "var(--wp-space-3)",
376
+ width: "100%",
377
+ padding: "var(--wp-space-3) var(--wp-space-4)",
378
+ border: cellBorder,
379
+ borderColor: selected ? "var(--wp-border-focus)" : "var(--wp-border-subtle)",
380
+ borderRadius: "var(--wp-radius-md)",
381
+ background: selected ? "var(--wp-surface-selected)" : "var(--wp-surface-card)",
382
+ cursor: "pointer",
383
+ textAlign: "left",
384
+ minWidth: 0,
385
+ transition: "background var(--wp-duration-fast), border-color var(--wp-duration-fast)"
386
+ },
387
+ children: [
388
+ /* @__PURE__ */ jsx(
389
+ "span",
390
+ {
391
+ "aria-hidden": true,
392
+ style: {
393
+ width: 4,
394
+ height: 26,
395
+ flex: "none",
396
+ borderRadius: "var(--wp-radius-pill)",
397
+ background: event.color
398
+ }
399
+ }
400
+ ),
401
+ /* @__PURE__ */ jsx(
402
+ "span",
403
+ {
404
+ style: {
405
+ flex: "1 1 auto",
406
+ minWidth: 0,
407
+ overflow: "hidden",
408
+ textOverflow: "ellipsis",
409
+ whiteSpace: "nowrap",
410
+ fontSize: 14,
411
+ fontWeight: 600,
412
+ color: "var(--wp-text-strong)"
413
+ },
414
+ children: event.title
415
+ }
416
+ ),
417
+ event.typeLabel && /* @__PURE__ */ jsx(Tag, { color: event.color, className: "wp-caption", children: event.typeLabel }),
418
+ event.status && /* @__PURE__ */ jsx(Badge, { tone: statusTone(event.status), children: event.status }),
419
+ /* @__PURE__ */ jsx("span", { style: { flex: "none", fontSize: 13, color: "var(--wp-text-muted)" }, children: fmtRange(event.dayStart, event.dayEnd) })
420
+ ]
421
+ },
422
+ event.id + fmtISO(event.dayStart)
423
+ );
424
+ };
425
+ return /* @__PURE__ */ jsxs(
426
+ "div",
427
+ {
428
+ style: {
429
+ display: "flex",
430
+ flexDirection: "column",
431
+ gap: "var(--wp-space-3)",
432
+ minWidth: 0
433
+ },
434
+ children: [
435
+ /* @__PURE__ */ jsxs(
436
+ "div",
437
+ {
438
+ style: {
439
+ display: "flex",
440
+ flexWrap: "wrap",
441
+ alignItems: "center",
442
+ gap: "var(--wp-space-2)"
443
+ },
444
+ children: [
445
+ /* @__PURE__ */ jsx(
446
+ SegmentedControl,
447
+ {
448
+ items: [...viewItems],
449
+ value: activeView,
450
+ onChange: (v) => setView(v)
451
+ }
452
+ ),
453
+ /* @__PURE__ */ jsx(
454
+ "span",
455
+ {
456
+ "aria-hidden": true,
457
+ style: { width: 1, height: 20, background: "var(--wp-border-subtle)" }
458
+ }
459
+ ),
460
+ /* @__PURE__ */ jsx(IconButton, { icon: "chevron-left", label: "\uC774\uC804", onClick: () => move(-1) }),
461
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: () => setDate(today), children: "\uC624\uB298" }),
462
+ /* @__PURE__ */ jsx(IconButton, { icon: "chevron-right", label: "\uB2E4\uC74C", onClick: () => move(1) }),
463
+ /* @__PURE__ */ jsx("h3", { className: "wp-h4", style: { margin: "0 0 0 var(--wp-space-2)" }, children: headline }),
464
+ types && types.length > 0 && /* @__PURE__ */ jsx(
465
+ "span",
466
+ {
467
+ style: {
468
+ display: "flex",
469
+ flexWrap: "wrap",
470
+ alignItems: "center",
471
+ gap: "var(--wp-space-1)",
472
+ marginLeft: "auto"
473
+ },
474
+ children: types.map((t) => {
475
+ const off = hiddenTypes.has(t.value);
476
+ const color = dayEvents.find((e) => e.type === t.value)?.color ?? t.color;
477
+ return /* @__PURE__ */ jsx(
478
+ "button",
479
+ {
480
+ type: "button",
481
+ "aria-pressed": !off,
482
+ title: off ? `${t.label} \uC77C\uC815 \uD45C\uC2DC` : `${t.label} \uC77C\uC815 \uC228\uAE30\uAE30`,
483
+ onClick: () => toggleType(t.value),
484
+ style: {
485
+ border: "none",
486
+ background: "none",
487
+ padding: 0,
488
+ cursor: "pointer",
489
+ opacity: off ? 0.4 : 1,
490
+ transition: "opacity var(--wp-duration-fast)"
491
+ },
492
+ children: /* @__PURE__ */ jsx(Tag, { color, filled: !off, children: t.label })
493
+ },
494
+ t.value
495
+ );
496
+ })
497
+ }
498
+ )
499
+ ]
500
+ }
501
+ ),
502
+ /* @__PURE__ */ jsxs(
503
+ "div",
504
+ {
505
+ style: {
506
+ border: cellBorder,
507
+ borderRadius: "var(--wp-radius-card)",
508
+ background: "var(--wp-surface-card)",
509
+ overflow: "hidden"
510
+ },
511
+ children: [
512
+ activeView === "month" && /* @__PURE__ */ jsxs(Fragment, { children: [
513
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(7, 1fr)" }, children: WEEKDAYS.map((w, i) => /* @__PURE__ */ jsx(
514
+ "div",
515
+ {
516
+ className: "wp-caption",
517
+ style: {
518
+ padding: "var(--wp-space-2) 0",
519
+ textAlign: "center",
520
+ fontWeight: 600,
521
+ color: i === 6 ? "var(--wp-text-danger)" : "var(--wp-text-muted)"
522
+ },
523
+ children: w
524
+ },
525
+ w
526
+ )) }),
527
+ monthWeeks.map((row) => /* @__PURE__ */ jsxs(
528
+ "div",
529
+ {
530
+ style: { position: "relative", borderTop: cellBorder, minHeight: row.rowHeight },
531
+ children: [
532
+ /* @__PURE__ */ jsx(
533
+ "div",
534
+ {
535
+ style: {
536
+ position: "absolute",
537
+ inset: 0,
538
+ display: "grid",
539
+ gridTemplateColumns: "repeat(7, 1fr)"
540
+ },
541
+ children: row.days.map((day, i) => /* @__PURE__ */ jsx(
542
+ "div",
543
+ {
544
+ role: "button",
545
+ tabIndex: 0,
546
+ "aria-label": `${fmtISO(day.ts)} \uC77C\uC815 \uBCF4\uAE30`,
547
+ onClick: () => openDay(day.ts),
548
+ onKeyDown: (e) => {
549
+ if (e.key === "Enter" || e.key === " ") {
550
+ e.preventDefault();
551
+ openDay(day.ts);
552
+ }
553
+ },
554
+ style: {
555
+ display: "flex",
556
+ alignItems: "flex-start",
557
+ justifyContent: "flex-end",
558
+ padding: "var(--wp-space-1)",
559
+ borderRight: i < 6 ? cellBorder : void 0,
560
+ background: day.inMonth ? void 0 : "var(--wp-surface-sunken)",
561
+ cursor: "pointer"
562
+ },
563
+ children: dayNumber(day)
564
+ },
565
+ day.ts
566
+ ))
567
+ }
568
+ ),
569
+ /* @__PURE__ */ jsxs("div", { style: laneGridStyle(MONTH_BAR_TOP, MONTH_LANE_H), children: [
570
+ row.segments.map((seg) => /* @__PURE__ */ jsx(
571
+ EventBar,
572
+ {
573
+ segment: seg,
574
+ selected: seg.event.id === activeSelected,
575
+ onSelect: selectEvent
576
+ },
577
+ `${seg.event.id}-${row.weekStart}`
578
+ )),
579
+ row.hasOverflow && row.overflow.map(
580
+ (count, i) => count > 0 ? /* @__PURE__ */ jsxs(
581
+ "button",
582
+ {
583
+ type: "button",
584
+ title: `\uC228\uACA8\uC9C4 \uC77C\uC815 ${count}\uAC74 \u2014 \uC77C \uBCF4\uAE30\uB85C \uC774\uB3D9`,
585
+ onClick: (e) => {
586
+ e.stopPropagation();
587
+ openDay(row.days[i].ts);
588
+ },
589
+ style: {
590
+ gridColumn: `${i + 1} / span 1`,
591
+ gridRow: `${MONTH_MAX_LANES + 1}`,
592
+ pointerEvents: "auto",
593
+ justifySelf: "start",
594
+ alignSelf: "center",
595
+ margin: "0 var(--wp-space-1)",
596
+ padding: "0 var(--wp-space-1)",
597
+ height: 16,
598
+ border: "none",
599
+ borderRadius: "var(--wp-radius-xs)",
600
+ background: "none",
601
+ fontSize: 11,
602
+ fontWeight: 700,
603
+ color: "var(--wp-text-muted)",
604
+ cursor: "pointer"
605
+ },
606
+ children: [
607
+ "+",
608
+ count
609
+ ]
610
+ },
611
+ `ov-${row.days[i].ts}`
612
+ ) : null
613
+ )
614
+ ] })
615
+ ]
616
+ },
617
+ row.weekStart
618
+ ))
619
+ ] }),
620
+ activeView === "week" && week && /* @__PURE__ */ jsxs(Fragment, { children: [
621
+ /* @__PURE__ */ jsx(
622
+ "div",
623
+ {
624
+ style: {
625
+ display: "grid",
626
+ gridTemplateColumns: "repeat(7, 1fr)",
627
+ borderBottom: cellBorder
628
+ },
629
+ children: week.days.map((day) => /* @__PURE__ */ jsxs(
630
+ "button",
631
+ {
632
+ type: "button",
633
+ onClick: () => openDay(day.ts),
634
+ style: {
635
+ border: "none",
636
+ background: "none",
637
+ padding: "var(--wp-space-2) 0",
638
+ textAlign: "center",
639
+ cursor: "pointer"
640
+ },
641
+ children: [
642
+ /* @__PURE__ */ jsx(
643
+ "span",
644
+ {
645
+ className: "wp-caption",
646
+ style: {
647
+ display: "block",
648
+ fontWeight: 600,
649
+ color: day.isSunday ? "var(--wp-text-danger)" : "var(--wp-text-muted)"
650
+ },
651
+ children: day.label
652
+ }
653
+ ),
654
+ /* @__PURE__ */ jsx("span", { style: { marginTop: "var(--wp-space-half)", display: "inline-flex" }, children: dayNumber(day) })
655
+ ]
656
+ },
657
+ day.ts
658
+ ))
659
+ }
660
+ ),
661
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", minHeight: week.bodyHeight }, children: [
662
+ /* @__PURE__ */ jsx(
663
+ "div",
664
+ {
665
+ style: {
666
+ position: "absolute",
667
+ inset: 0,
668
+ display: "grid",
669
+ gridTemplateColumns: "repeat(7, 1fr)"
670
+ },
671
+ children: week.days.map((day, i) => /* @__PURE__ */ jsx(
672
+ "div",
673
+ {
674
+ style: {
675
+ borderRight: i < 6 ? cellBorder : void 0,
676
+ background: day.isToday ? "var(--wp-surface-brand-tint)" : void 0
677
+ }
678
+ },
679
+ day.ts
680
+ ))
681
+ }
682
+ ),
683
+ /* @__PURE__ */ jsx("div", { style: laneGridStyle(12, WEEK_LANE_H), children: week.segments.map((seg) => /* @__PURE__ */ jsx(
684
+ EventBar,
685
+ {
686
+ segment: seg,
687
+ selected: seg.event.id === activeSelected,
688
+ tall: true,
689
+ onSelect: selectEvent
690
+ },
691
+ seg.event.id
692
+ )) }),
693
+ week.segments.length === 0 && /* @__PURE__ */ jsx(EmptyState, { icon: "calendar", tight: true, title: "\uC77C\uC815 \uC5C6\uC74C", children: "\uC774 \uC8FC\uC5D0\uB294 \uD45C\uC2DC\uD560 \uC77C\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
694
+ ] })
695
+ ] }),
696
+ activeView === "day" && /* @__PURE__ */ jsx(
697
+ "div",
698
+ {
699
+ style: {
700
+ display: "flex",
701
+ flexDirection: "column",
702
+ gap: "var(--wp-space-2)",
703
+ padding: "var(--wp-space-4)"
704
+ },
705
+ children: dayItems.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { icon: "calendar", tight: true, title: "\uC77C\uC815 \uC5C6\uC74C", children: "\uC774 \uB0A0\uC9DC\uC5D0\uB294 \uD45C\uC2DC\uD560 \uC77C\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : dayItems.map((event) => eventRow(event))
706
+ }
707
+ ),
708
+ activeView === "agenda" && /* @__PURE__ */ jsx(
709
+ "div",
710
+ {
711
+ style: {
712
+ display: "flex",
713
+ flexDirection: "column",
714
+ gap: "var(--wp-space-4)",
715
+ padding: "var(--wp-space-4)"
716
+ },
717
+ children: agendaGroups.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { icon: "calendar", tight: true, title: "\uB2E4\uAC00\uC624\uB294 \uC77C\uC815 \uC5C6\uC74C", children: "\uAE30\uC900\uC77C \uC774\uD6C4\uC5D0 \uD45C\uC2DC\uD560 \uC77C\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : agendaGroups.map((group) => /* @__PURE__ */ jsxs("div", { children: [
718
+ /* @__PURE__ */ jsxs(
719
+ "div",
720
+ {
721
+ style: {
722
+ display: "flex",
723
+ alignItems: "center",
724
+ gap: "var(--wp-space-2)",
725
+ marginBottom: "var(--wp-space-2)"
726
+ },
727
+ children: [
728
+ /* @__PURE__ */ jsx(Icon, { name: "calendar", size: 16, style: { color: "var(--wp-text-muted)" } }),
729
+ /* @__PURE__ */ jsxs(
730
+ "span",
731
+ {
732
+ className: "wp-caption",
733
+ style: {
734
+ fontWeight: 700,
735
+ color: group.ts === today ? "var(--wp-text-brand)" : "var(--wp-text-muted)"
736
+ },
737
+ children: [
738
+ fmtMonthDay(group.ts),
739
+ " (",
740
+ weekdayName(group.ts),
741
+ ")",
742
+ group.ts === today ? " \xB7 \uC624\uB298" : ""
743
+ ]
744
+ }
745
+ )
746
+ ]
747
+ }
748
+ ),
749
+ /* @__PURE__ */ jsx(
750
+ "div",
751
+ {
752
+ style: { display: "flex", flexDirection: "column", gap: "var(--wp-space-1)" },
753
+ children: group.items.map((event) => eventRow(event))
754
+ }
755
+ )
756
+ ] }, group.ts))
757
+ }
758
+ )
759
+ ]
760
+ }
761
+ )
762
+ ]
763
+ }
764
+ );
765
+ };
766
+
767
+ export { EventCalendar };