funuicss 2.7.9 → 2.7.10
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/css/fun.css +59 -21
- package/index.tsx +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/ui/accordion/Accordion.d.ts +16 -2
- package/ui/accordion/Accordion.js +8 -8
- package/ui/accordion/Accordion.tsx +24 -17
- package/ui/avatar/Avatar.js +5 -4
- package/ui/avatar/Avatar.tsx +3 -1
- package/ui/button/Button.d.ts +1 -1
- package/ui/button/Button.js +1 -1
- package/ui/button/Button.tsx +3 -2
- package/ui/calendar/ActivityCard.d.ts +8 -0
- package/ui/calendar/ActivityCard.js +18 -0
- package/ui/calendar/ActivityCard.tsx +27 -0
- package/ui/calendar/Calendar.d.ts +5 -2
- package/ui/calendar/Calendar.js +119 -84
- package/ui/calendar/Calendar.tsx +211 -161
- package/ui/datepicker/DatePicker.js +4 -3
- package/ui/datepicker/DatePicker.tsx +8 -3
- package/ui/drop/Dropdown.js +17 -17
- package/ui/drop/Dropdown.tsx +31 -29
package/ui/calendar/Calendar.tsx
CHANGED
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import dayjs, { Dayjs } from 'dayjs';
|
|
4
4
|
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
|
5
5
|
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
|
6
|
-
import { PiCaretLeft, PiCaretRight, PiPlus, PiCircle, PiChecks } from 'react-icons/pi';
|
|
6
|
+
import { PiCaretLeft, PiCaretRight, PiPlus, PiCircle, PiChecks, PiEmpty } from 'react-icons/pi';
|
|
7
7
|
import Avatar from '../avatar/Avatar';
|
|
8
8
|
import Circle from '../specials/Circle';
|
|
9
9
|
import RowFlex from '../specials/RowFlex';
|
|
10
10
|
import Input from '../input/Input';
|
|
11
11
|
import Button from '../button/Button';
|
|
12
12
|
import Text from '../text/Text';
|
|
13
|
+
import ActivityCard from './ActivityCard';
|
|
14
|
+
import View from '../view/View';
|
|
15
|
+
import Dropdown from '../drop/Dropdown';
|
|
16
|
+
import { HiOutlineDotsVertical } from "react-icons/hi";
|
|
13
17
|
|
|
14
18
|
dayjs.extend(isSameOrAfter);
|
|
15
19
|
dayjs.extend(isSameOrBefore);
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
export type Activity = {
|
|
18
22
|
id: string;
|
|
19
23
|
title: string;
|
|
20
24
|
date: Date;
|
|
21
25
|
color?: string;
|
|
26
|
+
funcss?: string;
|
|
27
|
+
data?: any;
|
|
28
|
+
footer?: React.ReactNode;
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
interface CalendarProps {
|
|
@@ -27,7 +34,7 @@ interface CalendarProps {
|
|
|
27
34
|
onActivityClick?: (activity: Activity) => void;
|
|
28
35
|
onDateClick?: (date: Date) => void;
|
|
29
36
|
funcss?: string;
|
|
30
|
-
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
37
|
+
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
31
38
|
renderActivity?: (activity: Activity) => React.ReactNode;
|
|
32
39
|
showAdjacentMonths?: boolean;
|
|
33
40
|
minDate?: Date;
|
|
@@ -49,62 +56,74 @@ const Calendar: React.FC<CalendarProps> = ({
|
|
|
49
56
|
const [currentMonth, setCurrentMonth] = useState<Dayjs>(dayjs());
|
|
50
57
|
const [hoveredDate, setHoveredDate] = useState<string | null>(null);
|
|
51
58
|
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
|
|
59
|
+
const [showMoreActivities, setShowMoreActivities] = useState(false);
|
|
60
|
+
|
|
61
|
+
// ✅ NEW: View mode state
|
|
62
|
+
const [viewMode, setViewMode] = useState<'month' | 'week'>('month');
|
|
63
|
+
|
|
64
|
+
const startOfWeek = currentMonth.startOf('week').add(weekStart, 'day');
|
|
52
65
|
|
|
53
|
-
// Memoized calculations
|
|
54
66
|
const { days, monthActivities } = useMemo(() => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
let days: (Dayjs | null)[] = [];
|
|
68
|
+
|
|
69
|
+
if (viewMode === 'month') {
|
|
70
|
+
const startOfMonth = currentMonth.startOf('month');
|
|
71
|
+
const endOfMonth = currentMonth.endOf('month');
|
|
72
|
+
const firstDay = startOfMonth.day();
|
|
73
|
+
const daysBefore = (firstDay - weekStart + 7) % 7;
|
|
74
|
+
const daysInMonth = currentMonth.daysInMonth();
|
|
75
|
+
const totalDays = Math.ceil((daysBefore + daysInMonth) / 7) * 7;
|
|
76
|
+
|
|
77
|
+
for (let i = daysBefore - 1; i >= 0; i--) {
|
|
78
|
+
const date = startOfMonth.subtract(i + 1, 'day');
|
|
79
|
+
days.push(showAdjacentMonths ? date : null);
|
|
80
|
+
}
|
|
81
|
+
for (let i = 0; i < daysInMonth; i++) {
|
|
82
|
+
days.push(startOfMonth.add(i, 'day'));
|
|
83
|
+
}
|
|
84
|
+
const remaining = totalDays - days.length;
|
|
85
|
+
for (let i = 0; i < remaining; i++) {
|
|
86
|
+
const date = endOfMonth.add(i + 1, 'day');
|
|
87
|
+
days.push(showAdjacentMonths ? date : null);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
// ✅ Week View: only 7 days
|
|
91
|
+
for (let i = 0; i < 7; i++) {
|
|
92
|
+
days.push(startOfWeek.add(i, 'day'));
|
|
93
|
+
}
|
|
82
94
|
}
|
|
83
|
-
|
|
84
|
-
// Group activities by date
|
|
95
|
+
|
|
85
96
|
const monthActivities: Record<string, Activity[]> = {};
|
|
86
97
|
activities.forEach(activity => {
|
|
87
98
|
const date = dayjs(activity.date);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
const key = date.format('YYYY-MM-DD');
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
viewMode === 'month' &&
|
|
103
|
+
(date.isSame(currentMonth, 'month') || (showAdjacentMonths &&
|
|
104
|
+
(date.isBefore(currentMonth.endOf('month')) && date.isAfter(currentMonth.startOf('month')))))
|
|
105
|
+
) {
|
|
106
|
+
if (!monthActivities[key]) monthActivities[key] = [];
|
|
107
|
+
monthActivities[key].push(activity);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (viewMode === 'week' && date.isSame(startOfWeek, 'week')) {
|
|
91
111
|
if (!monthActivities[key]) monthActivities[key] = [];
|
|
92
112
|
monthActivities[key].push(activity);
|
|
93
113
|
}
|
|
94
114
|
});
|
|
95
|
-
|
|
115
|
+
|
|
96
116
|
return { days, monthActivities };
|
|
97
|
-
}, [currentMonth, activities, weekStart, showAdjacentMonths]);
|
|
117
|
+
}, [currentMonth, activities, viewMode, weekStart, showAdjacentMonths]);
|
|
98
118
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
119
|
+
const prevPeriod = () =>
|
|
120
|
+
setCurrentMonth(currentMonth.subtract(1, viewMode === 'month' ? 'month' : 'week'));
|
|
121
|
+
const nextPeriod = () =>
|
|
122
|
+
setCurrentMonth(currentMonth.add(1, viewMode === 'month' ? 'month' : 'week'));
|
|
102
123
|
const goToToday = () => setCurrentMonth(dayjs());
|
|
103
|
-
|
|
104
|
-
// Date handlers
|
|
124
|
+
|
|
105
125
|
const handleDateClick = (date: Dayjs) => {
|
|
106
126
|
if (isDateDisabled(date)) return;
|
|
107
|
-
|
|
108
127
|
setSelectedDate(date.toDate());
|
|
109
128
|
onDateClick?.(date.toDate());
|
|
110
129
|
};
|
|
@@ -115,19 +134,13 @@ const Calendar: React.FC<CalendarProps> = ({
|
|
|
115
134
|
onAdd?.(date.toDate());
|
|
116
135
|
};
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
(minDate && date.isBefore(dayjs(minDate), 'day')) ||
|
|
122
|
-
(maxDate && date.isAfter(dayjs(maxDate), 'day'))
|
|
123
|
-
);
|
|
124
|
-
};
|
|
137
|
+
const isDateDisabled = (date: Dayjs) =>
|
|
138
|
+
(minDate && date.isBefore(dayjs(minDate), 'day')) ||
|
|
139
|
+
(maxDate && date.isAfter(dayjs(maxDate), 'day'));
|
|
125
140
|
|
|
126
141
|
const isToday = (date: Dayjs) => date.isSame(dayjs(), 'day');
|
|
127
142
|
const isSelected = (date: Dayjs) => selectedDate && date.isSame(selectedDate, 'day');
|
|
128
|
-
const isCurrentMonth = (date: Dayjs) => date.isSame(currentMonth, 'month');
|
|
129
143
|
|
|
130
|
-
// Weekday headers
|
|
131
144
|
const weekdays = useMemo(() => {
|
|
132
145
|
const days = [];
|
|
133
146
|
for (let i = 0; i < 7; i++) {
|
|
@@ -137,157 +150,194 @@ const Calendar: React.FC<CalendarProps> = ({
|
|
|
137
150
|
return days;
|
|
138
151
|
}, [weekStart]);
|
|
139
152
|
|
|
153
|
+
|
|
154
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const updateViewMode = () => {
|
|
158
|
+
const small = window.innerWidth < 768;
|
|
159
|
+
setIsMobile(small);
|
|
160
|
+
setViewMode(small ? 'week' : 'month');
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
updateViewMode(); // initial check
|
|
164
|
+
window.addEventListener('resize', updateViewMode);
|
|
165
|
+
return () => window.removeEventListener('resize', updateViewMode);
|
|
166
|
+
}, []);
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
140
170
|
return (
|
|
141
171
|
<div className={`calendar ${funcss}`}>
|
|
142
172
|
<div className="calendar-header">
|
|
143
|
-
<Avatar funcss=
|
|
173
|
+
<Avatar funcss="border" onClick={prevPeriod}>
|
|
144
174
|
<PiCaretLeft />
|
|
145
175
|
</Avatar>
|
|
146
|
-
|
|
176
|
+
|
|
147
177
|
<div className="calendar-title">
|
|
178
|
+
<RowFlex gap={1} align="center">
|
|
179
|
+
<Input
|
|
180
|
+
type="text"
|
|
181
|
+
select
|
|
182
|
+
value={currentMonth.month().toString()}
|
|
183
|
+
onChange={(e) =>
|
|
184
|
+
setCurrentMonth(currentMonth.month(parseInt(e.target.value)))
|
|
185
|
+
}
|
|
186
|
+
options={Array.from({ length: 12 }, (_, i) => ({
|
|
187
|
+
value: i.toString(),
|
|
188
|
+
text: dayjs().month(i).format('MMMM'),
|
|
189
|
+
}))}
|
|
190
|
+
borderless
|
|
191
|
+
funcss="round-edge"
|
|
192
|
+
/>
|
|
193
|
+
|
|
194
|
+
<Input
|
|
195
|
+
type="text"
|
|
196
|
+
select
|
|
197
|
+
value={currentMonth.year().toString()}
|
|
198
|
+
onChange={(e) =>
|
|
199
|
+
setCurrentMonth(currentMonth.year(parseInt(e.target.value)))
|
|
200
|
+
}
|
|
201
|
+
options={Array.from({ length: 21 }, (_, i) => {
|
|
202
|
+
const year = dayjs().year() - 10 + i;
|
|
203
|
+
return { value: year.toString(), text: year.toString() };
|
|
204
|
+
})}
|
|
205
|
+
borderless
|
|
206
|
+
funcss="round-edge"
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
<Dropdown
|
|
210
|
+
direction="dropdown"
|
|
211
|
+
position='right'
|
|
212
|
+
openOnHover={false}
|
|
213
|
+
button={
|
|
214
|
+
<Avatar>
|
|
215
|
+
<HiOutlineDotsVertical />
|
|
216
|
+
</Avatar>
|
|
217
|
+
}
|
|
218
|
+
items={[
|
|
219
|
+
{
|
|
220
|
+
label: <span className="text-sm">Today</span>,
|
|
221
|
+
onClick: () => goToToday(),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
label: <div className="text-sm" onClick={() =>
|
|
225
|
+
setViewMode(viewMode === 'month' ? 'week' : 'month')
|
|
226
|
+
}>
|
|
227
|
+
{viewMode === 'month' ? 'Switch to Week' : 'Switch to Month'}
|
|
228
|
+
</div>,
|
|
229
|
+
},
|
|
230
|
+
]}
|
|
231
|
+
/>
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
</RowFlex>
|
|
235
|
+
</div>
|
|
148
236
|
|
|
149
|
-
|
|
150
|
-
value={currentMonth.month()}
|
|
151
|
-
onChange={(e) => {
|
|
152
|
-
const newMonth = currentMonth.month(parseInt(e.target.value));
|
|
153
|
-
setCurrentMonth(newMonth);
|
|
154
|
-
}}
|
|
155
|
-
type="text"
|
|
156
|
-
label="Select Month"
|
|
157
|
-
borderless
|
|
158
|
-
fullWidth
|
|
159
|
-
funcss='round-edge'
|
|
160
|
-
select
|
|
161
|
-
options={[
|
|
162
|
-
{ value: "", text: "-- Select month --" },
|
|
163
|
-
{ value: "0", text: "January" },
|
|
164
|
-
{ value: "1", text: "February" },
|
|
165
|
-
{ value: "2", text: "March" },
|
|
166
|
-
{ value: "3", text: "April" },
|
|
167
|
-
{ value: "4", text: "May" },
|
|
168
|
-
{ value: "5", text: "June" },
|
|
169
|
-
{ value: "6", text: "July" },
|
|
170
|
-
{ value: "7", text: "August" },
|
|
171
|
-
{ value: "8", text: "September" },
|
|
172
|
-
{ value: "9", text: "October" },
|
|
173
|
-
{ value: "10", text: "November" },
|
|
174
|
-
{ value: "11", text: "December" }
|
|
175
|
-
]}
|
|
176
|
-
/>
|
|
177
|
-
<Input
|
|
178
|
-
type="text"
|
|
179
|
-
label="Select Year"
|
|
180
|
-
funcss='round-edge'
|
|
181
|
-
fullWidth
|
|
182
|
-
borderless
|
|
183
|
-
select
|
|
184
|
-
value={currentMonth.year().toString()}
|
|
185
|
-
onChange={(e) => {
|
|
186
|
-
const newYear = currentMonth.year(parseInt(e.target.value));
|
|
187
|
-
setCurrentMonth(newYear);
|
|
188
|
-
}}
|
|
189
|
-
options={Array.from({ length: 21 }, (_, i) => {
|
|
190
|
-
const year = dayjs().year() - 10 + i;
|
|
191
|
-
return {
|
|
192
|
-
value: year.toString(),
|
|
193
|
-
text: year.toString(),
|
|
194
|
-
};
|
|
195
|
-
})}
|
|
196
|
-
/>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
<Button bg='lighter border' onClick={goToToday}>Today</Button>
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
<Avatar funcss='border' onClick={nextMonth} aria-label="Next month">
|
|
237
|
+
<Avatar funcss="border" onClick={nextPeriod}>
|
|
204
238
|
<PiCaretRight />
|
|
205
239
|
</Avatar>
|
|
206
240
|
</div>
|
|
207
241
|
|
|
208
242
|
<div className="calendar-weekdays">
|
|
209
243
|
{weekdays.map((d, i) => (
|
|
210
|
-
<div key={i} className="weekday-header">
|
|
244
|
+
<div key={i} className="weekday-header">
|
|
245
|
+
{d}
|
|
246
|
+
</div>
|
|
211
247
|
))}
|
|
212
248
|
</div>
|
|
213
249
|
|
|
214
250
|
<div className="calendar-grid">
|
|
215
251
|
{days.map((date, index) => {
|
|
216
|
-
if (!date
|
|
217
|
-
|
|
252
|
+
if (!date || (viewMode === 'month' && !date.isSame(currentMonth, 'month'))) {
|
|
253
|
+
return <div key={index} className="calendar-cell empty" />;
|
|
254
|
+
}
|
|
255
|
+
|
|
218
256
|
const key = date.format('YYYY-MM-DD');
|
|
219
257
|
const activitiesToday = monthActivities[key] || [];
|
|
220
258
|
const disabled = isDateDisabled(date);
|
|
221
259
|
const today = isToday(date);
|
|
222
260
|
const selected = isSelected(date);
|
|
223
|
-
|
|
224
|
-
|
|
261
|
+
|
|
225
262
|
return (
|
|
226
263
|
<div
|
|
227
264
|
key={key}
|
|
228
|
-
className={`calendar-cell ${
|
|
229
|
-
!currentMonth ? 'adjacent-month' : ''} ${
|
|
230
|
-
disabled ? 'disabled' : ''} ${
|
|
231
|
-
today ? 'today' : ''} ${
|
|
232
|
-
selected ? 'selected' : ''}`
|
|
233
|
-
}
|
|
265
|
+
className={`calendar-cell hoverable ${disabled ? 'disabled' : ''} ${today ? 'today' : ''} ${selected ? 'selected' : ''}`}
|
|
234
266
|
onClick={() => handleDateClick(date)}
|
|
235
267
|
onMouseEnter={() => setHoveredDate(key)}
|
|
236
268
|
onMouseLeave={() => setHoveredDate(null)}
|
|
237
|
-
aria-disabled={disabled}
|
|
238
|
-
aria-label={date.format('MMMM D, YYYY')}
|
|
239
|
-
role="button"
|
|
240
|
-
tabIndex={0}
|
|
241
269
|
>
|
|
242
|
-
<div className=
|
|
243
|
-
|
|
244
|
-
<Text
|
|
245
|
-
text= {date.date()}
|
|
246
|
-
color={today ? 'primary' : ''}
|
|
247
|
-
size='xl'
|
|
248
|
-
/>
|
|
249
|
-
{today && <PiChecks className="text-success" />}
|
|
250
|
-
</RowFlex>
|
|
270
|
+
<div className={`day-number ${today ? 'today' : ''}`}>
|
|
271
|
+
{date.date()}
|
|
251
272
|
</div>
|
|
252
273
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
e.stopPropagation();
|
|
261
|
-
onActivityClick?.(activity);
|
|
262
|
-
}}
|
|
263
|
-
>
|
|
264
|
-
{renderActivity ? renderActivity(activity) : activity.title}
|
|
265
|
-
</div>
|
|
274
|
+
{
|
|
275
|
+
!isMobile && (
|
|
276
|
+
<div className="activities ">
|
|
277
|
+
{activitiesToday.slice(0, showMoreActivities ? activitiesToday.length : 3).map((activity) => (
|
|
278
|
+
<ActivityCard activity={activity} onClick={(e) => {
|
|
279
|
+
onActivityClick?.(activity);
|
|
280
|
+
}}/>
|
|
266
281
|
))}
|
|
267
|
-
{activitiesToday.length >
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
</
|
|
282
|
+
{activitiesToday.length > 3 && (
|
|
283
|
+
<Button smaller funcss='p-0' color="primary" onClick={() => setShowMoreActivities(!showMoreActivities)}>
|
|
284
|
+
{showMoreActivities ? 'Show Less' : <>+{activitiesToday.length - 3} more</>}
|
|
285
|
+
</Button>
|
|
271
286
|
)}
|
|
272
287
|
</div>
|
|
288
|
+
)
|
|
289
|
+
}
|
|
273
290
|
|
|
274
291
|
{hoveredDate === key && !disabled && (
|
|
275
|
-
<div
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
>
|
|
280
|
-
<Circle hoverable funcss='card bg'>
|
|
281
|
-
<PiPlus />
|
|
282
|
-
</Circle>
|
|
292
|
+
<div className="add-icon hide-small" onClick={(e) => handleAdd(e, date)}>
|
|
293
|
+
<Circle bg='primary'>
|
|
294
|
+
<PiPlus />
|
|
295
|
+
</Circle>
|
|
283
296
|
</div>
|
|
284
297
|
)}
|
|
285
298
|
</div>
|
|
286
299
|
);
|
|
287
300
|
})}
|
|
288
301
|
</div>
|
|
302
|
+
|
|
303
|
+
{isMobile && selectedDate && (
|
|
304
|
+
<div className="calendar-activities-mobile p-1">
|
|
305
|
+
<RowFlex gap={0.5} justify="space-between" align="center" className="mt-3 mb-2">
|
|
306
|
+
<Text
|
|
307
|
+
text={dayjs(selectedDate).format('dddd, MMMM D')}
|
|
308
|
+
weight={600}
|
|
309
|
+
funcss="mb-2"
|
|
310
|
+
/>
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
<div onClick={(e) => handleAdd(e, dayjs(selectedDate))}>
|
|
314
|
+
<Circle bg="primary">
|
|
315
|
+
<PiPlus />
|
|
316
|
+
</Circle>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
</RowFlex>
|
|
320
|
+
{(monthActivities[dayjs(selectedDate).format('YYYY-MM-DD')] || []).map((activity) => (
|
|
321
|
+
<ActivityCard activity={activity} onClick={(e) => {
|
|
322
|
+
onActivityClick?.(activity);
|
|
323
|
+
}}/>
|
|
324
|
+
))}
|
|
325
|
+
{(monthActivities[dayjs(selectedDate).format('YYYY-MM-DD')] || []).length === 0 && (
|
|
326
|
+
<View funcss='mt-2 text-center'>
|
|
327
|
+
<div> <PiEmpty size={30}/></div>
|
|
328
|
+
<Text text="No activities for this day." size="sm" opacity={2} />
|
|
329
|
+
<div className="mt-2">
|
|
330
|
+
<span onClick={(e) => handleAdd(e, dayjs(selectedDate))}>
|
|
331
|
+
<Button small bg='lighter' startIcon={<PiPlus />}>Add Activity</Button>
|
|
332
|
+
</span>
|
|
333
|
+
</div>
|
|
334
|
+
</View>
|
|
335
|
+
)}
|
|
336
|
+
</div>
|
|
337
|
+
)}
|
|
338
|
+
|
|
289
339
|
</div>
|
|
290
340
|
);
|
|
291
341
|
};
|
|
292
342
|
|
|
293
|
-
export default Calendar;
|
|
343
|
+
export default Calendar;
|
|
@@ -115,15 +115,16 @@ var DatePicker = function (_a) {
|
|
|
115
115
|
"Selected: ",
|
|
116
116
|
formatDate(selected))),
|
|
117
117
|
mode === 'interval' && Array.isArray(selected) && (react_1.default.createElement("div", { className: 'text-sm' }, selected[1]
|
|
118
|
-
? "
|
|
119
|
-
: "
|
|
118
|
+
? "".concat(formatDate(selected[0]), " to ").concat(formatDate(selected[1]))
|
|
119
|
+
: " ".concat(formatDate(selected[0]), " - End date")))),
|
|
120
120
|
react_1.default.createElement("div", { style: { lineHeight: "0" } },
|
|
121
121
|
react_1.default.createElement(pi_1.PiX, { className: "clear-icon", onClick: handleClear, style: { cursor: 'pointer' } })))),
|
|
122
122
|
react_1.default.createElement("div", { className: "datepicker-weekdays" }, ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map(function (d) { return (react_1.default.createElement("div", { key: d }, d)); })),
|
|
123
123
|
react_1.default.createElement("div", { className: "datepicker-grid" }, days.map(function (date, idx) {
|
|
124
124
|
var isSelectedClass = date && isSelected(date) ? 'selected' : '';
|
|
125
125
|
var isInRangeClass = date && isSelected(date) && Array.isArray(selected) ? 'in-range' : '';
|
|
126
|
-
return (react_1.default.createElement("div", { key: idx, onClick: function () { return date && handleSelect(date); }
|
|
126
|
+
return (react_1.default.createElement("div", { key: idx, onClick: function () { return date && handleSelect(date); } }, date &&
|
|
127
|
+
react_1.default.createElement(Avatar_1.default, { funcss: "borderless datepicker-day ".concat(!date ? 'empty' : '', " ").concat(isSelectedClass, " ").concat(isInRangeClass) }, date ? (0, dayjs_1.default)(date).date() : '')));
|
|
127
128
|
}))));
|
|
128
129
|
};
|
|
129
130
|
exports.default = DatePicker;
|
|
@@ -103,8 +103,8 @@ const DatePicker: React.FC<DatePickerProps> = ({
|
|
|
103
103
|
{mode === 'interval' && Array.isArray(selected) && (
|
|
104
104
|
<div className='text-sm'>
|
|
105
105
|
{selected[1]
|
|
106
|
-
?
|
|
107
|
-
: `
|
|
106
|
+
? `${formatDate(selected[0])} to ${formatDate(selected[1])}`
|
|
107
|
+
: ` ${formatDate(selected[0])} - End date`}
|
|
108
108
|
</div>
|
|
109
109
|
)}
|
|
110
110
|
</span>
|
|
@@ -129,9 +129,14 @@ const DatePicker: React.FC<DatePickerProps> = ({
|
|
|
129
129
|
<div
|
|
130
130
|
key={idx}
|
|
131
131
|
onClick={() => date && handleSelect(date)}
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
>
|
|
134
|
+
{
|
|
135
|
+
date &&
|
|
136
|
+
<Avatar funcss={`borderless datepicker-day ${!date ? 'empty' : ''} ${isSelectedClass} ${isInRangeClass}`}>
|
|
134
137
|
{date ? dayjs(date).date() : ''}
|
|
138
|
+
</Avatar>
|
|
139
|
+
}
|
|
135
140
|
</div>
|
|
136
141
|
);
|
|
137
142
|
})}
|
package/ui/drop/Dropdown.js
CHANGED
|
@@ -40,7 +40,7 @@ var Dropdown = function (_a) {
|
|
|
40
40
|
var containerRef = (0, react_1.useRef)(null);
|
|
41
41
|
var _h = (0, react_1.useState)(false), open = _h[0], setOpen = _h[1];
|
|
42
42
|
var containerClass = "".concat(direction, " ").concat(position, " ").concat(className).trim();
|
|
43
|
-
var menuClass = "drop-menu".concat(hoverable ? ' item-hoverable' : '');
|
|
43
|
+
var menuClass = "drop-menu ".concat(hoverable ? ' item-hoverable' : '');
|
|
44
44
|
(0, react_1.useEffect)(function () {
|
|
45
45
|
if (openOnHover)
|
|
46
46
|
return;
|
|
@@ -55,21 +55,21 @@ var Dropdown = function (_a) {
|
|
|
55
55
|
var showMenu = openOnHover || open;
|
|
56
56
|
return (react_1.default.createElement("div", { ref: containerRef, className: containerClass, onMouseEnter: function () { return openOnHover && setOpen(true); }, onMouseLeave: function () { return openOnHover && setOpen(false); } },
|
|
57
57
|
react_1.default.createElement("div", { className: "drop-button", onClick: function () { return !openOnHover && setOpen(!open); }, style: { cursor: !openOnHover ? 'pointer' : undefined } }, button),
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
showMenu &&
|
|
59
|
+
react_1.default.createElement("div", { className: menuClass, style: {
|
|
60
|
+
width: width,
|
|
61
|
+
minWidth: minWidth,
|
|
62
|
+
maxWidth: maxWidth,
|
|
63
|
+
height: height,
|
|
64
|
+
minHeight: minHeight,
|
|
65
|
+
maxHeight: maxHeight,
|
|
66
|
+
} }, items.map(function (item, index) { return (react_1.default.createElement("div", { key: index, className: "drop-item hoverable", onClick: function () {
|
|
67
|
+
var _a;
|
|
68
|
+
if (!closableOnlyOutside) {
|
|
69
|
+
(_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
70
|
+
if (!openOnHover)
|
|
71
|
+
setOpen(false);
|
|
72
|
+
}
|
|
73
|
+
} }, item.label)); }))));
|
|
74
74
|
};
|
|
75
75
|
exports.default = Dropdown;
|
package/ui/drop/Dropdown.tsx
CHANGED
|
@@ -47,7 +47,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
47
47
|
const [open, setOpen] = useState(false);
|
|
48
48
|
|
|
49
49
|
const containerClass = `${direction} ${position} ${className}`.trim();
|
|
50
|
-
const menuClass = `drop-menu${hoverable ? ' item-hoverable' : ''}`;
|
|
50
|
+
const menuClass = `drop-menu ${hoverable ? ' item-hoverable' : ''}`;
|
|
51
51
|
|
|
52
52
|
useEffect(() => {
|
|
53
53
|
if (openOnHover) return;
|
|
@@ -78,35 +78,37 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
78
78
|
>
|
|
79
79
|
{button}
|
|
80
80
|
</div>
|
|
81
|
-
|
|
81
|
+
{
|
|
82
|
+
showMenu &&
|
|
83
|
+
|
|
82
84
|
<div
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
85
|
+
className={menuClass}
|
|
86
|
+
style={{
|
|
87
|
+
width,
|
|
88
|
+
minWidth,
|
|
89
|
+
maxWidth,
|
|
90
|
+
height,
|
|
91
|
+
minHeight,
|
|
92
|
+
maxHeight,
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{items.map((item, index) => (
|
|
96
|
+
<div
|
|
97
|
+
key={index}
|
|
98
|
+
className="drop-item hoverable"
|
|
99
|
+
onClick={() => {
|
|
100
|
+
if(!closableOnlyOutside){
|
|
101
|
+
item.onClick?.();
|
|
102
|
+
if (!openOnHover) setOpen(false);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
{item.label}
|
|
108
|
+
</div>
|
|
109
|
+
))}
|
|
110
|
+
</div>
|
|
111
|
+
}
|
|
110
112
|
</div>
|
|
111
113
|
);
|
|
112
114
|
};
|