sellmate-design-system-react 9.0.0-beta.63 → 9.0.0-beta.64

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/dist/index.js CHANGED
@@ -13689,6 +13689,98 @@ function monthCells(year, month) {
13689
13689
  }
13690
13690
  var WEEK_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
13691
13691
 
13692
+ // src/components/SCalendarBoard/calendar-board-layout.ts
13693
+ function eventEndDate(event) {
13694
+ const end = event.endDate;
13695
+ return end != null && end > event.date ? end : event.date;
13696
+ }
13697
+ function layoutCalendarBoard({
13698
+ cells,
13699
+ events,
13700
+ rowCapacity,
13701
+ blockedDates
13702
+ }) {
13703
+ const count = cells.length;
13704
+ const weekCount = Math.ceil(count / 7);
13705
+ const segmentsByCell = Array.from({ length: count }, () => []);
13706
+ const eventsByCell = Array.from({ length: count }, () => []);
13707
+ const hiddenCountByCell = new Array(count).fill(0);
13708
+ const moreLaneByWeek = new Array(weekCount).fill(-1);
13709
+ const runs = [];
13710
+ events.forEach((event, order) => {
13711
+ const start = event.date;
13712
+ const end = eventEndDate(event);
13713
+ let from = -1;
13714
+ let to = -1;
13715
+ for (let i = 0; i < count; i++) {
13716
+ const { date } = cells[i];
13717
+ if (date < start || date > end) continue;
13718
+ if (from < 0) from = i;
13719
+ to = i;
13720
+ if (!blockedDates.has(date)) eventsByCell[i].push(event);
13721
+ }
13722
+ if (from < 0) return;
13723
+ let runStart = -1;
13724
+ const flush = (endIndex) => {
13725
+ if (runStart < 0) return;
13726
+ runs.push({ event, order, startIndex: runStart, endIndex, lane: -1 });
13727
+ runStart = -1;
13728
+ };
13729
+ for (let i = from; i <= to; i++) {
13730
+ if (blockedDates.has(cells[i].date)) {
13731
+ flush(i - 1);
13732
+ continue;
13733
+ }
13734
+ if (runStart >= 0 && i % 7 === 0) flush(i - 1);
13735
+ if (runStart < 0) runStart = i;
13736
+ }
13737
+ flush(to);
13738
+ });
13739
+ runs.sort(
13740
+ (a, b) => a.startIndex - b.startIndex || b.endIndex - b.startIndex - (a.endIndex - a.startIndex) || a.order - b.order
13741
+ );
13742
+ const weekLanes = Array.from({ length: weekCount }, () => []);
13743
+ for (const run of runs) {
13744
+ const week = Math.floor(run.startIndex / 7);
13745
+ const fromDay = run.startIndex % 7;
13746
+ const toDay = run.endIndex % 7;
13747
+ const lanes = weekLanes[week];
13748
+ let lane = 0;
13749
+ for (; ; ) {
13750
+ if (lanes[lane] == null) lanes[lane] = new Array(7).fill(false);
13751
+ let free = true;
13752
+ for (let d = fromDay; d <= toDay && free; d++) if (lanes[lane][d]) free = false;
13753
+ if (free) break;
13754
+ lane += 1;
13755
+ }
13756
+ for (let d = fromDay; d <= toDay; d++) lanes[lane][d] = true;
13757
+ run.lane = lane;
13758
+ }
13759
+ for (let week = 0; week < weekCount; week++) {
13760
+ if (weekLanes[week].length > rowCapacity) moreLaneByWeek[week] = rowCapacity - 1;
13761
+ }
13762
+ for (const run of runs) {
13763
+ const week = Math.floor(run.startIndex / 7);
13764
+ const moreLane = moreLaneByWeek[week];
13765
+ const limit = moreLane < 0 ? rowCapacity : moreLane;
13766
+ if (run.lane >= limit) {
13767
+ for (let i = run.startIndex; i <= run.endIndex; i++) hiddenCountByCell[i] += 1;
13768
+ continue;
13769
+ }
13770
+ const { event } = run;
13771
+ segmentsByCell[run.startIndex].push({
13772
+ event,
13773
+ key: `${event.id ?? `${event.date}-${run.order}`}-${run.startIndex}`,
13774
+ startIndex: run.startIndex,
13775
+ span: run.endIndex - run.startIndex + 1,
13776
+ lane: run.lane,
13777
+ startsHere: cells[run.startIndex].date === event.date,
13778
+ endsHere: cells[run.endIndex].date === eventEndDate(event)
13779
+ });
13780
+ }
13781
+ return { segmentsByCell, eventsByCell, hiddenCountByCell, moreLaneByWeek };
13782
+ }
13783
+
13692
13784
  // src/components/SCalendarBoard/calendarBoard.config.ts
13693
13785
  var CALENDAR_BOARD_EVENT_COLORS = [
13694
13786
  "default",
@@ -13733,7 +13825,10 @@ var CALENDAR_BOARD_DAY_BG = {
13733
13825
  function CalendarEventButton({
13734
13826
  event,
13735
13827
  onSelect,
13736
- className
13828
+ flatStart = false,
13829
+ flatEnd = false,
13830
+ className,
13831
+ style
13737
13832
  }) {
13738
13833
  const preset = CALENDAR_BOARD_EVENT_PRESETS[event.color ?? "default"];
13739
13834
  const dot = event.dotColor ?? preset.dot;
@@ -13753,10 +13848,13 @@ function CalendarEventButton({
13753
13848
  "h-(--cmp-calendarBoard-item-height) shrink-0 rounded-(--cmp-calendarBoard-item-radius)",
13754
13849
  "gap-(--cmp-calendarBoard-eventButton-inline-gap) px-(--cmp-calendarBoard-item-paddingX)",
13755
13850
  "bg-(--ceb-bg) text-(--cmp-calendarBoard-eventButton-text-color-default)",
13851
+ // 잘린 쪽은 평평하게 — 다음 조각과 이어 보면 한 막대가 주 경계에서 나뉜 모양이 된다.
13852
+ flatStart && "rounded-s-none",
13853
+ flatEnd && "rounded-e-none",
13756
13854
  disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
13757
13855
  className
13758
13856
  ),
13759
- style: { "--ceb-bg": preset.bg },
13857
+ style: { ...style, "--ceb-bg": preset.bg },
13760
13858
  onClick: (e) => {
13761
13859
  if (disabled) return;
13762
13860
  onSelect?.(event, e);
@@ -13766,7 +13864,7 @@ function CalendarEventButton({
13766
13864
  "span",
13767
13865
  {
13768
13866
  "aria-hidden": true,
13769
- className: "pointer-events-none absolute inset-0 rounded-(--cmp-calendarBoard-item-radius) bg-(--cmp-calendarBoard-eventButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-eventButton-hover-overlay-opacity)"
13867
+ className: "pointer-events-none absolute inset-0 rounded-[inherit] bg-(--cmp-calendarBoard-eventButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-eventButton-hover-overlay-opacity)"
13770
13868
  }
13771
13869
  ),
13772
13870
  /* @__PURE__ */ jsx(SBadge, { "aria-hidden": true, color: dot, className: "shrink-0" }),
@@ -13800,7 +13898,7 @@ function CalendarEventButton({
13800
13898
  }
13801
13899
  );
13802
13900
  }
13803
- var CalendarMoreButton = /* @__PURE__ */ forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", onClick, className }, ref) {
13901
+ var CalendarMoreButton = /* @__PURE__ */ forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", onClick, className, style }, ref) {
13804
13902
  return /* @__PURE__ */ jsxs(
13805
13903
  "button",
13806
13904
  {
@@ -13813,6 +13911,7 @@ var CalendarMoreButton = /* @__PURE__ */ forwardRef(function CalendarMoreButton2
13813
13911
  "bg-(--cmp-calendarBoard-moreButton-bg)",
13814
13912
  className
13815
13913
  ),
13914
+ style,
13816
13915
  onClick,
13817
13916
  children: [
13818
13917
  /* @__PURE__ */ jsx(
@@ -13831,6 +13930,9 @@ var CalendarMoreButton = /* @__PURE__ */ forwardRef(function CalendarMoreButton2
13831
13930
  }
13832
13931
  );
13833
13932
  });
13933
+ var HEADER_HEIGHT = "var(--cmp-calendarBoard-dayCard-header-paddingTop) + var(--cmp-calendarBoard-daySequence-size) + var(--cmp-calendarBoard-dayCard-header-paddingBottom)";
13934
+ var laneTop = (lane) => `calc(${HEADER_HEIGHT} + ${lane} * (var(--cmp-calendarBoard-item-height) + var(--cmp-calendarBoard-dayCard-grid-gap)))`;
13935
+ var spanWidth = (span) => `calc(${span} * 100% + ${span - 1}px - 2 * var(--cmp-calendarBoard-dayCard-paddingX))`;
13834
13936
  var CalendarDayCard = /* @__PURE__ */ forwardRef(function CalendarDayCard2({
13835
13937
  date,
13836
13938
  day,
@@ -13839,9 +13941,11 @@ var CalendarDayCard = /* @__PURE__ */ forwardRef(function CalendarDayCard2({
13839
13941
  isSelected,
13840
13942
  selectable,
13841
13943
  color,
13842
- events,
13944
+ segments,
13945
+ dayEventCount,
13843
13946
  body,
13844
13947
  hiddenCount,
13948
+ moreLane,
13845
13949
  isOpen,
13846
13950
  moreLabel,
13847
13951
  onDaySelect,
@@ -13849,7 +13953,7 @@ var CalendarDayCard = /* @__PURE__ */ forwardRef(function CalendarDayCard2({
13849
13953
  onOpenEvents,
13850
13954
  ...rest
13851
13955
  }, ref) {
13852
- const hasEvents = events.length + hiddenCount > 0;
13956
+ const hasEvents = dayEventCount > 0;
13853
13957
  const interactive = selectable || hasEvents;
13854
13958
  const activate = () => {
13855
13959
  if (hasEvents) onOpenEvents?.();
@@ -13884,7 +13988,7 @@ var CalendarDayCard = /* @__PURE__ */ forwardRef(function CalendarDayCard2({
13884
13988
  "span",
13885
13989
  {
13886
13990
  "aria-hidden": true,
13887
- className: "pointer-events-none absolute inset-[1px] rounded-(--cmp-calendarBoard-dayCard-focus-border-radius) border-(length:--cmp-calendarBoard-dayCard-focus-border-width) border-solid border-(--cmp-calendarBoard-dayCard-focus-border-color)"
13991
+ className: "pointer-events-none absolute inset-[1px] z-20 rounded-(--cmp-calendarBoard-dayCard-focus-border-radius) border-(length:--cmp-calendarBoard-dayCard-focus-border-width) border-solid border-(--cmp-calendarBoard-dayCard-focus-border-color)"
13888
13992
  }
13889
13993
  ),
13890
13994
  /* @__PURE__ */ jsx("div", { className: "flex shrink-0 pt-(--cmp-calendarBoard-dayCard-header-paddingTop) pb-(--cmp-calendarBoard-dayCard-header-paddingBottom)", children: /* @__PURE__ */ jsx(
@@ -13903,39 +14007,41 @@ var CalendarDayCard = /* @__PURE__ */ forwardRef(function CalendarDayCard2({
13903
14007
  children: day
13904
14008
  }
13905
14009
  ) }),
13906
- /* @__PURE__ */ jsxs(
13907
- "div",
14010
+ body != null && /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col pb-(--cmp-calendarBoard-dayCard-grid-paddingBottom)", children: body }),
14011
+ body == null && segments.map((segment) => /* @__PURE__ */ jsx(
14012
+ CalendarEventButton,
13908
14013
  {
13909
- className: cn(
13910
- "flex min-h-0 flex-col gap-(--cmp-calendarBoard-dayCard-grid-gap) pb-(--cmp-calendarBoard-dayCard-grid-paddingBottom)",
13911
- // 슬롯은 남는 세로를 다 갖는다 — 안에서 h-full 로 칸을 채울 수 있어야 한다.
13912
- body != null && "flex-1"
13913
- ),
13914
- children: [
13915
- body,
13916
- body == null && events.map((event, i) => /* @__PURE__ */ jsx(
13917
- CalendarEventButton,
13918
- {
13919
- event,
13920
- onSelect: (ev, e) => {
13921
- e.stopPropagation();
13922
- onEventClick?.(ev, e);
13923
- }
13924
- },
13925
- event.id ?? `${event.date}-${i}`
13926
- )),
13927
- hiddenCount > 0 && /* @__PURE__ */ jsx(
13928
- CalendarMoreButton,
13929
- {
13930
- count: hiddenCount,
13931
- label: moreLabel,
13932
- onClick: (e) => {
13933
- e.stopPropagation();
13934
- onOpenEvents?.();
13935
- }
13936
- }
13937
- )
13938
- ]
14014
+ event: segment.event,
14015
+ flatStart: !segment.startsHere,
14016
+ flatEnd: !segment.endsHere,
14017
+ className: "absolute z-10",
14018
+ style: {
14019
+ top: laneTop(segment.lane),
14020
+ left: "var(--cmp-calendarBoard-dayCard-paddingX)",
14021
+ width: spanWidth(segment.span)
14022
+ },
14023
+ onSelect: (ev, e) => {
14024
+ e.stopPropagation();
14025
+ onEventClick?.(ev, e);
14026
+ }
14027
+ },
14028
+ segment.key
14029
+ )),
14030
+ body == null && hiddenCount > 0 && moreLane >= 0 && /* @__PURE__ */ jsx(
14031
+ CalendarMoreButton,
14032
+ {
14033
+ count: hiddenCount,
14034
+ label: moreLabel,
14035
+ className: "absolute z-10",
14036
+ style: {
14037
+ top: laneTop(moreLane),
14038
+ left: "var(--cmp-calendarBoard-dayCard-paddingX)",
14039
+ width: spanWidth(1)
14040
+ },
14041
+ onClick: (e) => {
14042
+ e.stopPropagation();
14043
+ onOpenEvents?.();
14044
+ }
13939
14045
  }
13940
14046
  )
13941
14047
  ]
@@ -14069,16 +14175,14 @@ function SCalendarBoard({
14069
14175
  observer.observe(cell);
14070
14176
  return () => observer.disconnect();
14071
14177
  }, [rowCount]);
14072
- const eventMap = useMemo(() => {
14073
- const map = /* @__PURE__ */ new Map();
14074
- (events ?? []).forEach((event) => {
14075
- const list = map.get(event.date);
14076
- if (list) list.push(event);
14077
- else map.set(event.date, [event]);
14078
- });
14079
- return map;
14080
- }, [events]);
14081
- const openEvents = openDate ? eventMap.get(openDate) ?? [] : [];
14178
+ const layout = useMemo(() => {
14179
+ const blockedDates = new Set(
14180
+ cells.filter((cell) => dayContent?.[cell.date] != null).map((cell) => cell.date)
14181
+ );
14182
+ return layoutCalendarBoard({ cells, events: events ?? [], rowCapacity, blockedDates });
14183
+ }, [cells, events, rowCapacity, dayContent]);
14184
+ const openIndex = openDate == null ? -1 : cells.findIndex((cell) => cell.date === openDate);
14185
+ const openEvents = openIndex < 0 ? [] : layout.eventsByCell[openIndex];
14082
14186
  useLayoutEffect(() => {
14083
14187
  if (openDate == null || panelEl == null) return;
14084
14188
  const cell = gridRef.current?.querySelector(`[data-date="${openDate}"]`);
@@ -14219,11 +14323,9 @@ function SCalendarBoard({
14219
14323
  // 행은 판 높이를 균등하게 나눠 갖는다 — 일정이 많은 주만 길어지면 격자가 깨진다.
14220
14324
  gridTemplateRows: `repeat(${rowCount}, minmax(var(--cmp-calendarBoard-dayCard-minHeight), 1fr))`
14221
14325
  },
14222
- children: cells.map((cell) => {
14326
+ children: cells.map((cell, index) => {
14223
14327
  const content = dayContent?.[cell.date];
14224
- const list = content == null ? eventMap.get(cell.date) ?? [] : [];
14225
- const folded = list.length > rowCapacity;
14226
- const visible = folded ? list.slice(0, rowCapacity - 1) : list;
14328
+ const list = layout.eventsByCell[index];
14227
14329
  const card = /* @__PURE__ */ jsx(
14228
14330
  CalendarDayCard,
14229
14331
  {
@@ -14234,9 +14336,11 @@ function SCalendarBoard({
14234
14336
  isSelected: value != null && value === cell.date,
14235
14337
  selectable,
14236
14338
  color: dayColors?.[cell.date] ?? "default",
14237
- events: visible,
14339
+ segments: layout.segmentsByCell[index],
14340
+ dayEventCount: list.length,
14238
14341
  body: content,
14239
- hiddenCount: folded ? list.length - (rowCapacity - 1) : 0,
14342
+ hiddenCount: layout.hiddenCountByCell[index],
14343
+ moreLane: layout.moreLaneByWeek[Math.floor(index / 7)],
14240
14344
  isOpen: openDate === cell.date,
14241
14345
  moreLabel,
14242
14346
  onDaySelect: (date) => onValueChange?.(date, list),