@ayseaistudio/ui-components 3.9.2 → 3.9.4

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,8 +1,7 @@
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";
4
+ import { IconChevronRight, IconChevronLeft } from "@tabler/icons-react";
6
5
  import "./style.css";
7
6
  import { Label } from "../Label/Label";
8
7
  import { TertiaryButton } from "../TertiaryButton/TertiaryButton";
@@ -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
- // sync month/year to first value for visibility
64
- const first = values[0];
65
- if (first instanceof Date) {
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
- }, [values, currentMonth, currentYear, effectiveVariant]);
76
- // Notify parent component when selection changes
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 (onDaySelection) {
79
- if (selectedDays.length > 0) {
80
- const dates = selectedDays
81
- .sort((a, b) => a - b)
82
- .map(d => new Date(currentYear, currentMonth, d));
83
- onDaySelection(dates);
84
- }
85
- else {
86
- onDaySelection([]);
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
- }, [selectedDays, currentYear, currentMonth]);
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 (!isCurrentMonth) {
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
- setSelectedDays([]);
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
- setSelectedDays((prev) => {
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
- const isWeekRangeCell = effectiveVariant === "week" && weekMeta.inRange;
319
- const isDisabled = !isWeekRangeCell && ((disableOutsideDays && !day.currentMonth) || (maxDate && cellDate > maxDate));
320
- const status = effectiveVariant === "week" && (weekMeta.isStart || weekMeta.isEnd)
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" : ""}${weekMeta.inRange ? " week-range" : ""}${weekMeta.isStart ? " week-start" : ""}${weekMeta.isEnd ? " 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));
384
+ return day ? (_jsx("div", { className: `calendar-year-day-clickable${isDisabled ? " disabled" : ""}${isRangeCell ? " week-range" : ""}${isStartCell ? " week-start" : ""}${isEndCell ? " week-end" : ""}`, onMouseDown: (e) => e.preventDefault(), 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
  };
@@ -114,12 +114,44 @@
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 {
120
138
  background: transparent !important;
121
139
  border: none !important;
140
+ border: 1px solid transparent !important;
141
+ border-color: transparent !important;
142
+ outline: none !important;
143
+ box-shadow: none !important;
144
+ }
145
+
146
+ /* week-range içindeki selected olmayan günlerde hover'da bile border yok */
147
+ .calendar .calendar-year-day-clickable.week-range:not(.week-start):not(.week-end) .calendar-year-day-instance,
148
+ .calendar .calendar-year-day-clickable.week-range:not(.week-start):not(.week-end) .calendar-year-day-instance:hover,
149
+ .calendar .calendar-year-day-clickable.week-range:not(.week-start):not(.week-end) .calendar-year-day-instance:active,
150
+ .calendar .calendar-year-day-clickable.week-range:not(.week-start):not(.week-end) .calendar-year-day-instance:focus {
151
+ border: 1px solid transparent !important;
152
+ border-color: transparent !important;
122
153
  outline: none !important;
154
+ box-shadow: none !important;
123
155
  }
124
156
 
125
157
  .calendar .calendar-year-day-clickable.week-range .calendar-year-day {
@@ -132,14 +164,130 @@
132
164
  color: rgba(61, 61, 61, 1) !important;
133
165
  }
134
166
 
135
- .calendar .calendar-year-day-clickable.week-range.week-start {
136
- border-top-left-radius: 10px;
137
- border-bottom-left-radius: 10px;
167
+ /* Calendar içindeki day button'ların UA / library border-shadowlarını ez */
168
+ .calendar .calendar-year-day {
169
+ outline: none !important;
170
+ box-shadow: none !important;
171
+ border-color: transparent !important;
172
+ border: 1px solid transparent !important;
138
173
  }
139
174
 
140
- .calendar .calendar-year-day-clickable.week-range.week-end {
141
- border-top-right-radius: 10px;
142
- border-bottom-right-radius: 10px;
175
+ /* Hover/active anında bazı lib'ler border basıyor -> tamamen kapat */
176
+ .calendar .calendar-year-day:hover,
177
+ .calendar .calendar-year-day:active,
178
+ .calendar .calendar-year-day:focus,
179
+ .calendar .calendar-year-day:focus-visible {
180
+ outline: none !important;
181
+ box-shadow: none !important;
182
+ border: 1px solid transparent !important;
183
+ border-color: transparent !important;
184
+ }
185
+
186
+ /* Eğer wrapper focus-within alıyorsa onu da kapat */
187
+ .calendar .calendar-year-day-clickable:focus,
188
+ .calendar .calendar-year-day-clickable:focus-within {
189
+ outline: none !important;
190
+ box-shadow: none !important;
191
+ }
192
+
193
+ /* Wrapper içindeki tüm calendar-year-day instance'lar için border'ı kapat */
194
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance,
195
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance:hover,
196
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance:active,
197
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance:focus,
198
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance:focus-visible {
199
+ outline: none !important;
200
+ box-shadow: none !important;
201
+ border: 1px solid transparent !important;
202
+ border-color: transparent !important;
203
+ }
204
+
205
+ /* Wrapper hover'da bile border kapalı */
206
+ .calendar .calendar-year-day-clickable:hover .calendar-year-day-instance,
207
+ .calendar .calendar-year-day-clickable:hover .calendar-year-day,
208
+ .calendar .calendar-year-day-clickable:hover .calendar-year-day-instance:hover,
209
+ .calendar .calendar-year-day-clickable:hover .calendar-year-day:hover {
210
+ outline: none !important;
211
+ box-shadow: none !important;
212
+ border: 1px solid transparent !important;
213
+ border-color: transparent !important;
214
+ }
215
+
216
+ /* Tüm olası class kombinasyonları için border kapat */
217
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance.selected,
218
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance.default,
219
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance.selected:hover,
220
+ .calendar .calendar-year-day-clickable .calendar-year-day-instance.default:hover {
221
+ border: 1px solid transparent !important;
222
+ border-color: transparent !important;
223
+ outline: none !important;
224
+ box-shadow: none !important;
225
+ }
226
+
227
+ /* Normal günlerdeki siyah border'ı da kapat */
228
+ .calendar-year-day {
229
+ border: 1px solid transparent !important;
230
+ box-shadow: none !important;
231
+ }
232
+
233
+ .calendar-year-day.month-day,
234
+ .calendar-year-day.different-month-day {
235
+ border-color: transparent !important;
236
+ border: 1px solid transparent !important;
237
+ }
238
+
239
+ /* CalendarYearDay bileşeninin tüm varyantları için border kapat */
240
+ .calendar .calendar-year-day-instance,
241
+ .calendar .calendar-year-day-instance.month-day,
242
+ .calendar .calendar-year-day-instance.different-month-day,
243
+ .calendar .calendar-year-day-instance.current-month,
244
+ .calendar .calendar-year-day-instance.other-month {
245
+ border: 1px solid transparent !important;
246
+ border-color: transparent !important;
247
+ outline: none !important;
248
+ box-shadow: none !important;
249
+ }
250
+
251
+ /* Hover/active/focus state'lerinde de border kapalı */
252
+ .calendar .calendar-year-day-instance:hover,
253
+ .calendar .calendar-year-day-instance:active,
254
+ .calendar .calendar-year-day-instance:focus,
255
+ .calendar .calendar-year-day-instance:focus-visible {
256
+ border: 1px solid transparent !important;
257
+ border-color: transparent !important;
258
+ outline: none !important;
259
+ box-shadow: none !important;
260
+ }
261
+
262
+ /* CalendarYearDay içindeki tüm olası elementler için border kapat */
263
+ .calendar .calendar-year-day-clickable *,
264
+ .calendar .calendar-year-day-clickable *:hover,
265
+ .calendar .calendar-year-day-clickable *:active,
266
+ .calendar .calendar-year-day-clickable *:focus,
267
+ .calendar .calendar-year-day-clickable *:focus-visible {
268
+ outline: none !important;
269
+ box-shadow: none !important;
270
+ }
271
+
272
+ /* Özellikle week-range içindeki elementlerde border yok */
273
+ .calendar .calendar-year-day-clickable.week-range *,
274
+ .calendar .calendar-year-day-clickable.week-range *:hover,
275
+ .calendar .calendar-year-day-clickable.week-range *:active,
276
+ .calendar .calendar-year-day-clickable.week-range *:focus {
277
+ border: 1px solid transparent !important;
278
+ border-color: transparent !important;
279
+ outline: none !important;
280
+ box-shadow: none !important;
281
+ }
282
+
283
+ /* Wrapper hover'da bile border kapalı - tüm kombinasyonlar */
284
+ .calendar .calendar-year-day-clickable:hover *,
285
+ .calendar .calendar-year-day-clickable:active *,
286
+ .calendar .calendar-year-day-clickable:focus * {
287
+ border: 1px solid transparent !important;
288
+ border-color: transparent !important;
289
+ outline: none !important;
290
+ box-shadow: none !important;
143
291
  }
144
292
 
145
293
  .calendar .calendar-year-day-clickable.week-range.week-start .calendar-year-day-instance.selected,
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ayseaistudio/ui-components",
3
- "version": "3.9.2",
3
+ "version": "3.9.4",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",