@korsolutions/ui 0.0.21 → 0.0.22
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/components/index.d.mts +19 -2
- package/dist/components/index.mjs +139 -3
- package/dist/{index-pCM7YTs1.d.mts → index-vgnXBa4Z.d.mts} +97 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/{primitives-DNeYBN-3.mjs → primitives-ApsPS0vU.mjs} +333 -14
- package/dist/{toast-manager-BfoJ-_dB.mjs → toast-manager-Cdhl1ep0.mjs} +1 -1
- package/package.json +1 -1
- package/src/components/calendar/calendar.tsx +31 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/variants/default.tsx +127 -0
- package/src/components/calendar/variants/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/primitives/calendar/calendar-day.tsx +64 -0
- package/src/primitives/calendar/calendar-header.tsx +21 -0
- package/src/primitives/calendar/calendar-nav-button.tsx +60 -0
- package/src/primitives/calendar/calendar-root.tsx +41 -0
- package/src/primitives/calendar/calendar-title.tsx +23 -0
- package/src/primitives/calendar/calendar-week-labels.tsx +45 -0
- package/src/primitives/calendar/calendar-weeks.tsx +47 -0
- package/src/primitives/calendar/context.ts +23 -0
- package/src/primitives/calendar/index.ts +26 -0
- package/src/primitives/calendar/types.ts +39 -0
- package/src/primitives/index.ts +1 -0
- package/src/utils/date-utils.ts +113 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as DEFAULT_POSITION, r as useRelativePosition, t as DEFAULT_LAYOUT } from "./use-relative-position-BTKEyT1F.mjs";
|
|
2
|
-
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
+
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
|
|
4
4
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
5
|
|
|
@@ -123,14 +123,14 @@ const FieldPrimitive = {
|
|
|
123
123
|
|
|
124
124
|
//#endregion
|
|
125
125
|
//#region src/primitives/input/input.tsx
|
|
126
|
-
const calculateState$
|
|
126
|
+
const calculateState$7 = (props, isFocused) => {
|
|
127
127
|
if (props.isDisabled) return "disabled";
|
|
128
128
|
if (isFocused) return "focused";
|
|
129
129
|
return "default";
|
|
130
130
|
};
|
|
131
131
|
function InputPrimitive(props) {
|
|
132
132
|
const [isFocused, setIsFocused] = useState(false);
|
|
133
|
-
const state = calculateState$
|
|
133
|
+
const state = calculateState$7(props, isFocused);
|
|
134
134
|
const composedStyles = [
|
|
135
135
|
props.styles?.default?.style,
|
|
136
136
|
props.styles?.[state]?.style,
|
|
@@ -169,7 +169,7 @@ const useButtonPrimitive = () => {
|
|
|
169
169
|
|
|
170
170
|
//#endregion
|
|
171
171
|
//#region src/primitives/button/button-root.tsx
|
|
172
|
-
const calculateState$
|
|
172
|
+
const calculateState$6 = (props, isHovered) => {
|
|
173
173
|
if (props.isDisabled) return "disabled";
|
|
174
174
|
if (props.isLoading) return "loading";
|
|
175
175
|
if (isHovered) return "hovered";
|
|
@@ -177,7 +177,7 @@ const calculateState$4 = (props, isHovered) => {
|
|
|
177
177
|
};
|
|
178
178
|
function ButtonRoot(props) {
|
|
179
179
|
const [isHovered, setIsHovered] = useState(false);
|
|
180
|
-
const state = calculateState$
|
|
180
|
+
const state = calculateState$6(props, isHovered);
|
|
181
181
|
const calculatedStyle = [
|
|
182
182
|
props.styles?.root?.default,
|
|
183
183
|
props.styles?.root?.[state],
|
|
@@ -247,7 +247,7 @@ const useSelect = () => {
|
|
|
247
247
|
|
|
248
248
|
//#endregion
|
|
249
249
|
//#region src/primitives/select/select-root.tsx
|
|
250
|
-
const calculateState$
|
|
250
|
+
const calculateState$5 = (props) => {
|
|
251
251
|
if (props.isDisabled) return "disabled";
|
|
252
252
|
return "default";
|
|
253
253
|
};
|
|
@@ -255,7 +255,7 @@ function SelectRoot(props) {
|
|
|
255
255
|
const [isOpen, setIsOpen] = useState(false);
|
|
256
256
|
const [triggerLayout, setTriggerLayout] = useState(null);
|
|
257
257
|
const [options, setOptions] = useState([]);
|
|
258
|
-
const state = calculateState$
|
|
258
|
+
const state = calculateState$5(props);
|
|
259
259
|
const composedStyles = calculateComposedStyles(props.styles, state, "root", props.style);
|
|
260
260
|
const Component = props.render ?? View;
|
|
261
261
|
return /* @__PURE__ */ jsx(SelectContext.Provider, {
|
|
@@ -371,7 +371,7 @@ function SelectContent(props) {
|
|
|
371
371
|
|
|
372
372
|
//#endregion
|
|
373
373
|
//#region src/primitives/select/select-option.tsx
|
|
374
|
-
const calculateState$
|
|
374
|
+
const calculateState$4 = (selectState, hovered, selected) => {
|
|
375
375
|
if (selectState === "disabled") return "disabled";
|
|
376
376
|
if (selected) return "selected";
|
|
377
377
|
if (hovered) return "hovered";
|
|
@@ -381,7 +381,7 @@ function SelectOption(props) {
|
|
|
381
381
|
const [isHovered, setIsHovered] = useState(false);
|
|
382
382
|
const select = useSelect();
|
|
383
383
|
const isSelected = select.value === props.value;
|
|
384
|
-
const optionState = calculateState$
|
|
384
|
+
const optionState = calculateState$4(select.state, isHovered, isSelected);
|
|
385
385
|
const composedStyles = calculateComposedStyles(select.styles, optionState, "option", props.style);
|
|
386
386
|
useEffect(() => {
|
|
387
387
|
select.setOptions((prev) => {
|
|
@@ -707,14 +707,14 @@ const BadgePrimitive = {
|
|
|
707
707
|
|
|
708
708
|
//#endregion
|
|
709
709
|
//#region src/primitives/textarea/textarea.tsx
|
|
710
|
-
const calculateState$
|
|
710
|
+
const calculateState$3 = (props, isFocused) => {
|
|
711
711
|
if (props.isDisabled) return "disabled";
|
|
712
712
|
if (isFocused) return "focused";
|
|
713
713
|
return "default";
|
|
714
714
|
};
|
|
715
715
|
function TextareaPrimitive(props) {
|
|
716
716
|
const [isFocused, setIsFocused] = useState(false);
|
|
717
|
-
const state = calculateState$
|
|
717
|
+
const state = calculateState$3(props, isFocused);
|
|
718
718
|
const composedStyles = [
|
|
719
719
|
props.styles?.default?.style,
|
|
720
720
|
props.styles?.[state]?.style,
|
|
@@ -832,14 +832,14 @@ function DropdownMenuContent(props) {
|
|
|
832
832
|
|
|
833
833
|
//#endregion
|
|
834
834
|
//#region src/primitives/dropdown-menu/dropdown-menu-button.tsx
|
|
835
|
-
const calculateState = (isHovered) => {
|
|
835
|
+
const calculateState$2 = (isHovered) => {
|
|
836
836
|
if (isHovered) return "hovered";
|
|
837
837
|
return "default";
|
|
838
838
|
};
|
|
839
839
|
function DropdownMenuButton(props) {
|
|
840
840
|
const menu = useDropdownMenu();
|
|
841
841
|
const [isHovered, setIsHovered] = useState(false);
|
|
842
|
-
const state = calculateState(isHovered);
|
|
842
|
+
const state = calculateState$2(isHovered);
|
|
843
843
|
const composedStyle = [
|
|
844
844
|
menu.styles?.button?.default,
|
|
845
845
|
menu.styles?.button?.[state],
|
|
@@ -1061,4 +1061,323 @@ const PopoverPrimitive = {
|
|
|
1061
1061
|
};
|
|
1062
1062
|
|
|
1063
1063
|
//#endregion
|
|
1064
|
-
|
|
1064
|
+
//#region src/primitives/calendar/context.ts
|
|
1065
|
+
const CalendarContext = React.createContext(void 0);
|
|
1066
|
+
const useCalendarContext = () => {
|
|
1067
|
+
const context = React.useContext(CalendarContext);
|
|
1068
|
+
if (!context) throw new Error("Calendar components must be used within CalendarRoot");
|
|
1069
|
+
return context;
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
//#endregion
|
|
1073
|
+
//#region src/primitives/calendar/calendar-root.tsx
|
|
1074
|
+
function CalendarRoot(props) {
|
|
1075
|
+
const { children, value, onChange, defaultMonth = /* @__PURE__ */ new Date(), minDate, maxDate, style, styles, ...viewProps } = props;
|
|
1076
|
+
const [currentMonth, setCurrentMonth] = useState(defaultMonth);
|
|
1077
|
+
const containerStyle = [styles?.root, style];
|
|
1078
|
+
return /* @__PURE__ */ jsx(CalendarContext.Provider, {
|
|
1079
|
+
value: {
|
|
1080
|
+
value,
|
|
1081
|
+
onChange,
|
|
1082
|
+
currentMonth,
|
|
1083
|
+
setCurrentMonth,
|
|
1084
|
+
styles,
|
|
1085
|
+
minDate,
|
|
1086
|
+
maxDate
|
|
1087
|
+
},
|
|
1088
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
1089
|
+
...viewProps,
|
|
1090
|
+
style: containerStyle,
|
|
1091
|
+
children
|
|
1092
|
+
})
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
//#endregion
|
|
1097
|
+
//#region src/primitives/calendar/calendar-header.tsx
|
|
1098
|
+
function CalendarHeader(props) {
|
|
1099
|
+
const { children, style, ...viewProps } = props;
|
|
1100
|
+
const { styles } = useCalendarContext();
|
|
1101
|
+
const headerStyle = [styles?.header, style];
|
|
1102
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1103
|
+
...viewProps,
|
|
1104
|
+
style: headerStyle,
|
|
1105
|
+
children
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region src/utils/date-utils.ts
|
|
1111
|
+
const formatDate = (date, format) => {
|
|
1112
|
+
const months = [
|
|
1113
|
+
"January",
|
|
1114
|
+
"February",
|
|
1115
|
+
"March",
|
|
1116
|
+
"April",
|
|
1117
|
+
"May",
|
|
1118
|
+
"June",
|
|
1119
|
+
"July",
|
|
1120
|
+
"August",
|
|
1121
|
+
"September",
|
|
1122
|
+
"October",
|
|
1123
|
+
"November",
|
|
1124
|
+
"December"
|
|
1125
|
+
];
|
|
1126
|
+
const day = date.getDate();
|
|
1127
|
+
const month = months[date.getMonth()];
|
|
1128
|
+
const year = date.getFullYear();
|
|
1129
|
+
if (format === "MMMM yyyy") return `${month} ${year}`;
|
|
1130
|
+
if (format === "d") return day.toString();
|
|
1131
|
+
return date.toLocaleDateString();
|
|
1132
|
+
};
|
|
1133
|
+
const isDateSameDay = (date1, date2) => {
|
|
1134
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
|
|
1135
|
+
};
|
|
1136
|
+
const isDateToday = (date) => {
|
|
1137
|
+
return isDateSameDay(date, /* @__PURE__ */ new Date());
|
|
1138
|
+
};
|
|
1139
|
+
const isDateBefore = (date1, date2) => {
|
|
1140
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
1141
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
1142
|
+
return d1.getTime() < d2.getTime();
|
|
1143
|
+
};
|
|
1144
|
+
const isDateAfter = (date1, date2) => {
|
|
1145
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
1146
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
1147
|
+
return d1.getTime() > d2.getTime();
|
|
1148
|
+
};
|
|
1149
|
+
const addMonths = (date, months) => {
|
|
1150
|
+
const newDate = new Date(date);
|
|
1151
|
+
newDate.setMonth(newDate.getMonth() + months);
|
|
1152
|
+
return newDate;
|
|
1153
|
+
};
|
|
1154
|
+
const subMonths = (date, months) => {
|
|
1155
|
+
return addMonths(date, -months);
|
|
1156
|
+
};
|
|
1157
|
+
const startOfMonth = (date) => {
|
|
1158
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
1159
|
+
};
|
|
1160
|
+
const endOfMonth = (date) => {
|
|
1161
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
1162
|
+
};
|
|
1163
|
+
const getDaysInMonth = (date) => {
|
|
1164
|
+
return endOfMonth(date).getDate();
|
|
1165
|
+
};
|
|
1166
|
+
const getFirstDayOfMonth = (date) => {
|
|
1167
|
+
return startOfMonth(date).getDay();
|
|
1168
|
+
};
|
|
1169
|
+
const isSameMonth = (date1, date2) => {
|
|
1170
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth();
|
|
1171
|
+
};
|
|
1172
|
+
const getWeekDays = (month, year, week) => {
|
|
1173
|
+
const days = [];
|
|
1174
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
1175
|
+
const daysInMonth = getDaysInMonth(new Date(year, month));
|
|
1176
|
+
const startDay = week * 7 - (firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1);
|
|
1177
|
+
for (let i = 0; i < 7; i++) {
|
|
1178
|
+
const day = startDay + i;
|
|
1179
|
+
let date;
|
|
1180
|
+
if (day < 1) {
|
|
1181
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
1182
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
1183
|
+
const daysInPrevMonth = getDaysInMonth(new Date(prevYear, prevMonth));
|
|
1184
|
+
date = new Date(prevYear, prevMonth, daysInPrevMonth + day);
|
|
1185
|
+
} else if (day > daysInMonth) {
|
|
1186
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
1187
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
1188
|
+
date = new Date(nextYear, nextMonth, day - daysInMonth);
|
|
1189
|
+
} else date = new Date(year, month, day);
|
|
1190
|
+
days.push(date);
|
|
1191
|
+
}
|
|
1192
|
+
return days;
|
|
1193
|
+
};
|
|
1194
|
+
const getWeeksInMonth = (date) => {
|
|
1195
|
+
const firstDayOfMonth = getFirstDayOfMonth(date);
|
|
1196
|
+
const daysInMonth = getDaysInMonth(date);
|
|
1197
|
+
return Math.ceil((firstDayOfMonth + daysInMonth) / 7);
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
//#endregion
|
|
1201
|
+
//#region src/primitives/calendar/calendar-title.tsx
|
|
1202
|
+
function CalendarTitle(props) {
|
|
1203
|
+
const { children, style, formatStr = "MMMM yyyy", ...textProps } = props;
|
|
1204
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1205
|
+
const titleStyle = [styles?.headerTitle, style];
|
|
1206
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1207
|
+
...textProps,
|
|
1208
|
+
style: titleStyle,
|
|
1209
|
+
children: children ?? formatDate(currentMonth, formatStr)
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
//#endregion
|
|
1214
|
+
//#region src/primitives/calendar/calendar-nav-button.tsx
|
|
1215
|
+
const calculateState$1 = (isDisabled, isHovered) => {
|
|
1216
|
+
if (isDisabled) return "disabled";
|
|
1217
|
+
if (isHovered) return "hovered";
|
|
1218
|
+
return "default";
|
|
1219
|
+
};
|
|
1220
|
+
function CalendarNavButton(props) {
|
|
1221
|
+
const { children = props.direction === "prev" ? "‹" : "›", direction, style, textStyle, ...pressableProps } = props;
|
|
1222
|
+
const { currentMonth, setCurrentMonth, minDate, maxDate, styles } = useCalendarContext();
|
|
1223
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
1224
|
+
const isDisabled = React.useMemo(() => {
|
|
1225
|
+
if (direction === "prev" && minDate) return subMonths(currentMonth, 1) < minDate;
|
|
1226
|
+
if (direction === "next" && maxDate) return addMonths(currentMonth, 1) > maxDate;
|
|
1227
|
+
return false;
|
|
1228
|
+
}, [
|
|
1229
|
+
direction,
|
|
1230
|
+
currentMonth,
|
|
1231
|
+
minDate,
|
|
1232
|
+
maxDate
|
|
1233
|
+
]);
|
|
1234
|
+
const state = calculateState$1(isDisabled, isHovered);
|
|
1235
|
+
const handlePress = () => {
|
|
1236
|
+
if (isDisabled) return;
|
|
1237
|
+
setCurrentMonth(direction === "prev" ? subMonths(currentMonth, 1) : addMonths(currentMonth, 1));
|
|
1238
|
+
};
|
|
1239
|
+
const buttonStyle = [
|
|
1240
|
+
styles?.navButton?.default,
|
|
1241
|
+
styles?.navButton?.[state],
|
|
1242
|
+
style
|
|
1243
|
+
];
|
|
1244
|
+
const textStyleCombined = [
|
|
1245
|
+
styles?.navButtonText?.default,
|
|
1246
|
+
styles?.navButtonText?.[state],
|
|
1247
|
+
textStyle
|
|
1248
|
+
];
|
|
1249
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
1250
|
+
...pressableProps,
|
|
1251
|
+
onPress: handlePress,
|
|
1252
|
+
onHoverIn: () => setIsHovered(true),
|
|
1253
|
+
onHoverOut: () => setIsHovered(false),
|
|
1254
|
+
disabled: isDisabled,
|
|
1255
|
+
style: buttonStyle,
|
|
1256
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1257
|
+
style: textStyleCombined,
|
|
1258
|
+
children
|
|
1259
|
+
})
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
//#endregion
|
|
1264
|
+
//#region src/primitives/calendar/calendar-week-labels.tsx
|
|
1265
|
+
function CalendarWeekLabel(props) {
|
|
1266
|
+
const { styles } = useCalendarContext();
|
|
1267
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1268
|
+
numberOfLines: 1,
|
|
1269
|
+
style: [styles?.weekLabel, props.style],
|
|
1270
|
+
children: props.children
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
const DEFAULT_WEEK_DAYS = [
|
|
1274
|
+
"Su",
|
|
1275
|
+
"Mo",
|
|
1276
|
+
"Tu",
|
|
1277
|
+
"We",
|
|
1278
|
+
"Th",
|
|
1279
|
+
"Fr",
|
|
1280
|
+
"Sa"
|
|
1281
|
+
];
|
|
1282
|
+
function CalendarWeekLabels(props) {
|
|
1283
|
+
const { weekDays = DEFAULT_WEEK_DAYS, style } = props;
|
|
1284
|
+
const { styles } = useCalendarContext();
|
|
1285
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1286
|
+
style: [styles?.weekLabels, style],
|
|
1287
|
+
children: weekDays.map((day, index) => /* @__PURE__ */ jsx(CalendarWeekLabel, {
|
|
1288
|
+
style: styles?.weekLabel,
|
|
1289
|
+
children: day
|
|
1290
|
+
}, index))
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
//#endregion
|
|
1295
|
+
//#region src/primitives/calendar/calendar-day.tsx
|
|
1296
|
+
const calculateState = (date, selected, isCurrentMonth, isDisabled, isHovered) => {
|
|
1297
|
+
if (isDisabled) return "disabled";
|
|
1298
|
+
if (selected && isDateSameDay(date, selected)) return "selected";
|
|
1299
|
+
if (isDateToday(date)) return "today";
|
|
1300
|
+
if (isHovered) return "hovered";
|
|
1301
|
+
if (!isCurrentMonth) return "deprioritized";
|
|
1302
|
+
return "default";
|
|
1303
|
+
};
|
|
1304
|
+
function CalendarDay(props) {
|
|
1305
|
+
const calendar = useCalendarContext();
|
|
1306
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
1307
|
+
const isCurrentMonth = isSameMonth(props.date, calendar.currentMonth);
|
|
1308
|
+
const isDisabled = useMemo(() => {
|
|
1309
|
+
if (calendar.minDate && isDateBefore(props.date, calendar.minDate)) return true;
|
|
1310
|
+
if (calendar.maxDate && isDateAfter(props.date, calendar.maxDate)) return true;
|
|
1311
|
+
return false;
|
|
1312
|
+
}, [
|
|
1313
|
+
props.date,
|
|
1314
|
+
calendar.minDate,
|
|
1315
|
+
calendar.maxDate
|
|
1316
|
+
]);
|
|
1317
|
+
const state = calculateState(props.date, calendar.value, isCurrentMonth, isDisabled, isHovered);
|
|
1318
|
+
const handlePress = () => {
|
|
1319
|
+
console.log("Day pressed:", isDisabled, calendar.onChange);
|
|
1320
|
+
if (isDisabled || !calendar.onChange) return;
|
|
1321
|
+
calendar.onChange(props.date);
|
|
1322
|
+
};
|
|
1323
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
1324
|
+
onPress: handlePress,
|
|
1325
|
+
onHoverIn: () => setIsHovered(true),
|
|
1326
|
+
onHoverOut: () => setIsHovered(false),
|
|
1327
|
+
disabled: isDisabled,
|
|
1328
|
+
style: [
|
|
1329
|
+
calendar.styles?.dayButton?.default,
|
|
1330
|
+
calendar.styles?.dayButton?.[state],
|
|
1331
|
+
props.style
|
|
1332
|
+
],
|
|
1333
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1334
|
+
style: [
|
|
1335
|
+
calendar.styles?.dayText?.default,
|
|
1336
|
+
calendar.styles?.dayText?.[state],
|
|
1337
|
+
props.textStyle
|
|
1338
|
+
],
|
|
1339
|
+
children: formatDate(props.date, "d")
|
|
1340
|
+
})
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
//#endregion
|
|
1345
|
+
//#region src/primitives/calendar/calendar-weeks.tsx
|
|
1346
|
+
function CalendarWeek(props) {
|
|
1347
|
+
const { style, ...viewProps } = props;
|
|
1348
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1349
|
+
const days = getWeekDays(currentMonth.getMonth(), currentMonth.getFullYear(), props.index);
|
|
1350
|
+
const composedStyle = [styles?.week, style];
|
|
1351
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1352
|
+
...viewProps,
|
|
1353
|
+
style: composedStyle,
|
|
1354
|
+
children: days.map((day, index) => {
|
|
1355
|
+
return /* @__PURE__ */ jsx(CalendarDay, { date: day }, index);
|
|
1356
|
+
})
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
function CalendarWeeks(props) {
|
|
1360
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1361
|
+
const weeks = getWeeksInMonth(currentMonth);
|
|
1362
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1363
|
+
style: [styles?.weeks, props.style],
|
|
1364
|
+
children: Array.from({ length: weeks }).map((_, index) => {
|
|
1365
|
+
return /* @__PURE__ */ jsx(CalendarWeek, { index }, index);
|
|
1366
|
+
})
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
//#endregion
|
|
1371
|
+
//#region src/primitives/calendar/index.ts
|
|
1372
|
+
const CalendarPrimitive = {
|
|
1373
|
+
Root: CalendarRoot,
|
|
1374
|
+
Header: CalendarHeader,
|
|
1375
|
+
Title: CalendarTitle,
|
|
1376
|
+
NavButton: CalendarNavButton,
|
|
1377
|
+
CalendarWeekLabels,
|
|
1378
|
+
Weeks: CalendarWeeks,
|
|
1379
|
+
Day: CalendarDay
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
//#endregion
|
|
1383
|
+
export { TextareaPrimitive as a, AvatarPrimitive as c, SelectPrimitive as d, ButtonPrimitive as f, PortalHost as h, DropdownMenuPrimitive as i, EmptyPrimitive as l, FieldPrimitive as m, PopoverPrimitive as n, BadgePrimitive as o, InputPrimitive as p, usePopover as r, ToastPrimitive as s, CalendarPrimitive as t, CardPrimitive as u };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as ToastPrimitive } from "./primitives-ApsPS0vU.mjs";
|
|
2
2
|
import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { StyleSheet, View, useColorScheme } from "react-native";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CalendarPrimitive } from "@/primitives";
|
|
3
|
+
import { CalendarVariants } from "./variants";
|
|
4
|
+
|
|
5
|
+
export interface CalendarProps {
|
|
6
|
+
value?: Date;
|
|
7
|
+
onChange?: (date: Date | undefined) => void;
|
|
8
|
+
defaultMonth?: Date;
|
|
9
|
+
minDate?: Date;
|
|
10
|
+
maxDate?: Date;
|
|
11
|
+
variant?: keyof typeof CalendarVariants;
|
|
12
|
+
weekDays?: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Calendar(props: CalendarProps) {
|
|
16
|
+
const { variant = "default", weekDays, ...rootProps } = props;
|
|
17
|
+
const useVariantStyles = CalendarVariants[variant];
|
|
18
|
+
const variantStyles = useVariantStyles();
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<CalendarPrimitive.Root {...rootProps} styles={variantStyles}>
|
|
22
|
+
<CalendarPrimitive.Header>
|
|
23
|
+
<CalendarPrimitive.NavButton direction="prev" />
|
|
24
|
+
<CalendarPrimitive.Title />
|
|
25
|
+
<CalendarPrimitive.NavButton direction="next" />
|
|
26
|
+
</CalendarPrimitive.Header>
|
|
27
|
+
<CalendarPrimitive.CalendarWeekLabels weekDays={weekDays} />
|
|
28
|
+
<CalendarPrimitive.Weeks />
|
|
29
|
+
</CalendarPrimitive.Root>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./calendar";
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { CalendarStyles } from "@/primitives";
|
|
2
|
+
import { useThemedStyles } from "@/utils/use-themed-styles";
|
|
3
|
+
|
|
4
|
+
export const useCalendarVariantDefault = (): CalendarStyles => {
|
|
5
|
+
return useThemedStyles(
|
|
6
|
+
({ colors, radius, fontFamily, fontSize }): CalendarStyles => ({
|
|
7
|
+
root: {
|
|
8
|
+
padding: 16,
|
|
9
|
+
backgroundColor: colors.background,
|
|
10
|
+
borderRadius: radius,
|
|
11
|
+
borderWidth: 1,
|
|
12
|
+
borderColor: colors.border,
|
|
13
|
+
width: 324,
|
|
14
|
+
},
|
|
15
|
+
header: {
|
|
16
|
+
flexDirection: "row",
|
|
17
|
+
justifyContent: "space-between",
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
marginBottom: 16,
|
|
20
|
+
paddingHorizontal: 8,
|
|
21
|
+
},
|
|
22
|
+
headerTitle: {
|
|
23
|
+
fontSize: fontSize * 1.125,
|
|
24
|
+
fontWeight: "600",
|
|
25
|
+
fontFamily,
|
|
26
|
+
color: colors.foreground,
|
|
27
|
+
},
|
|
28
|
+
navButton: {
|
|
29
|
+
default: {
|
|
30
|
+
width: 32,
|
|
31
|
+
height: 32,
|
|
32
|
+
borderRadius: radius * 0.5,
|
|
33
|
+
alignItems: "center",
|
|
34
|
+
justifyContent: "center",
|
|
35
|
+
backgroundColor: "transparent",
|
|
36
|
+
},
|
|
37
|
+
disabled: {
|
|
38
|
+
opacity: 0.3,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
navButtonText: {
|
|
42
|
+
default: {
|
|
43
|
+
fontSize: fontSize * 1.5,
|
|
44
|
+
color: colors.foreground,
|
|
45
|
+
fontWeight: "500",
|
|
46
|
+
},
|
|
47
|
+
disabled: {
|
|
48
|
+
color: colors.mutedForeground,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
weekLabels: {
|
|
52
|
+
flexDirection: "row",
|
|
53
|
+
justifyContent: "space-between",
|
|
54
|
+
marginBottom: 8,
|
|
55
|
+
paddingVertical: 8,
|
|
56
|
+
gap: 2,
|
|
57
|
+
},
|
|
58
|
+
weekLabel: {
|
|
59
|
+
fontSize: fontSize * 0.875,
|
|
60
|
+
fontWeight: "500",
|
|
61
|
+
fontFamily,
|
|
62
|
+
color: colors.mutedForeground,
|
|
63
|
+
width: 40,
|
|
64
|
+
textAlign: "center",
|
|
65
|
+
},
|
|
66
|
+
weeks: {
|
|
67
|
+
flexDirection: "column",
|
|
68
|
+
gap: 2,
|
|
69
|
+
},
|
|
70
|
+
week: {
|
|
71
|
+
flexDirection: "row",
|
|
72
|
+
justifyContent: "space-between",
|
|
73
|
+
gap: 2,
|
|
74
|
+
},
|
|
75
|
+
dayButton: {
|
|
76
|
+
default: {
|
|
77
|
+
width: 40,
|
|
78
|
+
height: 40,
|
|
79
|
+
borderRadius: radius * 0.5,
|
|
80
|
+
alignItems: "center",
|
|
81
|
+
justifyContent: "center",
|
|
82
|
+
backgroundColor: "transparent",
|
|
83
|
+
},
|
|
84
|
+
selected: {
|
|
85
|
+
backgroundColor: colors.primary,
|
|
86
|
+
},
|
|
87
|
+
today: {
|
|
88
|
+
borderWidth: 1,
|
|
89
|
+
borderColor: colors.primary,
|
|
90
|
+
},
|
|
91
|
+
disabled: {
|
|
92
|
+
opacity: 0.3,
|
|
93
|
+
},
|
|
94
|
+
deprioritized: {
|
|
95
|
+
backgroundColor: "transparent",
|
|
96
|
+
},
|
|
97
|
+
hovered: {
|
|
98
|
+
backgroundColor: colors.muted,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
dayText: {
|
|
102
|
+
default: {
|
|
103
|
+
fontSize,
|
|
104
|
+
fontFamily,
|
|
105
|
+
color: colors.foreground,
|
|
106
|
+
fontWeight: "400",
|
|
107
|
+
pointerEvents: "none",
|
|
108
|
+
},
|
|
109
|
+
selected: {
|
|
110
|
+
color: colors.primaryForeground,
|
|
111
|
+
fontWeight: "600",
|
|
112
|
+
},
|
|
113
|
+
today: {
|
|
114
|
+
color: colors.primary,
|
|
115
|
+
fontWeight: "600",
|
|
116
|
+
},
|
|
117
|
+
disabled: {
|
|
118
|
+
color: colors.mutedForeground,
|
|
119
|
+
},
|
|
120
|
+
deprioritized: {
|
|
121
|
+
color: colors.mutedForeground,
|
|
122
|
+
opacity: 0.5,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { Text, StyleProp, TextStyle, ViewStyle, Pressable } from "react-native";
|
|
3
|
+
import { formatDate, isDateSameDay, isDateToday, isDateBefore, isDateAfter, isSameMonth } from "@/utils/date-utils";
|
|
4
|
+
import { useCalendarContext } from "./context";
|
|
5
|
+
import { CalendarDayState } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface CalendarDayProps {
|
|
8
|
+
date: Date;
|
|
9
|
+
onPress?: () => void;
|
|
10
|
+
|
|
11
|
+
style?: StyleProp<ViewStyle>;
|
|
12
|
+
textStyle?: StyleProp<TextStyle>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const calculateState = (
|
|
16
|
+
date: Date,
|
|
17
|
+
selected: Date | undefined,
|
|
18
|
+
isCurrentMonth: boolean,
|
|
19
|
+
isDisabled: boolean,
|
|
20
|
+
isHovered: boolean
|
|
21
|
+
): CalendarDayState => {
|
|
22
|
+
if (isDisabled) return "disabled";
|
|
23
|
+
if (selected && isDateSameDay(date, selected)) return "selected";
|
|
24
|
+
if (isDateToday(date)) return "today";
|
|
25
|
+
if (isHovered) return "hovered";
|
|
26
|
+
if (!isCurrentMonth) return "deprioritized";
|
|
27
|
+
return "default";
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function CalendarDay(props: CalendarDayProps) {
|
|
31
|
+
const calendar = useCalendarContext();
|
|
32
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
33
|
+
|
|
34
|
+
const isCurrentMonth = isSameMonth(props.date, calendar.currentMonth);
|
|
35
|
+
|
|
36
|
+
const isDisabled = useMemo(() => {
|
|
37
|
+
if (calendar.minDate && isDateBefore(props.date, calendar.minDate)) return true;
|
|
38
|
+
if (calendar.maxDate && isDateAfter(props.date, calendar.maxDate)) return true;
|
|
39
|
+
return false;
|
|
40
|
+
}, [props.date, calendar.minDate, calendar.maxDate]);
|
|
41
|
+
|
|
42
|
+
const state = calculateState(props.date, calendar.value, isCurrentMonth, isDisabled, isHovered);
|
|
43
|
+
|
|
44
|
+
const handlePress = () => {
|
|
45
|
+
console.log("Day pressed:", isDisabled, calendar.onChange);
|
|
46
|
+
if (isDisabled || !calendar.onChange) return;
|
|
47
|
+
calendar.onChange(props.date);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const composedStyle = [calendar.styles?.dayButton?.default, calendar.styles?.dayButton?.[state], props.style];
|
|
51
|
+
const composedTextStyle = [calendar.styles?.dayText?.default, calendar.styles?.dayText?.[state], props.textStyle];
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Pressable
|
|
55
|
+
onPress={handlePress}
|
|
56
|
+
onHoverIn={() => setIsHovered(true)}
|
|
57
|
+
onHoverOut={() => setIsHovered(false)}
|
|
58
|
+
disabled={isDisabled}
|
|
59
|
+
style={composedStyle}
|
|
60
|
+
>
|
|
61
|
+
<Text style={composedTextStyle}>{formatDate(props.date, "d")}</Text>
|
|
62
|
+
</Pressable>
|
|
63
|
+
);
|
|
64
|
+
}
|