ar-design 0.4.33 → 0.4.35
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/assets/css/components/data-display/calendar/styles.week-view.css +35 -19
- package/dist/components/data-display/calendar/Body.d.ts +2 -1
- package/dist/components/data-display/calendar/Body.js +2 -2
- package/dist/components/data-display/calendar/IProps.d.ts +1 -0
- package/dist/components/data-display/calendar/index.d.ts +1 -1
- package/dist/components/data-display/calendar/index.js +2 -2
- package/dist/components/data-display/calendar/views/Week.d.ts +2 -1
- package/dist/components/data-display/calendar/views/Week.js +136 -53
- package/package.json +1 -1
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
> .item {
|
|
17
17
|
display: flex;
|
|
18
18
|
flex-direction: column;
|
|
19
|
+
flex: 1;
|
|
19
20
|
align-items: center;
|
|
20
21
|
gap: 1rem;
|
|
21
22
|
width: calc(100% / 7);
|
|
22
23
|
padding: 0.5rem 0;
|
|
24
|
+
text-align: center;
|
|
23
25
|
|
|
24
26
|
> .day-name {
|
|
25
27
|
color: var(--gray-400);
|
|
@@ -33,11 +35,16 @@
|
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
> .body {
|
|
38
|
+
position: relative;
|
|
36
39
|
display: flex;
|
|
37
40
|
flex-direction: row;
|
|
38
41
|
width: 100%;
|
|
39
42
|
|
|
40
43
|
> .clocks {
|
|
44
|
+
position: relative;
|
|
45
|
+
width: 50px;
|
|
46
|
+
z-index: 1;
|
|
47
|
+
|
|
41
48
|
> div {
|
|
42
49
|
height: 60px;
|
|
43
50
|
|
|
@@ -54,25 +61,7 @@
|
|
|
54
61
|
height: calc(24 * 60px);
|
|
55
62
|
border: solid 1px transparent;
|
|
56
63
|
border-top-color: var(--gray-200);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
> .events-layer {
|
|
60
|
-
position: absolute;
|
|
61
|
-
top: 0;
|
|
62
|
-
left: 0;
|
|
63
|
-
width: 100%;
|
|
64
|
-
height: 100%;
|
|
65
|
-
pointer-events: none;
|
|
66
|
-
z-index: 1;
|
|
67
|
-
|
|
68
|
-
> .event-box {
|
|
69
|
-
position: absolute;
|
|
70
|
-
width: calc(100% / 7);
|
|
71
|
-
padding: 0.5rem;
|
|
72
|
-
color: var(--white);
|
|
73
|
-
font-size: 12px;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
64
|
+
z-index: 1;
|
|
76
65
|
|
|
77
66
|
> .row {
|
|
78
67
|
position: relative;
|
|
@@ -123,6 +112,33 @@
|
|
|
123
112
|
}
|
|
124
113
|
}
|
|
125
114
|
}
|
|
115
|
+
|
|
116
|
+
> .events-layer {
|
|
117
|
+
position: absolute;
|
|
118
|
+
right: 0;
|
|
119
|
+
width: calc(100% - 50px); /* Solda yer alan clocks'dan dolayı -50px yapıldı. */
|
|
120
|
+
height: calc(24 * 60px);
|
|
121
|
+
z-index: 2;
|
|
122
|
+
|
|
123
|
+
> .event-box {
|
|
124
|
+
position: absolute;
|
|
125
|
+
width: calc(100% / 7);
|
|
126
|
+
padding: 0.5rem;
|
|
127
|
+
color: var(--white);
|
|
128
|
+
font-size: 12px;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
126
132
|
}
|
|
127
133
|
}
|
|
128
134
|
}
|
|
135
|
+
|
|
136
|
+
.ar-calendar-tooltip {
|
|
137
|
+
position: fixed;
|
|
138
|
+
background-color: var(--black);
|
|
139
|
+
padding: 1rem;
|
|
140
|
+
border-radius: var(--border-radius-sm);
|
|
141
|
+
color: var(--white);
|
|
142
|
+
pointer-events: none;
|
|
143
|
+
z-index: 200;
|
|
144
|
+
}
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { View } from "../../../libs/types";
|
|
3
3
|
import { CalendarEvent } from "./IProps";
|
|
4
4
|
interface IProps<T> {
|
|
5
|
+
trackedBy: keyof (T & CalendarEvent);
|
|
5
6
|
data: (T & CalendarEvent)[];
|
|
6
7
|
renderItem: (item: T, index: number) => React.JSX.Element;
|
|
7
8
|
states: {
|
|
@@ -18,5 +19,5 @@ interface IProps<T> {
|
|
|
18
19
|
locale?: Intl.LocalesArgument;
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
|
-
declare const Body: <T>({ data, renderItem, states, config }: IProps<T>) => React.JSX.Element;
|
|
22
|
+
declare const Body: <T>({ trackedBy, data, renderItem, states, config }: IProps<T>) => React.JSX.Element;
|
|
22
23
|
export default Body;
|
|
@@ -2,11 +2,11 @@ import React from "react";
|
|
|
2
2
|
import Day from "./views/Day";
|
|
3
3
|
import Week from "./views/Week";
|
|
4
4
|
import Month from "./views/Month";
|
|
5
|
-
const Body = function ({ data, renderItem, states, config }) {
|
|
5
|
+
const Body = function ({ trackedBy, data, renderItem, states, config }) {
|
|
6
6
|
if (states.view.get === "Day")
|
|
7
7
|
return React.createElement(Day, null);
|
|
8
8
|
else if (states.view.get === "Week")
|
|
9
|
-
return React.createElement(Week, { data: data, renderItem: renderItem, states: { currentDate: states.currentDate }, config: config });
|
|
9
|
+
return (React.createElement(Week, { trackedBy: trackedBy, data: data, renderItem: renderItem, states: { currentDate: states.currentDate }, config: config }));
|
|
10
10
|
else if (states.view.get === "Month")
|
|
11
11
|
return React.createElement(Month, null);
|
|
12
12
|
return React.createElement(React.Fragment, null, "...");
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import IProps from "./IProps";
|
|
3
3
|
import "../../../assets/css/components/data-display/calendar/styles.css";
|
|
4
4
|
declare const Calendar: {
|
|
5
|
-
<T>({ data, renderItem, config }: IProps<T>): React.JSX.Element;
|
|
5
|
+
<T>({ trackedBy, data, renderItem, config }: IProps<T>): React.JSX.Element;
|
|
6
6
|
displayName: string;
|
|
7
7
|
};
|
|
8
8
|
export default Calendar;
|
|
@@ -3,7 +3,7 @@ import React, { useState } from "react";
|
|
|
3
3
|
import Body from "./Body";
|
|
4
4
|
import Header from "./Header";
|
|
5
5
|
import "../../../assets/css/components/data-display/calendar/styles.css";
|
|
6
|
-
const Calendar = function ({ data, renderItem, config }) {
|
|
6
|
+
const Calendar = function ({ trackedBy, data, renderItem, config }) {
|
|
7
7
|
// states
|
|
8
8
|
const [currentDate, setCurrentDate] = useState(new Date());
|
|
9
9
|
const [view, setView] = useState("Week");
|
|
@@ -15,7 +15,7 @@ const Calendar = function ({ data, renderItem, config }) {
|
|
|
15
15
|
set: setView,
|
|
16
16
|
},
|
|
17
17
|
}, config: config }),
|
|
18
|
-
React.createElement(Body, { data: data, renderItem: renderItem, states: {
|
|
18
|
+
React.createElement(Body, { trackedBy: trackedBy, data: data, renderItem: renderItem, states: {
|
|
19
19
|
currentDate: { get: currentDate, set: setCurrentDate },
|
|
20
20
|
view: {
|
|
21
21
|
get: view,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CalendarEvent } from "../IProps";
|
|
3
3
|
interface IProps<T> {
|
|
4
|
+
trackedBy: keyof (T & CalendarEvent);
|
|
4
5
|
data: (T & CalendarEvent)[];
|
|
5
6
|
renderItem: (item: T, index: number) => React.JSX.Element;
|
|
6
7
|
states: {
|
|
@@ -14,5 +15,5 @@ interface IProps<T> {
|
|
|
14
15
|
weekStartsOn?: number;
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
|
-
declare const Week: <T>({ data, renderItem, states, config }: IProps<T>) => React.JSX.Element;
|
|
18
|
+
declare const Week: <T>({ trackedBy, data, renderItem, states, config }: IProps<T>) => React.JSX.Element;
|
|
18
19
|
export default Week;
|
|
@@ -1,61 +1,138 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
2
|
-
|
|
1
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import ReactDOM from "react-dom";
|
|
3
|
+
const Week = function ({ trackedBy, data, renderItem, states, config }) {
|
|
4
|
+
// states
|
|
5
|
+
const [mouseCoordinate, setMouseCoordinate] = useState({
|
|
6
|
+
x: 0,
|
|
7
|
+
y: 0,
|
|
8
|
+
isRightHalf: false,
|
|
9
|
+
isBottomHalf: false,
|
|
10
|
+
});
|
|
11
|
+
const [activeTooltip, setActiveTooltip] = useState(null);
|
|
12
|
+
// variables
|
|
3
13
|
const startHour = 0;
|
|
4
14
|
const endHour = 24;
|
|
5
15
|
const hours = endHour - startHour;
|
|
6
|
-
const cellHeight = 60;
|
|
16
|
+
// const cellHeight = 60;
|
|
17
|
+
// methods
|
|
7
18
|
const weekDays = useMemo(() => getWeekDays(states.currentDate.get, config?.weekStartsOn ?? 1), [states.currentDate.get, config?.weekStartsOn]);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
19
|
+
// useEffects
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const handleMouseMove = (event) => {
|
|
22
|
+
setMouseCoordinate({
|
|
23
|
+
x: event.clientX,
|
|
24
|
+
y: event.clientY,
|
|
25
|
+
isRightHalf: event.clientX > window.innerWidth / 2,
|
|
26
|
+
isBottomHalf: event.clientY > window.innerHeight / 2,
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
30
|
+
return () => {
|
|
31
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
return (React.createElement(React.Fragment, null,
|
|
35
|
+
React.createElement("div", { className: "ar-calendar-week-view" },
|
|
36
|
+
React.createElement("div", { className: "head" }, weekDays.map((day) => (React.createElement("div", { key: day.toISOString(), className: "item" },
|
|
37
|
+
React.createElement("span", { className: "day-name" }, day.toLocaleString(config?.locale ?? "tr", { weekday: "short" }).toUpperCase()),
|
|
38
|
+
React.createElement("span", { className: "date" }, day.getDate()))))),
|
|
39
|
+
React.createElement("div", { className: "body" },
|
|
40
|
+
React.createElement("div", { className: "clocks" }, Array.from({ length: hours }, (_, index) => (React.createElement("div", { key: index },
|
|
41
|
+
React.createElement("span", null,
|
|
42
|
+
String(startHour + index).padStart(2, "0"),
|
|
43
|
+
":00"))))),
|
|
44
|
+
React.createElement("div", { role: "grid", className: "grid" }, Array.from({ length: hours }).map((_, rowIndex) => (React.createElement("div", { key: rowIndex, className: "row" }, weekDays.map((_, colIndex) => (React.createElement("div", { key: colIndex, className: "cell" }))))))),
|
|
45
|
+
React.createElement("div", { className: "events-layer" }, weekDays.map((day, dayIndex) => {
|
|
46
|
+
const dayStart = new Date(day).setHours(0, 0, 0, 0);
|
|
47
|
+
const dayEnd = new Date(day).setHours(23, 59, 59, 999);
|
|
48
|
+
// 1. Bu güne ait etkinlikleri filtrele ve sırala.
|
|
49
|
+
const dayEvents = data
|
|
50
|
+
.filter((event) => {
|
|
51
|
+
return event.start.getTime() <= dayEnd && event.end.getTime() >= dayStart;
|
|
52
|
+
})
|
|
53
|
+
.sort((a, b) => a.start.getTime() - b.start.getTime());
|
|
54
|
+
// 2. Çakışmaları hesapla (Görsel yerleşim için kritik adım).
|
|
55
|
+
const positionedEvents = computeEventLayout(dayEvents, dayStart, dayEnd);
|
|
56
|
+
return positionedEvents.map(({ event, layout, originalIndex }) => {
|
|
57
|
+
const uniqueValue = event[trackedBy];
|
|
58
|
+
const eventColor = getColor(uniqueValue);
|
|
59
|
+
return (React.createElement("div", { key: `${originalIndex}-${dayIndex}`, onMouseEnter: () => setActiveTooltip({ content: renderItem(event, originalIndex), id: originalIndex }), onMouseLeave: () => setActiveTooltip(null), className: "event-box", style: {
|
|
60
|
+
backgroundColor: eventColor.bg,
|
|
61
|
+
position: "absolute",
|
|
62
|
+
top: `${layout.top}px`,
|
|
63
|
+
height: `${layout.height}px`,
|
|
64
|
+
// Dinamik genişlik ve sol mesafe hesaplama.
|
|
65
|
+
left: `calc(${(100 / 7) * dayIndex}% + ${(layout.column * (100 / 7)) / layout.totalColumns}%)`,
|
|
66
|
+
width: `${100 / 7 / layout.totalColumns}%`,
|
|
67
|
+
border: `1px solid ${eventColor.border}`,
|
|
68
|
+
borderRadius: "var(--border-radius-sm)",
|
|
69
|
+
zIndex: 10,
|
|
70
|
+
} }, layout.height > 20 && renderItem(event, originalIndex)));
|
|
55
71
|
});
|
|
56
|
-
}))))
|
|
72
|
+
})))),
|
|
73
|
+
activeTooltip &&
|
|
74
|
+
ReactDOM.createPortal(React.createElement("div", { className: "ar-calendar-tooltip", style: {
|
|
75
|
+
top: mouseCoordinate.y,
|
|
76
|
+
left: mouseCoordinate.x,
|
|
77
|
+
transform: `translate(${mouseCoordinate.isRightHalf ? "-110%" : "10%"}, ${mouseCoordinate.isBottomHalf ? "-110%" : "10%"})`,
|
|
78
|
+
} }, activeTooltip.content), document.body)));
|
|
57
79
|
};
|
|
58
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Etkinliklerin çakışma durumuna göre konumlarını hesaplayan yardımcı fonksiyon
|
|
82
|
+
*/
|
|
83
|
+
function computeEventLayout(events, dayStart, dayEnd) {
|
|
84
|
+
const cellHeight = 60;
|
|
85
|
+
const results = [];
|
|
86
|
+
// Gruplandırma (Aynı anda çakışan etkinlik kümeleri)
|
|
87
|
+
let clusters = [];
|
|
88
|
+
let lastEventEnd = 0;
|
|
89
|
+
events.forEach((event, idx) => {
|
|
90
|
+
const start = Math.max(event.start.getTime(), dayStart);
|
|
91
|
+
const end = Math.min(event.end.getTime(), dayEnd);
|
|
92
|
+
if (start >= lastEventEnd) {
|
|
93
|
+
clusters.push([]); // Yeni bir küme başlat
|
|
94
|
+
}
|
|
95
|
+
const lastCluster = clusters[clusters.length - 1];
|
|
96
|
+
lastCluster.push({ event, idx, start, end });
|
|
97
|
+
lastEventEnd = Math.max(lastEventEnd, end);
|
|
98
|
+
});
|
|
99
|
+
// Her küme içindeki kolonları hesapla
|
|
100
|
+
clusters.forEach((cluster) => {
|
|
101
|
+
const columns = [];
|
|
102
|
+
cluster.forEach((item) => {
|
|
103
|
+
let placed = false;
|
|
104
|
+
for (let i = 0; i < columns.length; i++) {
|
|
105
|
+
// Eğer bu kolondaki son etkinlikle çakışmıyorsa buraya koy
|
|
106
|
+
const lastInColumn = columns[i][columns[i].length - 1];
|
|
107
|
+
if (item.start >= lastInColumn.end) {
|
|
108
|
+
columns[i].push(item);
|
|
109
|
+
placed = true;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!placed) {
|
|
114
|
+
columns.push([item]); // Yeni kolon aç
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// Sonuçları formatla
|
|
118
|
+
cluster.forEach((item) => {
|
|
119
|
+
const colIndex = columns.findIndex((col) => col.includes(item));
|
|
120
|
+
const startMinutes = new Date(item.start).getHours() * 60 + new Date(item.start).getMinutes();
|
|
121
|
+
const duration = (item.end - item.start) / 60000;
|
|
122
|
+
results.push({
|
|
123
|
+
event: item.event,
|
|
124
|
+
originalIndex: item.idx,
|
|
125
|
+
layout: {
|
|
126
|
+
top: (startMinutes / 60) * cellHeight,
|
|
127
|
+
height: (duration / 60) * cellHeight,
|
|
128
|
+
column: colIndex,
|
|
129
|
+
totalColumns: columns.length,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
return results;
|
|
135
|
+
}
|
|
59
136
|
const getWeekRange = (date, weekStartsOn = 1) => {
|
|
60
137
|
const current = new Date(date);
|
|
61
138
|
const currentDay = current.getDay();
|
|
@@ -84,7 +161,13 @@ const getColor = (id) => {
|
|
|
84
161
|
{ bg: "#e91e63", border: "#c2185b" }, // Pembe
|
|
85
162
|
{ bg: "#00bcd4", border: "#0097a7" }, // Turkuaz
|
|
86
163
|
];
|
|
87
|
-
|
|
164
|
+
// Eğer id string ise karakter kodlarının toplamını alarak tutarlı bir index üretiriz
|
|
165
|
+
let hash = 0;
|
|
166
|
+
const identifier = String(id);
|
|
167
|
+
for (let i = 0; i < identifier.length; i++) {
|
|
168
|
+
hash = identifier.charCodeAt(i) + ((hash << 5) - hash);
|
|
169
|
+
}
|
|
170
|
+
const index = Math.abs(hash);
|
|
88
171
|
return colors[index % colors.length];
|
|
89
172
|
};
|
|
90
173
|
export default Week;
|