@ayseaistudio/ui-components 3.9.2 → 3.9.3
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.
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import { IconChevronRight } from "@tabler/icons-react";
|
|
5
|
-
import { IconChevronLeft } from "@tabler/icons-react";
|
|
6
|
-
import "./style.css";
|
|
4
|
+
import { IconChevronRight, IconChevronLeft } from "@tabler/icons-react";
|
|
7
5
|
import { Label } from "../Label/Label";
|
|
8
6
|
import { TertiaryButton } from "../TertiaryButton/TertiaryButton";
|
|
9
7
|
import { CalendarYearDay } from "../CalendarYearDay/CalendarYearDay";
|
|
8
|
+
import "./style.css";
|
|
10
9
|
const normalizeVariantInput = (value) => {
|
|
11
10
|
if (!value)
|
|
12
11
|
return undefined;
|
|
@@ -33,6 +32,8 @@ export const Calendar = ({ property1, className, tertiaryButtonIcon = (_jsx(Icon
|
|
|
33
32
|
const [selectedDay, setSelectedDay] = React.useState(null);
|
|
34
33
|
const [selectedDays, setSelectedDays] = React.useState([]);
|
|
35
34
|
const [selectedWeekRange, setSelectedWeekRange] = React.useState(null);
|
|
35
|
+
const [rangeStart, setRangeStart] = React.useState(null);
|
|
36
|
+
const [rangeEnd, setRangeEnd] = React.useState(null);
|
|
36
37
|
const today = new Date();
|
|
37
38
|
const [currentMonth, setCurrentMonth] = React.useState(month ?? today.getMonth());
|
|
38
39
|
const [currentYear, setCurrentYear] = React.useState(year ?? today.getFullYear());
|
|
@@ -55,38 +56,61 @@ export const Calendar = ({ property1, className, tertiaryButtonIcon = (_jsx(Icon
|
|
|
55
56
|
setSelectedDay(value.getDate());
|
|
56
57
|
}
|
|
57
58
|
}, [value, effectiveVariant]);
|
|
58
|
-
// Controlled multiple values support (when provided)
|
|
59
|
+
// Controlled multiple values support (when provided) – treat as range in multi mode
|
|
59
60
|
React.useEffect(() => {
|
|
60
61
|
if (effectiveVariant !== "multi")
|
|
61
62
|
return;
|
|
62
63
|
if (Array.isArray(values) && values.length > 0) {
|
|
63
|
-
|
|
64
|
-
const first =
|
|
65
|
-
|
|
64
|
+
const sorted = [...values].sort((a, b) => a.getTime() - b.getTime());
|
|
65
|
+
const first = sorted[0];
|
|
66
|
+
const last = sorted[sorted.length - 1];
|
|
67
|
+
if (first instanceof Date && last instanceof Date) {
|
|
68
|
+
setRangeStart(first);
|
|
69
|
+
setRangeEnd(last);
|
|
66
70
|
setCurrentMonth(first.getMonth());
|
|
67
71
|
setCurrentYear(first.getFullYear());
|
|
68
72
|
}
|
|
69
|
-
// take only current month days for highlighting
|
|
70
|
-
const currentMonthDays = values
|
|
71
|
-
.filter(d => d.getFullYear() === currentYear && d.getMonth() === currentMonth)
|
|
72
|
-
.map(d => d.getDate());
|
|
73
|
-
setSelectedDays(currentMonthDays);
|
|
74
73
|
}
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
else {
|
|
75
|
+
setRangeStart(null);
|
|
76
|
+
setRangeEnd(null);
|
|
77
|
+
}
|
|
78
|
+
}, [values, effectiveVariant]);
|
|
79
|
+
// Compute selectedDays for the current month from the active range in multi mode
|
|
77
80
|
React.useEffect(() => {
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
if (effectiveVariant !== "multi")
|
|
82
|
+
return;
|
|
83
|
+
if (!rangeStart) {
|
|
84
|
+
setSelectedDays([]);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const end = rangeEnd && rangeEnd.getTime() >= rangeStart.getTime() ? rangeEnd : rangeStart;
|
|
88
|
+
const days = [];
|
|
89
|
+
const cursor = new Date(rangeStart);
|
|
90
|
+
while (cursor.getTime() <= end.getTime()) {
|
|
91
|
+
if (cursor.getFullYear() === currentYear && cursor.getMonth() === currentMonth) {
|
|
92
|
+
days.push(cursor.getDate());
|
|
87
93
|
}
|
|
94
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
88
95
|
}
|
|
89
|
-
|
|
96
|
+
setSelectedDays(days);
|
|
97
|
+
}, [rangeStart, rangeEnd, currentMonth, currentYear, effectiveVariant]);
|
|
98
|
+
// Notify parent component when selection changes (except multi, which calls manually)
|
|
99
|
+
React.useEffect(() => {
|
|
100
|
+
if (!onDaySelection)
|
|
101
|
+
return;
|
|
102
|
+
if (effectiveVariant === "multi")
|
|
103
|
+
return;
|
|
104
|
+
if (selectedDays.length > 0) {
|
|
105
|
+
const dates = selectedDays
|
|
106
|
+
.sort((a, b) => a - b)
|
|
107
|
+
.map(d => new Date(currentYear, currentMonth, d));
|
|
108
|
+
onDaySelection(dates);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
onDaySelection([]);
|
|
112
|
+
}
|
|
113
|
+
}, [selectedDays, currentYear, currentMonth, effectiveVariant, onDaySelection]);
|
|
90
114
|
// Reset selection when variant changes
|
|
91
115
|
React.useEffect(() => {
|
|
92
116
|
if (effectiveVariant === "single") {
|
|
@@ -169,22 +193,40 @@ export const Calendar = ({ property1, className, tertiaryButtonIcon = (_jsx(Icon
|
|
|
169
193
|
onDaySelection?.(resolvedWeek);
|
|
170
194
|
return;
|
|
171
195
|
}
|
|
172
|
-
// multi
|
|
173
|
-
if (
|
|
196
|
+
// multi: treat as date range (start + end)
|
|
197
|
+
if (effectiveVariant === "multi") {
|
|
198
|
+
// Always move view to clicked date
|
|
174
199
|
setCurrentMonth(cellDate.getMonth());
|
|
175
200
|
setCurrentYear(cellDate.getFullYear());
|
|
176
|
-
|
|
201
|
+
// Case 1: no start yet OR both start & end already selected -> start new range
|
|
202
|
+
if (!rangeStart || rangeEnd) {
|
|
203
|
+
setRangeStart(cellDate);
|
|
204
|
+
setRangeEnd(null);
|
|
205
|
+
onChangeMultiple?.([cellDate]);
|
|
206
|
+
onDaySelection?.([cellDate]);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Case 2: we have a start but no end -> complete the range
|
|
210
|
+
let start = rangeStart;
|
|
211
|
+
let end = cellDate;
|
|
212
|
+
if (end.getTime() < start.getTime()) {
|
|
213
|
+
const tmp = start;
|
|
214
|
+
start = end;
|
|
215
|
+
end = tmp;
|
|
216
|
+
}
|
|
217
|
+
setRangeStart(start);
|
|
218
|
+
setRangeEnd(end);
|
|
219
|
+
const allDates = [];
|
|
220
|
+
const cursor = new Date(start);
|
|
221
|
+
while (cursor.getTime() <= end.getTime()) {
|
|
222
|
+
allDates.push(new Date(cursor));
|
|
223
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
224
|
+
}
|
|
225
|
+
onChangeMultiple?.(allDates);
|
|
226
|
+
onDaySelection?.(allDates);
|
|
177
227
|
return;
|
|
178
228
|
}
|
|
179
|
-
|
|
180
|
-
const dayNum = cellDate.getDate();
|
|
181
|
-
const next = prev.includes(dayNum) ? prev.filter((d) => d !== dayNum) : [...prev, dayNum];
|
|
182
|
-
onChangeMultiple?.(next
|
|
183
|
-
.sort((a, b) => a - b)
|
|
184
|
-
.map((d) => new Date(cellDate.getFullYear(), cellDate.getMonth(), d)));
|
|
185
|
-
return next;
|
|
186
|
-
});
|
|
187
|
-
}, [buildWeekFromDate, disableOutsideDays, effectiveVariant, onChange, onChangeMultiple, onDaySelection, maxDate]);
|
|
229
|
+
}, [buildWeekFromDate, disableOutsideDays, effectiveVariant, onChange, onChangeMultiple, onDaySelection, maxDate, rangeStart, rangeEnd]);
|
|
188
230
|
const getStatusForDay = (day, cellDate) => {
|
|
189
231
|
if (effectiveVariant === "week" && selectedWeekRange) {
|
|
190
232
|
const { isStart, isEnd } = getWeekRangeMeta(cellDate);
|
|
@@ -315,12 +357,31 @@ export const Calendar = ({ property1, className, tertiaryButtonIcon = (_jsx(Icon
|
|
|
315
357
|
const taskCount = getAppointmentCountForDate(cellDate);
|
|
316
358
|
const weekDates = buildWeekFromDate(cellDate);
|
|
317
359
|
const weekMeta = effectiveVariant === "week" ? getWeekRangeMeta(cellDate) : { inRange: false, isStart: false, isEnd: false };
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
360
|
+
// Range meta for multi-mode (date range)
|
|
361
|
+
let multiRangeMeta = { inRange: false, isStart: false, isEnd: false };
|
|
362
|
+
if (effectiveVariant === "multi" && rangeStart) {
|
|
363
|
+
let start = rangeStart;
|
|
364
|
+
let end = rangeEnd && rangeEnd.getTime() >= rangeStart.getTime() ? rangeEnd : rangeStart;
|
|
365
|
+
if (rangeEnd && rangeEnd.getTime() < rangeStart.getTime()) {
|
|
366
|
+
start = rangeEnd;
|
|
367
|
+
end = rangeStart;
|
|
368
|
+
}
|
|
369
|
+
const time = cellDate.getTime();
|
|
370
|
+
multiRangeMeta = {
|
|
371
|
+
inRange: time >= start.getTime() && time <= end.getTime(),
|
|
372
|
+
isStart: time === start.getTime(),
|
|
373
|
+
isEnd: time === end.getTime(),
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const isRangeCell = (effectiveVariant === "week" && weekMeta.inRange) || (effectiveVariant === "multi" && multiRangeMeta.inRange);
|
|
377
|
+
const isStartCell = effectiveVariant === "week" ? weekMeta.isStart : multiRangeMeta.isStart;
|
|
378
|
+
const isEndCell = effectiveVariant === "week" ? weekMeta.isEnd : multiRangeMeta.isEnd;
|
|
379
|
+
const isDisabled = !isRangeCell && ((disableOutsideDays && !day.currentMonth) || (maxDate && cellDate > maxDate));
|
|
380
|
+
const status = ((effectiveVariant === "week" && (weekMeta.isStart || weekMeta.isEnd)) ||
|
|
381
|
+
(effectiveVariant === "multi" && (multiRangeMeta.isStart || multiRangeMeta.isEnd)))
|
|
321
382
|
? "selected"
|
|
322
383
|
: getStatusForDay(day, cellDate);
|
|
323
|
-
return day ? (_jsx("div", { className: `calendar-year-day-clickable${isDisabled ? " disabled" : ""}${
|
|
384
|
+
return day ? (_jsx("div", { className: `calendar-year-day-clickable${isDisabled ? " disabled" : ""}${isRangeCell ? " week-range" : ""}${isStartCell ? " week-start" : ""}${isEndCell ? " week-end" : ""}`, onClick: () => handleSelectDate(cellDate, day.currentMonth, weekDates), children: _jsx(CalendarYearDay, { className: `calendar-year-day-instance ${day.currentMonth ? 'current-month' : 'other-month'}${isToday ? ' today' : ''}`, size: "medium", status: status, text: day.day.toString(), taskCount: taskCount, version: day.currentMonth ? "month-day" : "different-month-day" }) }, cellKey)) : (_jsx("div", { className: "calendar-year-day-empty" }, cellKey));
|
|
324
385
|
}) }, `week-${wi}`));
|
|
325
386
|
}) })] }));
|
|
326
387
|
};
|
package/dist/Calendar/style.css
CHANGED
|
@@ -114,6 +114,24 @@
|
|
|
114
114
|
.calendar .calendar-year-day-clickable.week-range {
|
|
115
115
|
background-color: rgba(113, 163, 13, 0.1);
|
|
116
116
|
border-radius: 0;
|
|
117
|
+
margin: 0 -2px;
|
|
118
|
+
padding: 0 2px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Başlangıç hücresinde sol margin/padding yok */
|
|
122
|
+
.calendar .calendar-year-day-clickable.week-range.week-start {
|
|
123
|
+
border-top-left-radius: 10px;
|
|
124
|
+
border-bottom-left-radius: 10px;
|
|
125
|
+
margin-left: 0;
|
|
126
|
+
padding-left: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Bitiş hücresinde sağ margin/padding yok */
|
|
130
|
+
.calendar .calendar-year-day-clickable.week-range.week-end {
|
|
131
|
+
border-top-right-radius: 10px;
|
|
132
|
+
border-bottom-right-radius: 10px;
|
|
133
|
+
margin-right: 0;
|
|
134
|
+
padding-right: 0;
|
|
117
135
|
}
|
|
118
136
|
|
|
119
137
|
.calendar .calendar-year-day-clickable.week-range .calendar-year-day-instance {
|
|
@@ -132,16 +150,6 @@
|
|
|
132
150
|
color: rgba(61, 61, 61, 1) !important;
|
|
133
151
|
}
|
|
134
152
|
|
|
135
|
-
.calendar .calendar-year-day-clickable.week-range.week-start {
|
|
136
|
-
border-top-left-radius: 10px;
|
|
137
|
-
border-bottom-left-radius: 10px;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.calendar .calendar-year-day-clickable.week-range.week-end {
|
|
141
|
-
border-top-right-radius: 10px;
|
|
142
|
-
border-bottom-right-radius: 10px;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
153
|
.calendar .calendar-year-day-clickable.week-range.week-start .calendar-year-day-instance.selected,
|
|
146
154
|
.calendar .calendar-year-day-clickable.week-range.week-end .calendar-year-day-instance.selected {
|
|
147
155
|
background-color: #b1e635 !important;
|
|
@@ -12,7 +12,7 @@ export const CalendarYearDay = ({ size, version, status, className, text, taskCo
|
|
|
12
12
|
return 0;
|
|
13
13
|
};
|
|
14
14
|
const badgeCount = getBadgeCount();
|
|
15
|
-
return (_jsxs("button", { type: "button", "aria-pressed": dayStatus === "selected", className: `calendar-year-day ${dayStatus} ${version} size-0-${size} ${className}`, children: [_jsx(Label, { className: "calendar-year-day-label", bold: "off", color: "black", size: "medium", spacing: "off", stroke: "off", text: text, version: "primary" }), badgeCount > 0 && (_jsx("div", { className: "badge-container", children: Array.from({ length: badgeCount }).map((_, idx) => (_jsx(Badge, { size: "XX-small", color: "grey", className: "instance-node" }, idx))) }))] }));
|
|
15
|
+
return (_jsxs("button", { type: "button", "aria-pressed": dayStatus === "selected", className: `calendar-year-day ${dayStatus} ${version} size-0-${size} ${className}`, onMouseDown: (e) => e.preventDefault(), children: [_jsx(Label, { className: "calendar-year-day-label", bold: "off", color: "black", size: "medium", spacing: "off", stroke: "off", text: text, version: "primary" }), badgeCount > 0 && (_jsx("div", { className: "badge-container", children: Array.from({ length: badgeCount }).map((_, idx) => (_jsx(Badge, { size: "XX-small", color: "grey", className: "instance-node" }, idx))) }))] }));
|
|
16
16
|
};
|
|
17
17
|
CalendarYearDay.propTypes = {
|
|
18
18
|
size: PropTypes.oneOf(["large", "medium"]),
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
position: relative;
|
|
14
14
|
width: 36px;
|
|
15
15
|
transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
|
|
16
|
+
-webkit-tap-highlight-color: transparent;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
.calendar-year-day.size-0-large {
|
|
@@ -44,6 +45,17 @@
|
|
|
44
45
|
border-color: rgba(152, 211, 23, 1);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
.calendar-year-day:focus {
|
|
49
|
+
outline: none !important;
|
|
50
|
+
box-shadow: none !important;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.calendar-year-day:active {
|
|
54
|
+
outline: none !important;
|
|
55
|
+
box-shadow: none !important;
|
|
56
|
+
border-color: transparent !important;
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
.calendar-year-day:focus-visible {
|
|
48
60
|
outline: 2px solid rgba(152, 211, 23, 0.6);
|
|
49
61
|
outline-offset: 2px;
|