@oneluiz/dual-datepicker 3.6.0 → 3.9.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/core/calendar-grid/calendar-grid.cache.d.ts +39 -0
- package/core/calendar-grid/calendar-grid.factory.d.ts +26 -0
- package/core/calendar-grid/calendar-grid.types.d.ts +57 -0
- package/core/calendar-grid/index.d.ts +50 -0
- package/core/calendar-grid/range-highlighter.cache.d.ts +105 -0
- package/core/calendar-grid/range-highlighter.d.ts +85 -0
- package/core/calendar-grid/range-highlighter.types.d.ts +182 -0
- package/core/calendar-grid/virtual-weeks.logic.d.ts +116 -0
- package/core/calendar-grid/virtual-weeks.types.d.ts +71 -0
- package/core/index.d.ts +11 -0
- package/dual-datepicker.component.d.ts +78 -1
- package/esm2022/core/calendar-grid/calendar-grid.cache.mjs +92 -0
- package/esm2022/core/calendar-grid/calendar-grid.factory.mjs +97 -0
- package/esm2022/core/calendar-grid/calendar-grid.types.mjs +8 -0
- package/esm2022/core/calendar-grid/index.mjs +51 -0
- package/esm2022/core/calendar-grid/range-highlighter.cache.mjs +198 -0
- package/esm2022/core/calendar-grid/range-highlighter.mjs +185 -0
- package/esm2022/core/calendar-grid/range-highlighter.types.mjs +11 -0
- package/esm2022/core/calendar-grid/virtual-weeks.logic.mjs +149 -0
- package/esm2022/core/calendar-grid/virtual-weeks.types.mjs +11 -0
- package/esm2022/core/index.mjs +14 -1
- package/esm2022/dual-datepicker.component.mjs +177 -38
- package/fesm2022/oneluiz-dual-datepicker.mjs +965 -39
- package/fesm2022/oneluiz-dual-datepicker.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CalendarGridFactory } from './calendar-grid.factory';
|
|
2
|
+
import { CalendarGrid } from './calendar-grid.types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class CalendarGridCache {
|
|
5
|
+
private factory;
|
|
6
|
+
private cache;
|
|
7
|
+
private readonly maxSize;
|
|
8
|
+
constructor(factory: CalendarGridFactory);
|
|
9
|
+
/**
|
|
10
|
+
* Get or create a calendar grid
|
|
11
|
+
*
|
|
12
|
+
* @param monthDate - Any date within the target month
|
|
13
|
+
* @param weekStart - First day of week (0 = Sunday, 1 = Monday, etc.)
|
|
14
|
+
* @param locale - Locale identifier (optional)
|
|
15
|
+
* @returns CalendarGrid - cached or newly created
|
|
16
|
+
*/
|
|
17
|
+
get(monthDate: Date, weekStart?: number, locale?: string): CalendarGrid;
|
|
18
|
+
/**
|
|
19
|
+
* Build cache key from month parameters
|
|
20
|
+
*
|
|
21
|
+
* Format: "year-month-weekStart-locale"
|
|
22
|
+
* Example: "2026-1-0-en" (Feb 2026, Sunday start, English)
|
|
23
|
+
*/
|
|
24
|
+
private buildKey;
|
|
25
|
+
/**
|
|
26
|
+
* Clear entire cache (for testing or manual reset)
|
|
27
|
+
*/
|
|
28
|
+
clear(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get cache size (for debugging/testing)
|
|
31
|
+
*/
|
|
32
|
+
size(): number;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a specific month is cached
|
|
35
|
+
*/
|
|
36
|
+
has(monthDate: Date, weekStart?: number, locale?: string): boolean;
|
|
37
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CalendarGridCache, never>;
|
|
38
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<CalendarGridCache>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DateAdapter } from '../date-adapter';
|
|
2
|
+
import { CalendarGrid } from './calendar-grid.types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class CalendarGridFactory {
|
|
5
|
+
private adapter;
|
|
6
|
+
constructor(adapter: DateAdapter);
|
|
7
|
+
/**
|
|
8
|
+
* Create a calendar grid for a given month
|
|
9
|
+
*
|
|
10
|
+
* @param monthDate - Any date within the target month (will be normalized to start of month)
|
|
11
|
+
* @param weekStart - First day of week (0 = Sunday, 1 = Monday, etc.)
|
|
12
|
+
* @param locale - Locale identifier (optional, for future use)
|
|
13
|
+
* @returns CalendarGrid - 6 weeks x 7 days grid
|
|
14
|
+
*/
|
|
15
|
+
createGrid(monthDate: Date, weekStart?: number, locale?: string): CalendarGrid;
|
|
16
|
+
/**
|
|
17
|
+
* Calculate offset (number of padding days from previous month)
|
|
18
|
+
*
|
|
19
|
+
* @param firstDayOfWeek - Day of week for first day of month (0-6)
|
|
20
|
+
* @param weekStart - Desired week start (0-6)
|
|
21
|
+
* @returns Number of padding days needed
|
|
22
|
+
*/
|
|
23
|
+
private calculateOffset;
|
|
24
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CalendarGridFactory, never>;
|
|
25
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<CalendarGridFactory>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Grid Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure for memoized calendar month grids.
|
|
5
|
+
* Separates base grid structure (cacheable) from decorations (dynamic).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A single calendar cell representing one day
|
|
9
|
+
*/
|
|
10
|
+
export interface CalendarCell {
|
|
11
|
+
/** Date object (normalized to start of day) */
|
|
12
|
+
date: Date;
|
|
13
|
+
/** Whether this day belongs to the current rendered month */
|
|
14
|
+
inCurrentMonth: boolean;
|
|
15
|
+
/** ISO string 'YYYY-MM-DD' (timezone-safe via DateAdapter) */
|
|
16
|
+
iso: string;
|
|
17
|
+
/** Day of month (1-31) */
|
|
18
|
+
day: number;
|
|
19
|
+
/** Month (0-11, JavaScript convention) */
|
|
20
|
+
month: number;
|
|
21
|
+
/** Full year */
|
|
22
|
+
year: number;
|
|
23
|
+
/** Day of week (0 = Sunday, 6 = Saturday) */
|
|
24
|
+
dayOfWeek: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A calendar grid representing one month
|
|
28
|
+
*
|
|
29
|
+
* Grid is always 6 weeks x 7 days (42 cells) for layout stability.
|
|
30
|
+
* Includes padding days from previous/next month.
|
|
31
|
+
*/
|
|
32
|
+
export interface CalendarGrid {
|
|
33
|
+
/** Month identifier */
|
|
34
|
+
month: {
|
|
35
|
+
/** Year */
|
|
36
|
+
year: number;
|
|
37
|
+
/** Month 0-11 */
|
|
38
|
+
month: number;
|
|
39
|
+
};
|
|
40
|
+
/** Week start day (0 = Sunday, 1 = Monday, etc.) */
|
|
41
|
+
weekStart: number;
|
|
42
|
+
/** Locale (for future i18n, optional) */
|
|
43
|
+
locale?: string;
|
|
44
|
+
/** 6 weeks x 7 days matrix */
|
|
45
|
+
weeks: CalendarCell[][];
|
|
46
|
+
/** Flat array of all cells (convenience accessor) */
|
|
47
|
+
cells: CalendarCell[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Cache key for calendar grids
|
|
51
|
+
*/
|
|
52
|
+
export interface CalendarGridCacheKey {
|
|
53
|
+
year: number;
|
|
54
|
+
month: number;
|
|
55
|
+
weekStart: number;
|
|
56
|
+
locale?: string;
|
|
57
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Grid Module
|
|
3
|
+
*
|
|
4
|
+
* Performance-optimized calendar month grid generation with memoization.
|
|
5
|
+
*
|
|
6
|
+
* v3.7.0: Grid Structure Cache
|
|
7
|
+
* - CalendarGridFactory for deterministic 42-cell grids
|
|
8
|
+
* - CalendarGridCache with LRU (24 months)
|
|
9
|
+
*
|
|
10
|
+
* v3.8.0: Range Highlight Cache
|
|
11
|
+
* - RangeHighlighter for decoration logic
|
|
12
|
+
* - RangeHighlighterCache with LRU (48 grids)
|
|
13
|
+
* - Separates grid structure from decorations
|
|
14
|
+
*
|
|
15
|
+
* v3.9.0: Virtual Weeks (Windowed Rendering)
|
|
16
|
+
* - Virtual-weeks logic for reduced DOM complexity
|
|
17
|
+
* - Render only visible weeks (configurable window)
|
|
18
|
+
* - ~50% reduction in DOM nodes with windowSize=3
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* constructor(
|
|
23
|
+
* private gridCache: CalendarGridCache,
|
|
24
|
+
* private highlighterCache: RangeHighlighterCache
|
|
25
|
+
* ) {}
|
|
26
|
+
*
|
|
27
|
+
* const grid = this.gridCache.get(monthDate, weekStart);
|
|
28
|
+
* const decorated = this.highlighterCache.get(grid, {
|
|
29
|
+
* start, end, hoverDate, disabledDates
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Optional: Windowed rendering (v3.9.0+)
|
|
33
|
+
* const windowSize = 3; // Render only 3 weeks
|
|
34
|
+
* const visibleWeeks = getVisibleWeeks(
|
|
35
|
+
* decorated.weeks,
|
|
36
|
+
* weekStartIndex,
|
|
37
|
+
* windowSize
|
|
38
|
+
* );
|
|
39
|
+
* // decorated.cells[0].iso => '2026-02-01'
|
|
40
|
+
* // decorated.cells[0].isInRange => true
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export * from './calendar-grid.types';
|
|
44
|
+
export * from './calendar-grid.factory';
|
|
45
|
+
export * from './calendar-grid.cache';
|
|
46
|
+
export * from './range-highlighter.types';
|
|
47
|
+
export * from './range-highlighter';
|
|
48
|
+
export * from './range-highlighter.cache';
|
|
49
|
+
export * from './virtual-weeks.types';
|
|
50
|
+
export * from './virtual-weeks.logic';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { DateAdapter } from '../date-adapter';
|
|
2
|
+
import { CalendarGrid } from './calendar-grid.types';
|
|
3
|
+
import { DecoratedGrid, RangeDecorationParams } from './range-highlighter.types';
|
|
4
|
+
import { RangeHighlighter } from './range-highlighter';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* Range Highlighter Cache
|
|
8
|
+
*
|
|
9
|
+
* Memoizes decorated grids to avoid recomputing decorations.
|
|
10
|
+
*
|
|
11
|
+
* Cache strategy:
|
|
12
|
+
* - LRU eviction (Map preserves insertion order)
|
|
13
|
+
* - Max 48 entries (~1-2 years of decorated grids)
|
|
14
|
+
* - Key: month + start + end + hover + disabled signature
|
|
15
|
+
*
|
|
16
|
+
* Performance:
|
|
17
|
+
* - Cache hit: ~0.1ms (object lookup)
|
|
18
|
+
* - Cache miss: ~1ms (decoration + store)
|
|
19
|
+
* - Hit rate: Expected >80% in typical usage
|
|
20
|
+
*
|
|
21
|
+
* Memory:
|
|
22
|
+
* - ~15KB per decorated grid
|
|
23
|
+
* - Max 48 grids = ~720KB
|
|
24
|
+
* - Auto-eviction prevents leaks
|
|
25
|
+
*
|
|
26
|
+
* Edge cases handled:
|
|
27
|
+
* - Function predicates: Not cacheable (recompute every time)
|
|
28
|
+
* - Large disabled arrays: Sorted + joined for stable key
|
|
29
|
+
* - Hover changes: Separate cache entries
|
|
30
|
+
* - Multi-range mode: Included in key
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const grid = calendarGridCache.get(monthDate, 0);
|
|
35
|
+
* const decorated = rangeHighlighterCache.get(grid, {
|
|
36
|
+
* start: startDate,
|
|
37
|
+
* end: endDate,
|
|
38
|
+
* hoverDate: '2026-01-20',
|
|
39
|
+
* disabledDates: [...]
|
|
40
|
+
* });
|
|
41
|
+
* // Same params = same object reference (===)
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class RangeHighlighterCache {
|
|
45
|
+
private highlighter;
|
|
46
|
+
private adapter;
|
|
47
|
+
private cache;
|
|
48
|
+
private maxSize;
|
|
49
|
+
constructor(highlighter: RangeHighlighter, adapter: DateAdapter);
|
|
50
|
+
/**
|
|
51
|
+
* Get decorated grid (cached or computed)
|
|
52
|
+
*
|
|
53
|
+
* If cache hit: Returns existing DecoratedGrid (same object reference)
|
|
54
|
+
* If cache miss: Computes decorations, stores in cache, returns new grid
|
|
55
|
+
*
|
|
56
|
+
* @param grid Base calendar grid (from CalendarGridCache)
|
|
57
|
+
* @param params Decoration parameters
|
|
58
|
+
* @returns Decorated grid with range highlights
|
|
59
|
+
*/
|
|
60
|
+
get(grid: CalendarGrid, params: RangeDecorationParams): DecoratedGrid;
|
|
61
|
+
/**
|
|
62
|
+
* Build cache key from grid and params
|
|
63
|
+
*
|
|
64
|
+
* Key structure:
|
|
65
|
+
* `${monthKey}|${startISO}|${endISO}|${minISO}|${maxISO}|${hoverISO}|${disabledSig}`
|
|
66
|
+
*
|
|
67
|
+
* Example:
|
|
68
|
+
* "2026-1-0-|2026-01-15|2026-01-25|null|null|2026-01-20|2026-01-10,2026-01-11"
|
|
69
|
+
*
|
|
70
|
+
* @param grid Base calendar grid
|
|
71
|
+
* @param params Decoration parameters
|
|
72
|
+
* @returns Cache key components
|
|
73
|
+
*/
|
|
74
|
+
private buildKey;
|
|
75
|
+
/**
|
|
76
|
+
* Build signature for disabled dates
|
|
77
|
+
*
|
|
78
|
+
* Strategies:
|
|
79
|
+
* - null/undefined: 'none'
|
|
80
|
+
* - Function: 'function' (not cacheable)
|
|
81
|
+
* - Array: Sorted ISO dates joined with commas
|
|
82
|
+
*
|
|
83
|
+
* @param disabledDates Disabled dates specification
|
|
84
|
+
* @returns Signature string for cache key
|
|
85
|
+
*/
|
|
86
|
+
private buildDisabledSignature;
|
|
87
|
+
/**
|
|
88
|
+
* Clear all cached grids
|
|
89
|
+
*/
|
|
90
|
+
clear(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Get current cache size
|
|
93
|
+
*/
|
|
94
|
+
size(): number;
|
|
95
|
+
/**
|
|
96
|
+
* Check if key is cached
|
|
97
|
+
*
|
|
98
|
+
* @param grid Base calendar grid
|
|
99
|
+
* @param params Decoration parameters
|
|
100
|
+
* @returns True if this grid+params is cached
|
|
101
|
+
*/
|
|
102
|
+
has(grid: CalendarGrid, params: RangeDecorationParams): boolean;
|
|
103
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RangeHighlighterCache, never>;
|
|
104
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RangeHighlighterCache>;
|
|
105
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { DateAdapter } from '../date-adapter';
|
|
2
|
+
import { CalendarGrid } from './calendar-grid.types';
|
|
3
|
+
import { DecoratedGrid, RangeDecorationParams } from './range-highlighter.types';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Range Highlighter
|
|
7
|
+
*
|
|
8
|
+
* Applies decorations to calendar grids:
|
|
9
|
+
* - isSelectedStart, isSelectedEnd (range boundaries)
|
|
10
|
+
* - isInRange (cells within selected range)
|
|
11
|
+
* - isInHoverRange (hover preview)
|
|
12
|
+
* - isDisabled (constraints, custom predicates)
|
|
13
|
+
*
|
|
14
|
+
* Design:
|
|
15
|
+
* - Pure functions (same input = same output)
|
|
16
|
+
* - Uses DateAdapter for all date operations (SSR-safe)
|
|
17
|
+
* - No side effects, no state
|
|
18
|
+
* - Fast (~1ms for 42 cells on mobile)
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const grid = calendarGridCache.get(monthDate, 0);
|
|
23
|
+
* const decorated = rangeHighlighter.decorate(grid, {
|
|
24
|
+
* start: startDate,
|
|
25
|
+
* end: endDate,
|
|
26
|
+
* hoverDate: '2026-01-20',
|
|
27
|
+
* disabledDates: [...]
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class RangeHighlighter {
|
|
32
|
+
private adapter;
|
|
33
|
+
constructor(adapter: DateAdapter);
|
|
34
|
+
/**
|
|
35
|
+
* Decorate calendar grid with range highlights
|
|
36
|
+
*
|
|
37
|
+
* @param grid Base calendar grid (from CalendarGridCache)
|
|
38
|
+
* @param params Decoration parameters (start, end, hover, disabled, etc.)
|
|
39
|
+
* @returns Decorated grid with computed properties
|
|
40
|
+
*/
|
|
41
|
+
decorate(grid: CalendarGrid, params: RangeDecorationParams): DecoratedGrid;
|
|
42
|
+
/**
|
|
43
|
+
* Check if cell is within selected range
|
|
44
|
+
*
|
|
45
|
+
* @param cellISO Cell date (ISO format)
|
|
46
|
+
* @param startISO Start date (ISO or null)
|
|
47
|
+
* @param endISO End date (ISO or null)
|
|
48
|
+
* @returns True if cell is in range [start, end] (inclusive)
|
|
49
|
+
*/
|
|
50
|
+
private isInRange;
|
|
51
|
+
/**
|
|
52
|
+
* Check if cell is within hover preview range
|
|
53
|
+
*
|
|
54
|
+
* @param cellISO Cell date (ISO format)
|
|
55
|
+
* @param hoverRange Hover range boundaries (or null)
|
|
56
|
+
* @returns True if cell is in hover range
|
|
57
|
+
*/
|
|
58
|
+
private isInHoverRange;
|
|
59
|
+
/**
|
|
60
|
+
* Check if cell is disabled
|
|
61
|
+
*
|
|
62
|
+
* @param date Cell date object
|
|
63
|
+
* @param minISO Minimum allowed date (ISO or null)
|
|
64
|
+
* @param maxISO Maximum allowed date (ISO or null)
|
|
65
|
+
* @param disabledDates Disabled dates (array, function, or null)
|
|
66
|
+
* @returns True if cell is disabled
|
|
67
|
+
*/
|
|
68
|
+
private isDisabled;
|
|
69
|
+
/**
|
|
70
|
+
* Compute hover preview range
|
|
71
|
+
*
|
|
72
|
+
* When user hovers over a date (and not selecting start):
|
|
73
|
+
* - Show preview range from start to hover
|
|
74
|
+
* - Range is always [min, max] where min <= max
|
|
75
|
+
*
|
|
76
|
+
* @param startISO Current start date (ISO or null)
|
|
77
|
+
* @param hoverISO Hovered date (ISO or null)
|
|
78
|
+
* @param selectingStart True if selecting start date (hover disabled)
|
|
79
|
+
* @param multiRange True if in multi-range mode
|
|
80
|
+
* @returns Hover range boundaries or null
|
|
81
|
+
*/
|
|
82
|
+
private computeHoverRange;
|
|
83
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RangeHighlighter, never>;
|
|
84
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RangeHighlighter>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Range Highlighter Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for calendar cell decorations with range highlighting.
|
|
5
|
+
* Used by RangeHighlighter to cache decorated grids and avoid recomputations.
|
|
6
|
+
*
|
|
7
|
+
* @module core/calendar-grid/range-highlighter.types
|
|
8
|
+
* @version 3.8.0
|
|
9
|
+
*/
|
|
10
|
+
import { CalendarCell, CalendarGrid } from './calendar-grid.types';
|
|
11
|
+
/**
|
|
12
|
+
* Calendar cell with range highlight decorations
|
|
13
|
+
*
|
|
14
|
+
* Extends base CalendarCell with computed properties for:
|
|
15
|
+
* - Start/end markers (selected range boundaries)
|
|
16
|
+
* - Range membership (cell within selected range)
|
|
17
|
+
* - Hover preview (temporary range during mouse hover)
|
|
18
|
+
* - Disabled state (constraints, custom predicates)
|
|
19
|
+
*/
|
|
20
|
+
export interface DecoratedCell extends CalendarCell {
|
|
21
|
+
/**
|
|
22
|
+
* True if this cell is the selected start date
|
|
23
|
+
*/
|
|
24
|
+
isSelectedStart: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* True if this cell is the selected end date
|
|
27
|
+
*/
|
|
28
|
+
isSelectedEnd: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* True if this cell is within the selected range (inclusive)
|
|
31
|
+
*/
|
|
32
|
+
isInRange: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* True if this cell is within the hover preview range
|
|
35
|
+
*/
|
|
36
|
+
isInHoverRange: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* True if this cell is disabled (via constraints or custom logic)
|
|
39
|
+
*/
|
|
40
|
+
isDisabled: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Calendar grid with decorated cells
|
|
44
|
+
*
|
|
45
|
+
* Contains:
|
|
46
|
+
* - base: Original CalendarGrid (from CalendarGridCache)
|
|
47
|
+
* - weeks: 2D array of decorated cells (6 × 7)
|
|
48
|
+
* - cells: Flat array of decorated cells (42 cells)
|
|
49
|
+
*/
|
|
50
|
+
export interface DecoratedGrid {
|
|
51
|
+
/**
|
|
52
|
+
* Base grid structure (memoized by CalendarGridCache)
|
|
53
|
+
*/
|
|
54
|
+
base: CalendarGrid;
|
|
55
|
+
/**
|
|
56
|
+
* Decorated cells organized as weeks (6 weeks × 7 days)
|
|
57
|
+
*/
|
|
58
|
+
weeks: DecoratedCell[][];
|
|
59
|
+
/**
|
|
60
|
+
* Decorated cells as flat array (42 cells for layout stability)
|
|
61
|
+
*/
|
|
62
|
+
cells: DecoratedCell[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parameters for range decoration
|
|
66
|
+
*
|
|
67
|
+
* All dates must be Date objects (pre-parsed by component).
|
|
68
|
+
* Cache key is built from ISO dates (via DateAdapter.toISODate).
|
|
69
|
+
*
|
|
70
|
+
* Constraints:
|
|
71
|
+
* - start/end: Selected range boundaries (null if not selected)
|
|
72
|
+
* - minDate/maxDate: Hard constraints (optional, for future use)
|
|
73
|
+
* - hoverDate: Current hover date (null if not hovering)
|
|
74
|
+
* - disabledDates: Array of disabled dates OR function predicate
|
|
75
|
+
*/
|
|
76
|
+
export interface RangeDecorationParams {
|
|
77
|
+
/**
|
|
78
|
+
* Selected start date (null if not selected yet)
|
|
79
|
+
*/
|
|
80
|
+
start: Date | null;
|
|
81
|
+
/**
|
|
82
|
+
* Selected end date (null if not selected yet)
|
|
83
|
+
*/
|
|
84
|
+
end: Date | null;
|
|
85
|
+
/**
|
|
86
|
+
* Minimum allowed date (optional, for future constraint support)
|
|
87
|
+
* All dates before this will be disabled.
|
|
88
|
+
*/
|
|
89
|
+
minDate?: Date | null;
|
|
90
|
+
/**
|
|
91
|
+
* Maximum allowed date (optional, for future constraint support)
|
|
92
|
+
* All dates after this will be disabled.
|
|
93
|
+
*/
|
|
94
|
+
maxDate?: Date | null;
|
|
95
|
+
/**
|
|
96
|
+
* Current hover date (null if not hovering)
|
|
97
|
+
* Used to calculate hover preview range.
|
|
98
|
+
*/
|
|
99
|
+
hoverDate?: string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Disabled dates specification
|
|
102
|
+
*
|
|
103
|
+
* Can be one of:
|
|
104
|
+
* - Array of Date objects to disable (exact matches)
|
|
105
|
+
* - Function predicate (date) => boolean
|
|
106
|
+
* - undefined/null (no dates disabled)
|
|
107
|
+
*
|
|
108
|
+
* NOTE: Functions cannot be cached reliably (no stable key).
|
|
109
|
+
* If using function, cache will be bypassed for isDisabled computation.
|
|
110
|
+
*/
|
|
111
|
+
disabledDates?: Date[] | ((date: Date) => boolean) | null;
|
|
112
|
+
/**
|
|
113
|
+
* Multi-range mode flag (affects hover range behavior)
|
|
114
|
+
* Default: false
|
|
115
|
+
*/
|
|
116
|
+
multiRange?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Currently selecting start date (affects hover preview)
|
|
119
|
+
* Default: false
|
|
120
|
+
*/
|
|
121
|
+
selectingStartDate?: boolean;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Cache key for decorated grid
|
|
125
|
+
*
|
|
126
|
+
* Built from:
|
|
127
|
+
* - monthKey: `${year}-${month}-${weekStart}-${locale}`
|
|
128
|
+
* - startISO, endISO: ISO dates or 'null'
|
|
129
|
+
* - minISO, maxISO: ISO dates or 'null' (optional)
|
|
130
|
+
* - hoverISO: ISO date or 'null'
|
|
131
|
+
* - disabledSignature: Hash of disabled dates (or 'none' / 'function')
|
|
132
|
+
*
|
|
133
|
+
* Example:
|
|
134
|
+
* "2026-1-0-|2026-01-15|2026-01-25|null|null|2026-01-20|2026-01-10,2026-01-11"
|
|
135
|
+
*
|
|
136
|
+
* Segment breakdown:
|
|
137
|
+
* 1. 2026-1-0- (month: Jan 2026, weekStart: Sunday, no locale)
|
|
138
|
+
* 2. 2026-01-15 (start date)
|
|
139
|
+
* 3. 2026-01-25 (end date)
|
|
140
|
+
* 4. null (no minDate)
|
|
141
|
+
* 5. null (no maxDate)
|
|
142
|
+
* 6. 2026-01-20 (hovering over Jan 20)
|
|
143
|
+
* 7. 2026-01-10,2026-01-11 (disabled dates: Jan 10 & 11)
|
|
144
|
+
*/
|
|
145
|
+
export interface DecoratedGridCacheKey {
|
|
146
|
+
/**
|
|
147
|
+
* Combined month key (from base grid)
|
|
148
|
+
*/
|
|
149
|
+
monthKey: string;
|
|
150
|
+
/**
|
|
151
|
+
* Start date ISO (YYYY-MM-DD) or 'null'
|
|
152
|
+
*/
|
|
153
|
+
startISO: string;
|
|
154
|
+
/**
|
|
155
|
+
* End date ISO (YYYY-MM-DD) or 'null'
|
|
156
|
+
*/
|
|
157
|
+
endISO: string;
|
|
158
|
+
/**
|
|
159
|
+
* Min date ISO (YYYY-MM-DD) or 'null'
|
|
160
|
+
*/
|
|
161
|
+
minISO: string;
|
|
162
|
+
/**
|
|
163
|
+
* Max date ISO (YYYY-MM-DD) or 'null'
|
|
164
|
+
*/
|
|
165
|
+
maxISO: string;
|
|
166
|
+
/**
|
|
167
|
+
* Hover date ISO (YYYY-MM-DD) or 'null'
|
|
168
|
+
*/
|
|
169
|
+
hoverISO: string;
|
|
170
|
+
/**
|
|
171
|
+
* Disabled dates signature
|
|
172
|
+
*
|
|
173
|
+
* - 'none': No dates disabled
|
|
174
|
+
* - 'function': Using predicate function (not cacheable)
|
|
175
|
+
* - sorted ISO string: "2026-01-10,2026-01-11,..." (for array)
|
|
176
|
+
*/
|
|
177
|
+
disabledSignature: string;
|
|
178
|
+
/**
|
|
179
|
+
* Full cache key (concatenation of all segments)
|
|
180
|
+
*/
|
|
181
|
+
full: string;
|
|
182
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual Weeks Logic (Pure Functions)
|
|
3
|
+
*
|
|
4
|
+
* Pure computation layer for windowed week rendering.
|
|
5
|
+
* No side effects, fully testable with node:test.
|
|
6
|
+
*
|
|
7
|
+
* @module core/calendar-grid/virtual-weeks.logic
|
|
8
|
+
* @version 3.9.0
|
|
9
|
+
*/
|
|
10
|
+
import { VirtualWeekWindow } from './virtual-weeks.types';
|
|
11
|
+
/**
|
|
12
|
+
* Get visible weeks from total weeks array
|
|
13
|
+
*
|
|
14
|
+
* Pure function: Given weeks array and window config, returns visible slice.
|
|
15
|
+
*
|
|
16
|
+
* @param weeks Total weeks array (usually 6 weeks)
|
|
17
|
+
* @param startIndex Start index of visible window (0-based)
|
|
18
|
+
* @param windowSize How many weeks to show
|
|
19
|
+
* @returns Visible weeks slice
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const allWeeks = [week0, week1, week2, week3, week4, week5]; // 6 weeks
|
|
24
|
+
* const visible = getVisibleWeeks(allWeeks, 0, 3);
|
|
25
|
+
* // Returns [week0, week1, week2]
|
|
26
|
+
*
|
|
27
|
+
* const visible2 = getVisibleWeeks(allWeeks, 3, 3);
|
|
28
|
+
* // Returns [week3, week4, week5]
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function getVisibleWeeks<T>(weeks: T[], startIndex: number, windowSize: number): T[];
|
|
32
|
+
/**
|
|
33
|
+
* Clamp week start index to valid range
|
|
34
|
+
*
|
|
35
|
+
* Ensures startIndex is within bounds [0, totalWeeks - windowSize].
|
|
36
|
+
* Prevents scrolling beyond available weeks.
|
|
37
|
+
*
|
|
38
|
+
* @param startIndex Desired start index
|
|
39
|
+
* @param totalWeeks Total weeks available
|
|
40
|
+
* @param windowSize Window size
|
|
41
|
+
* @returns Clamped start index
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* clampWeekStart(0, 6, 3); // 0 (valid)
|
|
46
|
+
* clampWeekStart(3, 6, 3); // 3 (valid, shows weeks 3-5)
|
|
47
|
+
* clampWeekStart(4, 6, 3); // 3 (clamped, can't show beyond week 5)
|
|
48
|
+
* clampWeekStart(-1, 6, 3); // 0 (clamped, can't go negative)
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function clampWeekStart(startIndex: number, totalWeeks: number, windowSize: number): number;
|
|
52
|
+
/**
|
|
53
|
+
* Navigate week window (scroll up/down)
|
|
54
|
+
*
|
|
55
|
+
* Returns new start index after navigation.
|
|
56
|
+
* Handles clamping automatically.
|
|
57
|
+
*
|
|
58
|
+
* @param currentStart Current start index
|
|
59
|
+
* @param direction Navigation direction (+1 = down/later, -1 = up/earlier)
|
|
60
|
+
* @param totalWeeks Total weeks available
|
|
61
|
+
* @param windowSize Window size
|
|
62
|
+
* @returns New start index after navigation
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* // Start at week 0, navigate down
|
|
67
|
+
* navigateWeekWindow(0, 1, 6, 3); // Returns 1 (now showing weeks 1-3)
|
|
68
|
+
*
|
|
69
|
+
* // At week 3 (last valid position), navigate down
|
|
70
|
+
* navigateWeekWindow(3, 1, 6, 3); // Returns 3 (can't go further)
|
|
71
|
+
*
|
|
72
|
+
* // At week 1, navigate up
|
|
73
|
+
* navigateWeekWindow(1, -1, 6, 3); // Returns 0 (now showing weeks 0-2)
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function navigateWeekWindow(currentStart: number, direction: number, totalWeeks: number, windowSize: number): number;
|
|
77
|
+
/**
|
|
78
|
+
* Get virtual week window state
|
|
79
|
+
*
|
|
80
|
+
* Computes full window state including navigation capabilities.
|
|
81
|
+
*
|
|
82
|
+
* @param startIndex Current start index
|
|
83
|
+
* @param totalWeeks Total weeks available
|
|
84
|
+
* @param windowSize Window size
|
|
85
|
+
* @returns Complete window state
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const state = getVirtualWeekWindow(0, 6, 3);
|
|
90
|
+
* // {
|
|
91
|
+
* // startIndex: 0,
|
|
92
|
+
* // windowSize: 3,
|
|
93
|
+
* // totalWeeks: 6,
|
|
94
|
+
* // canNavigateUp: false, // Already at top
|
|
95
|
+
* // canNavigateDown: true // Can scroll down
|
|
96
|
+
* // }
|
|
97
|
+
*
|
|
98
|
+
* const state2 = getVirtualWeekWindow(3, 6, 3);
|
|
99
|
+
* // {
|
|
100
|
+
* // startIndex: 3,
|
|
101
|
+
* // windowSize: 3,
|
|
102
|
+
* // totalWeeks: 6,
|
|
103
|
+
* // canNavigateUp: true, // Can scroll up
|
|
104
|
+
* // canNavigateDown: false // Already at bottom
|
|
105
|
+
* // }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function getVirtualWeekWindow(startIndex: number, totalWeeks: number, windowSize: number): VirtualWeekWindow;
|
|
109
|
+
/**
|
|
110
|
+
* Check if virtual weeks mode is enabled
|
|
111
|
+
*
|
|
112
|
+
* @param windowSize Window size from config (undefined = disabled)
|
|
113
|
+
* @param totalWeeks Total weeks available
|
|
114
|
+
* @returns True if windowing should be applied
|
|
115
|
+
*/
|
|
116
|
+
export declare function isVirtualWeeksEnabled(windowSize: number | undefined, totalWeeks: number): boolean;
|