@lazerlen/legend-calendar 1.2.0 → 1.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazerlen/legend-calendar",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "private": false,
5
5
  "description": "A better calendar for React Native.",
6
6
  "repository": {
@@ -304,6 +304,12 @@ interface CalendarItemDayContainerTheme {
304
304
  /** An absolute positioned filler to join the active days together in a single
305
305
  * complete range. */
306
306
  activeDayFiller?: ViewStyle | ((params: CalendarDayMetadata) => ViewStyle);
307
+ /** An absolutely-positioned background view rendered inside the spacer,
308
+ * behind the day button. Useful for rendering a range band that doesn't
309
+ * extend behind the circular edge days. */
310
+ activeDayRangeBackground?:
311
+ | ViewStyle
312
+ | ((params: CalendarDayMetadata) => ViewStyle | undefined);
307
313
  }
308
314
 
309
315
  export interface CalendarItemDayContainerProps {
@@ -361,8 +367,24 @@ export const CalendarItemDayContainer = memo(function CalendarItemDayContainer({
361
367
  : theme?.activeDayFiller),
362
368
  };
363
369
 
370
+ const rangeBackgroundTheme =
371
+ typeof theme?.activeDayRangeBackground === "function" && metadata
372
+ ? theme.activeDayRangeBackground(metadata)
373
+ : theme?.activeDayRangeBackground;
374
+ const rangeBackground: ViewStyle | null = rangeBackgroundTheme
375
+ ? {
376
+ position: "absolute",
377
+ top: 0,
378
+ bottom: 0,
379
+ left: 0,
380
+ right: 0,
381
+ ...rangeBackgroundTheme,
382
+ }
383
+ : null;
384
+
364
385
  return (
365
386
  <View style={spacerStyles}>
387
+ {rangeBackground ? <View style={rangeBackground} /> : null}
366
388
  {activeDayFiller ? <View style={activeDayFiller} /> : null}
367
389
  {children}
368
390
  </View>
@@ -249,6 +249,57 @@ export const DatePicker = () => {
249
249
  );
250
250
  };
251
251
 
252
+ export function AutoScrollToActiveRange() {
253
+ const futureDate = addMonths(today, 6);
254
+ const futureDateEnd = addMonths(futureDate, 1);
255
+
256
+ return (
257
+ <VStack grow spacing={20}>
258
+ <Text>
259
+ This calendar has a date range 6 months in the future. It automatically
260
+ scrolls to show the active range on mount.
261
+ </Text>
262
+ <View style={{ flex: 1, width: "100%" }}>
263
+ <Calendar.List
264
+ calendarActiveDateRanges={[
265
+ {
266
+ startId: toDateId(futureDate),
267
+ endId: toDateId(futureDateEnd),
268
+ },
269
+ ]}
270
+ onCalendarDayPress={loggingHandler("onCalendarDayPress")}
271
+ />
272
+ </View>
273
+ </VStack>
274
+ );
275
+ }
276
+
277
+ export function AutoScrollDisabled() {
278
+ const futureDate = addMonths(today, 6);
279
+ const futureDateEnd = addMonths(futureDate, 1);
280
+
281
+ return (
282
+ <VStack grow spacing={20}>
283
+ <Text>
284
+ This calendar has auto-scroll disabled. It opens at the current month
285
+ even though the active range is 6 months in the future.
286
+ </Text>
287
+ <View style={{ flex: 1, width: "100%" }}>
288
+ <Calendar.List
289
+ calendarActiveDateRanges={[
290
+ {
291
+ startId: toDateId(futureDate),
292
+ endId: toDateId(futureDateEnd),
293
+ },
294
+ ]}
295
+ calendarInitialScrollToActiveRange={false}
296
+ onCalendarDayPress={loggingHandler("onCalendarDayPress")}
297
+ />
298
+ </View>
299
+ </VStack>
300
+ );
301
+ }
302
+
252
303
  export const TwoCalendarListsMounted = () => {
253
304
  return (
254
305
  <VStack grow spacing={48}>
@@ -8,7 +8,12 @@ import { StyleSheet, View } from "react-native";
8
8
 
9
9
  import type { CalendarProps } from "@/components/Calendar";
10
10
  import { Calendar } from "@/components/Calendar";
11
- import { getWeekOfMonth, startOfMonth, toDateId } from "@/helpers/dates";
11
+ import {
12
+ fromDateId,
13
+ getWeekOfMonth,
14
+ startOfMonth,
15
+ toDateId,
16
+ } from "@/helpers/dates";
12
17
  import type { CalendarMonth } from "@/hooks/useCalendarList";
13
18
  import { getHeightForMonth, useCalendarList } from "@/hooks/useCalendarList";
14
19
  import { activeDateRangesStore } from "@/hooks/useOptimizedDayMetadata";
@@ -69,6 +74,20 @@ export interface CalendarListProps
69
74
  */
70
75
  calendarInitialMonthId?: string;
71
76
 
77
+ /**
78
+ * When enabled, automatically scrolls to the month containing the start date
79
+ * of the first active range on mount. Only applies when
80
+ * `calendarActiveDateRanges` has at least one range with a `startId`.
81
+ *
82
+ * Takes precedence over `calendarInitialMonthId` when enabled and a valid
83
+ * range exists.
84
+ *
85
+ * Uses `initialScrollIndex` internally, so scrolling only happens on mount.
86
+ *
87
+ * @defaultValue true
88
+ */
89
+ calendarInitialScrollToActiveRange?: boolean;
90
+
72
91
  /**
73
92
  * Overwrites the default `Calendar` component.
74
93
  *
@@ -113,6 +132,7 @@ export function CalendarList({
113
132
  const {
114
133
  // List-related props
115
134
  calendarInitialMonthId,
135
+ calendarInitialScrollToActiveRange = true,
116
136
  calendarPastScrollRangeInMonths = 12,
117
137
  calendarFutureScrollRangeInMonths = 12,
118
138
  calendarFirstDayOfWeek = "sunday",
@@ -198,6 +218,25 @@ export function CalendarList({
198
218
  calendarMinDateId,
199
219
  });
200
220
 
221
+ // Compute the scroll index based on active date range if enabled
222
+ let computedInitialScrollIndex = initialMonthIndex;
223
+ if (calendarInitialScrollToActiveRange && calendarActiveDateRanges) {
224
+ const firstRange = calendarActiveDateRanges[0];
225
+ if (firstRange?.startId) {
226
+ // Convert the startId to the first day of that month
227
+ const startDate = fromDateId(firstRange.startId);
228
+ const monthId = toDateId(startOfMonth(startDate));
229
+
230
+ // Find the index of this month in the monthList
231
+ const monthIndex = monthList.findIndex((month) => month.id === monthId);
232
+
233
+ // Use this index if found, otherwise fall back to initialMonthIndex
234
+ if (monthIndex !== -1) {
235
+ computedInitialScrollIndex = monthIndex;
236
+ }
237
+ }
238
+ }
239
+
201
240
  const monthListWithCalendarProps = monthList.map((month) => ({
202
241
  ...month,
203
242
  calendarProps,
@@ -320,7 +359,7 @@ export function CalendarList({
320
359
  drawDistance={560}
321
360
  estimatedItemSize={273}
322
361
  getFixedItemSize={getFixedItemSize}
323
- initialScrollIndex={initialMonthIndex}
362
+ initialScrollIndex={computedInitialScrollIndex}
324
363
  keyExtractor={keyExtractor}
325
364
  maintainVisibleContentPosition
326
365
  onEndReached={handleOnEndReached}