react-native-ruler-date-picker 0.1.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/LICENSE +21 -0
- package/README.md +124 -0
- package/lib/commonjs/RulerDatePicker.js +376 -0
- package/lib/commonjs/RulerDatePicker.js.map +1 -0
- package/lib/commonjs/Tick.js +79 -0
- package/lib/commonjs/Tick.js.map +1 -0
- package/lib/commonjs/defaults.js +48 -0
- package/lib/commonjs/defaults.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/useHaptics.js +83 -0
- package/lib/commonjs/useHaptics.js.map +1 -0
- package/lib/commonjs/utils.js +99 -0
- package/lib/commonjs/utils.js.map +1 -0
- package/lib/module/RulerDatePicker.js +371 -0
- package/lib/module/RulerDatePicker.js.map +1 -0
- package/lib/module/Tick.js +74 -0
- package/lib/module/Tick.js.map +1 -0
- package/lib/module/defaults.js +44 -0
- package/lib/module/defaults.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/useHaptics.js +80 -0
- package/lib/module/useHaptics.js.map +1 -0
- package/lib/module/utils.js +90 -0
- package/lib/module/utils.js.map +1 -0
- package/lib/typescript/RulerDatePicker.d.ts +21 -0
- package/lib/typescript/RulerDatePicker.d.ts.map +1 -0
- package/lib/typescript/Tick.d.ts +26 -0
- package/lib/typescript/Tick.d.ts.map +1 -0
- package/lib/typescript/defaults.d.ts +24 -0
- package/lib/typescript/defaults.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +104 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/useHaptics.d.ts +20 -0
- package/lib/typescript/useHaptics.d.ts.map +1 -0
- package/lib/typescript/utils.d.ts +31 -0
- package/lib/typescript/utils.d.ts.map +1 -0
- package/package.json +106 -0
- package/src/RulerDatePicker.tsx +462 -0
- package/src/Tick.tsx +104 -0
- package/src/defaults.ts +44 -0
- package/src/index.ts +2 -0
- package/src/types.ts +129 -0
- package/src/useHaptics.ts +107 -0
- package/src/utils.ts +115 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MS_PER_DAY = exports.LIGHT_COLORS = exports.DEFAULT_DAY_RANGE = exports.DEFAULTS = exports.DARK_COLORS = void 0;
|
|
7
|
+
// ── Internal constants (not user-configurable) ───────────────────────────
|
|
8
|
+
const MS_PER_DAY = exports.MS_PER_DAY = 86_400_000;
|
|
9
|
+
const DEFAULT_DAY_RANGE = exports.DEFAULT_DAY_RANGE = 365;
|
|
10
|
+
|
|
11
|
+
// ── User-configurable defaults ───────────────────────────────────────────
|
|
12
|
+
const DEFAULTS = exports.DEFAULTS = {
|
|
13
|
+
tickSpacing: 24,
|
|
14
|
+
tickHeight: 12,
|
|
15
|
+
tickTallHeight: 24,
|
|
16
|
+
tickThickness: 4,
|
|
17
|
+
height: 120,
|
|
18
|
+
rulerHeight: 60,
|
|
19
|
+
indicatorWidth: 2,
|
|
20
|
+
indicatorHeight: 40,
|
|
21
|
+
todayDotSize: 6,
|
|
22
|
+
labelFontSize: 10,
|
|
23
|
+
bufferTicks: 10,
|
|
24
|
+
updateDebounceMs: 100,
|
|
25
|
+
fastSwipeTickThreshold: 1,
|
|
26
|
+
continuousHapticIntervalMs: 20,
|
|
27
|
+
enableHaptics: true,
|
|
28
|
+
showResetToToday: false
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ── Default color palettes ───────────────────────────────────────────────
|
|
32
|
+
const LIGHT_COLORS = exports.LIGHT_COLORS = {
|
|
33
|
+
tickColor: '#D1D5DB',
|
|
34
|
+
tickTallColor: '#9CA3AF',
|
|
35
|
+
labelColor: '#6B7280',
|
|
36
|
+
accentColor: '#3B82F6',
|
|
37
|
+
indicatorColor: '#3B82F6',
|
|
38
|
+
backgroundColor: 'transparent'
|
|
39
|
+
};
|
|
40
|
+
const DARK_COLORS = exports.DARK_COLORS = {
|
|
41
|
+
tickColor: '#4B5563',
|
|
42
|
+
tickTallColor: '#6B7280',
|
|
43
|
+
labelColor: '#9CA3AF',
|
|
44
|
+
accentColor: '#60A5FA',
|
|
45
|
+
indicatorColor: '#60A5FA',
|
|
46
|
+
backgroundColor: 'transparent'
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["MS_PER_DAY","exports","DEFAULT_DAY_RANGE","DEFAULTS","tickSpacing","tickHeight","tickTallHeight","tickThickness","height","rulerHeight","indicatorWidth","indicatorHeight","todayDotSize","labelFontSize","bufferTicks","updateDebounceMs","fastSwipeTickThreshold","continuousHapticIntervalMs","enableHaptics","showResetToToday","LIGHT_COLORS","tickColor","tickTallColor","labelColor","accentColor","indicatorColor","backgroundColor","DARK_COLORS"],"sourceRoot":"../../src","sources":["defaults.ts"],"mappings":";;;;;;AAEA;AACO,MAAMA,UAAU,GAAAC,OAAA,CAAAD,UAAA,GAAG,UAAU;AAC7B,MAAME,iBAAiB,GAAAD,OAAA,CAAAC,iBAAA,GAAG,GAAG;;AAEpC;AACO,MAAMC,QAAQ,GAAAF,OAAA,CAAAE,QAAA,GAAG;EACtBC,WAAW,EAAE,EAAE;EACfC,UAAU,EAAE,EAAE;EACdC,cAAc,EAAE,EAAE;EAClBC,aAAa,EAAE,CAAC;EAChBC,MAAM,EAAE,GAAG;EACXC,WAAW,EAAE,EAAE;EACfC,cAAc,EAAE,CAAC;EACjBC,eAAe,EAAE,EAAE;EACnBC,YAAY,EAAE,CAAC;EACfC,aAAa,EAAE,EAAE;EACjBC,WAAW,EAAE,EAAE;EACfC,gBAAgB,EAAE,GAAG;EACrBC,sBAAsB,EAAE,CAAC;EACzBC,0BAA0B,EAAE,EAAE;EAC9BC,aAAa,EAAE,IAAI;EACnBC,gBAAgB,EAAE;AACpB,CAAU;;AAEV;AACO,MAAMC,YAA4B,GAAAnB,OAAA,CAAAmB,YAAA,GAAG;EAC1CC,SAAS,EAAE,SAAS;EACpBC,aAAa,EAAE,SAAS;EACxBC,UAAU,EAAE,SAAS;EACrBC,WAAW,EAAE,SAAS;EACtBC,cAAc,EAAE,SAAS;EACzBC,eAAe,EAAE;AACnB,CAAC;AAEM,MAAMC,WAA2B,GAAA1B,OAAA,CAAA0B,WAAA,GAAG;EACzCN,SAAS,EAAE,SAAS;EACpBC,aAAa,EAAE,SAAS;EACxBC,UAAU,EAAE,SAAS;EACrBC,WAAW,EAAE,SAAS;EACtBC,cAAc,EAAE,SAAS;EACzBC,eAAe,EAAE;AACnB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "RulerDatePicker", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _RulerDatePicker.RulerDatePicker;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _RulerDatePicker = require("./RulerDatePicker");
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_RulerDatePicker","require"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;AAAA,IAAAA,gBAAA,GAAAC,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useHaptics = useHaptics;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _defaults = require("./defaults");
|
|
10
|
+
/**
|
|
11
|
+
* Attempts to dynamically require expo-haptics.
|
|
12
|
+
* Returns null if the module is not installed, allowing graceful degradation
|
|
13
|
+
* in pure React Native CLI projects.
|
|
14
|
+
*/
|
|
15
|
+
let ExpoHaptics = null;
|
|
16
|
+
try {
|
|
17
|
+
ExpoHaptics = require('expo-haptics');
|
|
18
|
+
} catch {
|
|
19
|
+
// expo-haptics not installed — haptics will be silently disabled
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Haptics abstraction hook.
|
|
23
|
+
*
|
|
24
|
+
* - If `onHapticTrigger` is provided, delegates all haptic calls to it.
|
|
25
|
+
* - Otherwise, uses expo-haptics if available.
|
|
26
|
+
* - Falls back to no-op if neither is available or haptics are disabled.
|
|
27
|
+
*/
|
|
28
|
+
function useHaptics({
|
|
29
|
+
enableHaptics,
|
|
30
|
+
onHapticTrigger,
|
|
31
|
+
continuousHapticIntervalMs = _defaults.DEFAULTS.continuousHapticIntervalMs
|
|
32
|
+
}) {
|
|
33
|
+
const hapticIntervalRef = (0, _react.useRef)(null);
|
|
34
|
+
|
|
35
|
+
/** Fire a single discrete haptic — used in slow scroll mode */
|
|
36
|
+
const fireDiscreteHaptic = (0, _react.useCallback)(() => {
|
|
37
|
+
if (!enableHaptics) return;
|
|
38
|
+
if (onHapticTrigger) {
|
|
39
|
+
onHapticTrigger('tick');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!ExpoHaptics) return;
|
|
43
|
+
if (_reactNative.Platform.OS === 'android') {
|
|
44
|
+
ExpoHaptics.impactAsync(ExpoHaptics.ImpactFeedbackStyle.Light).catch(() => {});
|
|
45
|
+
} else {
|
|
46
|
+
ExpoHaptics.selectionAsync().catch(() => {});
|
|
47
|
+
}
|
|
48
|
+
}, [enableHaptics, onHapticTrigger]);
|
|
49
|
+
|
|
50
|
+
/** Start a continuous haptic buzz — used in fast scroll mode */
|
|
51
|
+
const startContinuousHaptic = (0, _react.useCallback)(() => {
|
|
52
|
+
if (!enableHaptics) return;
|
|
53
|
+
if (onHapticTrigger) {
|
|
54
|
+
onHapticTrigger('continuous');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!ExpoHaptics) return;
|
|
58
|
+
|
|
59
|
+
// Already running — don't double-start
|
|
60
|
+
if (hapticIntervalRef.current) return;
|
|
61
|
+
|
|
62
|
+
// Fire one immediately so the transition isn't silent
|
|
63
|
+
ExpoHaptics.impactAsync(ExpoHaptics.ImpactFeedbackStyle.Light).catch(() => {});
|
|
64
|
+
const interval = _reactNative.Platform.OS === 'android' ? 35 : continuousHapticIntervalMs;
|
|
65
|
+
hapticIntervalRef.current = setInterval(() => {
|
|
66
|
+
ExpoHaptics.impactAsync(ExpoHaptics.ImpactFeedbackStyle.Light).catch(() => {});
|
|
67
|
+
}, interval);
|
|
68
|
+
}, [enableHaptics, onHapticTrigger, continuousHapticIntervalMs]);
|
|
69
|
+
|
|
70
|
+
/** Stop the continuous haptic buzz */
|
|
71
|
+
const stopContinuousHaptic = (0, _react.useCallback)(() => {
|
|
72
|
+
if (hapticIntervalRef.current) {
|
|
73
|
+
clearInterval(hapticIntervalRef.current);
|
|
74
|
+
hapticIntervalRef.current = null;
|
|
75
|
+
}
|
|
76
|
+
}, []);
|
|
77
|
+
return {
|
|
78
|
+
fireDiscreteHaptic,
|
|
79
|
+
startContinuousHaptic,
|
|
80
|
+
stopContinuousHaptic
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=useHaptics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","_reactNative","_defaults","ExpoHaptics","useHaptics","enableHaptics","onHapticTrigger","continuousHapticIntervalMs","DEFAULTS","hapticIntervalRef","useRef","fireDiscreteHaptic","useCallback","Platform","OS","impactAsync","ImpactFeedbackStyle","Light","catch","selectionAsync","startContinuousHaptic","current","interval","setInterval","stopContinuousHaptic","clearInterval"],"sourceRoot":"../../src","sources":["useHaptics.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,SAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA,IAAIG,WAAiD,GAAG,IAAI;AAC5D,IAAI;EACFA,WAAW,GAAGH,OAAO,CAAC,cAAc,CAAC;AACvC,CAAC,CAAC,MAAM;EACN;AAAA;AAeF;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASI,UAAUA,CAAC;EACzBC,aAAa;EACbC,eAAe;EACfC,0BAA0B,GAAGC,kBAAQ,CAACD;AACrB,CAAC,EAAc;EAChC,MAAME,iBAAiB,GAAG,IAAAC,aAAM,EAC9B,IACF,CAAC;;EAED;EACA,MAAMC,kBAAkB,GAAG,IAAAC,kBAAW,EAAC,MAAM;IAC3C,IAAI,CAACP,aAAa,EAAE;IAEpB,IAAIC,eAAe,EAAE;MACnBA,eAAe,CAAC,MAAM,CAAC;MACvB;IACF;IAEA,IAAI,CAACH,WAAW,EAAE;IAElB,IAAIU,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;MAC7BX,WAAW,CAACY,WAAW,CAACZ,WAAW,CAACa,mBAAmB,CAACC,KAAK,CAAC,CAACC,KAAK,CAClE,MAAM,CAAC,CACT,CAAC;IACH,CAAC,MAAM;MACLf,WAAW,CAACgB,cAAc,CAAC,CAAC,CAACD,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C;EACF,CAAC,EAAE,CAACb,aAAa,EAAEC,eAAe,CAAC,CAAC;;EAEpC;EACA,MAAMc,qBAAqB,GAAG,IAAAR,kBAAW,EAAC,MAAM;IAC9C,IAAI,CAACP,aAAa,EAAE;IAEpB,IAAIC,eAAe,EAAE;MACnBA,eAAe,CAAC,YAAY,CAAC;MAC7B;IACF;IAEA,IAAI,CAACH,WAAW,EAAE;;IAElB;IACA,IAAIM,iBAAiB,CAACY,OAAO,EAAE;;IAE/B;IACAlB,WAAW,CAACY,WAAW,CAACZ,WAAW,CAACa,mBAAmB,CAACC,KAAK,CAAC,CAACC,KAAK,CAClE,MAAM,CAAC,CACT,CAAC;IAED,MAAMI,QAAQ,GACZT,qBAAQ,CAACC,EAAE,KAAK,SAAS,GAAG,EAAE,GAAGP,0BAA0B;IAE7DE,iBAAiB,CAACY,OAAO,GAAGE,WAAW,CAAC,MAAM;MAC5CpB,WAAW,CAAEY,WAAW,CAACZ,WAAW,CAAEa,mBAAmB,CAACC,KAAK,CAAC,CAACC,KAAK,CACpE,MAAM,CAAC,CACT,CAAC;IACH,CAAC,EAAEI,QAAQ,CAAC;EACd,CAAC,EAAE,CAACjB,aAAa,EAAEC,eAAe,EAAEC,0BAA0B,CAAC,CAAC;;EAEhE;EACA,MAAMiB,oBAAoB,GAAG,IAAAZ,kBAAW,EAAC,MAAM;IAC7C,IAAIH,iBAAiB,CAACY,OAAO,EAAE;MAC7BI,aAAa,CAAChB,iBAAiB,CAACY,OAAO,CAAC;MACxCZ,iBAAiB,CAACY,OAAO,GAAG,IAAI;IAClC;EACF,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;IACLV,kBAAkB;IAClBS,qBAAqB;IACrBI;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.computeDayRange = computeDayRange;
|
|
7
|
+
exports.dateToDayOffset = dateToDayOffset;
|
|
8
|
+
exports.dayOffsetToDate = dayOffsetToDate;
|
|
9
|
+
exports.formatDateString = formatDateString;
|
|
10
|
+
exports.shouldShowLabel = shouldShowLabel;
|
|
11
|
+
exports.useResolvedColors = useResolvedColors;
|
|
12
|
+
var _reactNative = require("react-native");
|
|
13
|
+
var _defaults = require("./defaults");
|
|
14
|
+
/**
|
|
15
|
+
* Formats a Date object as a local YYYY-MM-DD string,
|
|
16
|
+
* avoiding timezone shifting bugs caused by toISOString().
|
|
17
|
+
*/
|
|
18
|
+
function formatDateString(date = new Date()) {
|
|
19
|
+
const year = date.getFullYear();
|
|
20
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
21
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
22
|
+
return `${year}-${month}-${day}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Converts a Date or YYYY-MM-DD string to a day offset relative to a reference time.
|
|
27
|
+
*/
|
|
28
|
+
function dateToDayOffset(date, referenceTime) {
|
|
29
|
+
const d = typeof date === 'string' ? new Date(date) : new Date(date);
|
|
30
|
+
d.setHours(0, 0, 0, 0);
|
|
31
|
+
return Math.round((d.getTime() - referenceTime) / _defaults.MS_PER_DAY);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Converts a day offset back to a Date object.
|
|
36
|
+
*/
|
|
37
|
+
function dayOffsetToDate(offset, referenceTime) {
|
|
38
|
+
return new Date(referenceTime + offset * _defaults.MS_PER_DAY);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolves user-provided color props against the system color scheme defaults.
|
|
43
|
+
* User-provided values always take precedence.
|
|
44
|
+
*/
|
|
45
|
+
function useResolvedColors(props) {
|
|
46
|
+
const scheme = (0, _reactNative.useColorScheme)();
|
|
47
|
+
const palette = scheme === 'dark' ? _defaults.DARK_COLORS : _defaults.LIGHT_COLORS;
|
|
48
|
+
return {
|
|
49
|
+
tickColor: props.tickColor ?? palette.tickColor,
|
|
50
|
+
tickTallColor: props.tickTallColor ?? props.tickColor ?? palette.tickTallColor,
|
|
51
|
+
labelColor: props.labelColor ?? palette.labelColor,
|
|
52
|
+
accentColor: props.accentColor ?? palette.accentColor,
|
|
53
|
+
indicatorColor: props.indicatorColor ?? palette.indicatorColor,
|
|
54
|
+
backgroundColor: props.backgroundColor ?? palette.backgroundColor
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determines whether a date should display a label based on the labelInterval setting.
|
|
60
|
+
*/
|
|
61
|
+
function shouldShowLabel(date, labelInterval, todayTime) {
|
|
62
|
+
if (!labelInterval || labelInterval === 'weekly') {
|
|
63
|
+
// Default: every 7th day relative to today (matches original Friday-style spacing)
|
|
64
|
+
const dayOffset = Math.round((date.getTime() - todayTime) / _defaults.MS_PER_DAY);
|
|
65
|
+
return dayOffset % 7 === 0;
|
|
66
|
+
}
|
|
67
|
+
if (labelInterval === 'daily') {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (labelInterval === 'monthly') {
|
|
71
|
+
return date.getDate() === 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Custom callback
|
|
75
|
+
return labelInterval(date);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Computes the min/max day offsets from props or defaults.
|
|
80
|
+
*/
|
|
81
|
+
function computeDayRange(todayTime, minDate, maxDate) {
|
|
82
|
+
let minOffset = -_defaults.DEFAULT_DAY_RANGE;
|
|
83
|
+
let maxOffset = _defaults.DEFAULT_DAY_RANGE;
|
|
84
|
+
if (minDate) {
|
|
85
|
+
const d = new Date(minDate);
|
|
86
|
+
d.setHours(0, 0, 0, 0);
|
|
87
|
+
minOffset = Math.round((d.getTime() - todayTime) / _defaults.MS_PER_DAY);
|
|
88
|
+
}
|
|
89
|
+
if (maxDate) {
|
|
90
|
+
const d = new Date(maxDate);
|
|
91
|
+
d.setHours(0, 0, 0, 0);
|
|
92
|
+
maxOffset = Math.round((d.getTime() - todayTime) / _defaults.MS_PER_DAY);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
minOffset,
|
|
96
|
+
maxOffset
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_defaults","formatDateString","date","Date","year","getFullYear","month","String","getMonth","padStart","day","getDate","dateToDayOffset","referenceTime","d","setHours","Math","round","getTime","MS_PER_DAY","dayOffsetToDate","offset","useResolvedColors","props","scheme","useColorScheme","palette","DARK_COLORS","LIGHT_COLORS","tickColor","tickTallColor","labelColor","accentColor","indicatorColor","backgroundColor","shouldShowLabel","labelInterval","todayTime","dayOffset","computeDayRange","minDate","maxDate","minOffset","DEFAULT_DAY_RANGE","maxOffset"],"sourceRoot":"../../src","sources":["utils.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useState, useRef, useCallback, useMemo } from 'react';
|
|
4
|
+
import { View, Text, StyleSheet, Dimensions, TouchableOpacity } from 'react-native';
|
|
5
|
+
import Animated, { useSharedValue, useAnimatedStyle, withDecay, withTiming, useAnimatedReaction, runOnJS } from 'react-native-reanimated';
|
|
6
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
7
|
+
import { DEFAULTS, MS_PER_DAY } from './defaults';
|
|
8
|
+
import { formatDateString, dateToDayOffset, dayOffsetToDate, useResolvedColors, shouldShowLabel, computeDayRange } from './utils';
|
|
9
|
+
import { useHaptics } from './useHaptics';
|
|
10
|
+
import { Tick } from './Tick';
|
|
11
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
|
+
const SCREEN_WIDTH = Dimensions.get('window').width;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A performant, customizable ruler-style date picker for React Native.
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - 60 FPS scrolling via Reanimated 3 decay physics + snap alignment
|
|
19
|
+
* - Dual-speed haptic feedback engine (discrete ticks vs continuous buzz)
|
|
20
|
+
* - Windowed tick rendering for memory efficiency
|
|
21
|
+
* - Fully configurable dimensions, colors, and behaviors
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <RulerDatePicker
|
|
26
|
+
* selectedDate={new Date()}
|
|
27
|
+
* onSelectDate={(date, dateString) => console.log(dateString)}
|
|
28
|
+
* />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function RulerDatePicker(props) {
|
|
32
|
+
const {
|
|
33
|
+
selectedDate,
|
|
34
|
+
onSelectDate,
|
|
35
|
+
minDate,
|
|
36
|
+
maxDate,
|
|
37
|
+
labelInterval,
|
|
38
|
+
highlightDays,
|
|
39
|
+
tickSpacing = DEFAULTS.tickSpacing,
|
|
40
|
+
tickHeight = DEFAULTS.tickHeight,
|
|
41
|
+
tickTallHeight = DEFAULTS.tickTallHeight,
|
|
42
|
+
tickThickness = DEFAULTS.tickThickness,
|
|
43
|
+
height = DEFAULTS.height,
|
|
44
|
+
rulerHeight = DEFAULTS.rulerHeight,
|
|
45
|
+
indicatorWidth = DEFAULTS.indicatorWidth,
|
|
46
|
+
indicatorHeight = DEFAULTS.indicatorHeight,
|
|
47
|
+
todayDotSize = DEFAULTS.todayDotSize,
|
|
48
|
+
labelFontSize = DEFAULTS.labelFontSize,
|
|
49
|
+
bufferTicks = DEFAULTS.bufferTicks,
|
|
50
|
+
updateDebounceMs = DEFAULTS.updateDebounceMs,
|
|
51
|
+
enableHaptics = DEFAULTS.enableHaptics,
|
|
52
|
+
onHapticTrigger,
|
|
53
|
+
fastSwipeTickThreshold = DEFAULTS.fastSwipeTickThreshold,
|
|
54
|
+
continuousHapticIntervalMs = DEFAULTS.continuousHapticIntervalMs,
|
|
55
|
+
showResetToToday = DEFAULTS.showResetToToday,
|
|
56
|
+
renderHeader
|
|
57
|
+
} = props;
|
|
58
|
+
|
|
59
|
+
// ── Resolve colors ──────────────────────────────────────────────────────
|
|
60
|
+
const colors = useResolvedColors(props);
|
|
61
|
+
|
|
62
|
+
// ── Haptics ─────────────────────────────────────────────────────────────
|
|
63
|
+
const {
|
|
64
|
+
fireDiscreteHaptic,
|
|
65
|
+
startContinuousHaptic,
|
|
66
|
+
stopContinuousHaptic
|
|
67
|
+
} = useHaptics({
|
|
68
|
+
enableHaptics,
|
|
69
|
+
onHapticTrigger,
|
|
70
|
+
continuousHapticIntervalMs
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ── Reference time (midnight today) ─────────────────────────────────────
|
|
74
|
+
const todayTime = useMemo(() => {
|
|
75
|
+
const d = new Date();
|
|
76
|
+
d.setHours(0, 0, 0, 0);
|
|
77
|
+
return d.getTime();
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
// ── Date boundaries ─────────────────────────────────────────────────────
|
|
81
|
+
const {
|
|
82
|
+
minOffset,
|
|
83
|
+
maxOffset
|
|
84
|
+
} = useMemo(() => computeDayRange(todayTime, minDate, maxDate), [todayTime, minDate, maxDate]);
|
|
85
|
+
|
|
86
|
+
// ── Initial offset from today ───────────────────────────────────────────
|
|
87
|
+
const initialOffsetDays = useMemo(() => {
|
|
88
|
+
return dateToDayOffset(selectedDate, todayTime);
|
|
89
|
+
// Intentionally only computed once on mount
|
|
90
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
91
|
+
}, []);
|
|
92
|
+
const halfVisible = Math.ceil(SCREEN_WIDTH / 2 / tickSpacing);
|
|
93
|
+
const windowSize = halfVisible + bufferTicks;
|
|
94
|
+
|
|
95
|
+
// ── Animated values ─────────────────────────────────────────────────────
|
|
96
|
+
const translateX = useSharedValue(-initialOffsetDays * tickSpacing);
|
|
97
|
+
const contextX = useSharedValue(0);
|
|
98
|
+
const previousIndex = useSharedValue(-initialOffsetDays);
|
|
99
|
+
const isFastMode = useSharedValue(false);
|
|
100
|
+
|
|
101
|
+
// ── State ───────────────────────────────────────────────────────────────
|
|
102
|
+
const initialDateStr = useMemo(() => {
|
|
103
|
+
const d = typeof selectedDate === 'string' ? new Date(selectedDate) : new Date(selectedDate);
|
|
104
|
+
d.setHours(0, 0, 0, 0);
|
|
105
|
+
return formatDateString(d);
|
|
106
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
107
|
+
}, []);
|
|
108
|
+
const [displayDateStr, setDisplayDateStr] = useState(initialDateStr);
|
|
109
|
+
const debounceTimerRef = useRef(null);
|
|
110
|
+
const [windowCenter, setWindowCenter] = useState(-initialOffsetDays);
|
|
111
|
+
|
|
112
|
+
// ── Visible ticks (windowed rendering) ──────────────────────────────────
|
|
113
|
+
const visibleTicks = useMemo(() => {
|
|
114
|
+
const ticks = [];
|
|
115
|
+
const start = Math.max(windowCenter - windowSize, minOffset);
|
|
116
|
+
const end = Math.min(windowCenter + windowSize, maxOffset);
|
|
117
|
+
for (let i = start; i <= end; i++) {
|
|
118
|
+
const d = new Date(todayTime + i * MS_PER_DAY);
|
|
119
|
+
ticks.push({
|
|
120
|
+
offset: i,
|
|
121
|
+
isLabeled: shouldShowLabel(d, labelInterval, todayTime),
|
|
122
|
+
isToday: i === 0,
|
|
123
|
+
isHighlighted: highlightDays ? highlightDays.includes(d.getDay()) : false,
|
|
124
|
+
dateStr: d.getDate().toString()
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return ticks;
|
|
128
|
+
}, [windowCenter, windowSize, todayTime, minOffset, maxOffset, labelInterval, highlightDays]);
|
|
129
|
+
|
|
130
|
+
// ── Tick change callbacks ───────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
const onTickChanged = useCallback((index, enteringFastMode) => {
|
|
133
|
+
if (enteringFastMode) {
|
|
134
|
+
startContinuousHaptic();
|
|
135
|
+
} else {
|
|
136
|
+
stopContinuousHaptic();
|
|
137
|
+
fireDiscreteHaptic();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Update display date
|
|
141
|
+
const d = dayOffsetToDate(index, todayTime);
|
|
142
|
+
const dateStr = formatDateString(d);
|
|
143
|
+
setWindowCenter(prevCenter => {
|
|
144
|
+
if (Math.abs(index - prevCenter) >= 5) {
|
|
145
|
+
return index;
|
|
146
|
+
}
|
|
147
|
+
return prevCenter;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Debounce the heavy onSelectDate callback
|
|
151
|
+
if (debounceTimerRef.current) {
|
|
152
|
+
clearTimeout(debounceTimerRef.current);
|
|
153
|
+
}
|
|
154
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
155
|
+
onSelectDate(d, dateStr);
|
|
156
|
+
}, updateDebounceMs);
|
|
157
|
+
}, [todayTime, onSelectDate, updateDebounceMs, startContinuousHaptic, stopContinuousHaptic, fireDiscreteHaptic]);
|
|
158
|
+
const onAnimationSettled = useCallback(index => {
|
|
159
|
+
stopContinuousHaptic();
|
|
160
|
+
fireDiscreteHaptic();
|
|
161
|
+
const d = dayOffsetToDate(index, todayTime);
|
|
162
|
+
const dateStr = formatDateString(d);
|
|
163
|
+
setDisplayDateStr(dateStr);
|
|
164
|
+
setWindowCenter(index);
|
|
165
|
+
onSelectDate(d, dateStr);
|
|
166
|
+
}, [todayTime, onSelectDate, stopContinuousHaptic, fireDiscreteHaptic]);
|
|
167
|
+
|
|
168
|
+
// ── Animated reaction ───────────────────────────────────────────────────
|
|
169
|
+
useAnimatedReaction(() => Math.round(-translateX.value / tickSpacing), (index, prev) => {
|
|
170
|
+
if (index !== prev && index >= minOffset && index <= maxOffset) {
|
|
171
|
+
previousIndex.value = index;
|
|
172
|
+
const ticksSkipped = prev !== null ? Math.abs(index - prev) : 1;
|
|
173
|
+
const shouldBeFast = ticksSkipped > fastSwipeTickThreshold;
|
|
174
|
+
if (shouldBeFast && !isFastMode.value) {
|
|
175
|
+
isFastMode.value = true;
|
|
176
|
+
runOnJS(onTickChanged)(index, true);
|
|
177
|
+
} else if (!shouldBeFast && isFastMode.value) {
|
|
178
|
+
isFastMode.value = false;
|
|
179
|
+
runOnJS(onTickChanged)(index, false);
|
|
180
|
+
} else if (!shouldBeFast) {
|
|
181
|
+
runOnJS(onTickChanged)(index, false);
|
|
182
|
+
}
|
|
183
|
+
if (shouldBeFast && isFastMode.value) {
|
|
184
|
+
runOnJS(onTickChanged)(index, true);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}, [tickSpacing, minOffset, maxOffset, fastSwipeTickThreshold]);
|
|
188
|
+
|
|
189
|
+
// ── Pan gesture ─────────────────────────────────────────────────────────
|
|
190
|
+
const pan = Gesture.Pan().onStart(() => {
|
|
191
|
+
contextX.value = translateX.value;
|
|
192
|
+
}).onUpdate(event => {
|
|
193
|
+
translateX.value = contextX.value + event.translationX;
|
|
194
|
+
}).onEnd(event => {
|
|
195
|
+
translateX.value = withDecay({
|
|
196
|
+
velocity: event.velocityX,
|
|
197
|
+
deceleration: 0.99
|
|
198
|
+
}, finished => {
|
|
199
|
+
if (finished) {
|
|
200
|
+
const maxTranslateX = -minOffset * tickSpacing;
|
|
201
|
+
const minTranslateX = -maxOffset * tickSpacing;
|
|
202
|
+
const clampedX = Math.min(Math.max(translateX.value, minTranslateX), maxTranslateX);
|
|
203
|
+
const snappedIndex = Math.round(clampedX / tickSpacing);
|
|
204
|
+
const snappedX = snappedIndex * tickSpacing;
|
|
205
|
+
translateX.value = withTiming(snappedX, {
|
|
206
|
+
duration: 150
|
|
207
|
+
}, done => {
|
|
208
|
+
if (done) {
|
|
209
|
+
isFastMode.value = false;
|
|
210
|
+
const index = Math.round(-snappedX / tickSpacing);
|
|
211
|
+
runOnJS(onAnimationSettled)(index);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
218
|
+
transform: [{
|
|
219
|
+
translateX: translateX.value
|
|
220
|
+
}]
|
|
221
|
+
}), [translateX]);
|
|
222
|
+
|
|
223
|
+
// ── Header ──────────────────────────────────────────────────────────────
|
|
224
|
+
const displayDate = new Date(displayDateStr);
|
|
225
|
+
const displayFormat = displayDate.toLocaleDateString('en-US', {
|
|
226
|
+
weekday: 'long',
|
|
227
|
+
month: 'long',
|
|
228
|
+
day: 'numeric'
|
|
229
|
+
});
|
|
230
|
+
const displayYear = displayDate.getFullYear();
|
|
231
|
+
const currentYear = new Date().getFullYear();
|
|
232
|
+
const showYear = displayYear !== currentYear;
|
|
233
|
+
const isTodaySelected = displayDateStr === formatDateString(new Date(todayTime));
|
|
234
|
+
const handleResetToToday = useCallback(() => {
|
|
235
|
+
stopContinuousHaptic();
|
|
236
|
+
translateX.value = withTiming(0, {
|
|
237
|
+
duration: 300
|
|
238
|
+
});
|
|
239
|
+
const todayStr = formatDateString(new Date(todayTime));
|
|
240
|
+
setDisplayDateStr(todayStr);
|
|
241
|
+
setWindowCenter(0);
|
|
242
|
+
onSelectDate(new Date(todayTime), todayStr);
|
|
243
|
+
}, [todayTime, onSelectDate, stopContinuousHaptic, translateX]);
|
|
244
|
+
|
|
245
|
+
// ── Render ──────────────────────────────────────────────────────────────
|
|
246
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
247
|
+
style: [styles.container, {
|
|
248
|
+
height,
|
|
249
|
+
backgroundColor: colors.backgroundColor
|
|
250
|
+
}],
|
|
251
|
+
children: [renderHeader ? renderHeader(displayDate, isTodaySelected, handleResetToToday) : /*#__PURE__*/_jsxs(View, {
|
|
252
|
+
style: styles.headerContainer,
|
|
253
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
254
|
+
style: styles.dateHeader,
|
|
255
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
256
|
+
style: [styles.yearText, {
|
|
257
|
+
color: colors.labelColor
|
|
258
|
+
}],
|
|
259
|
+
children: showYear ? displayYear : ''
|
|
260
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
261
|
+
style: [styles.dateText, {
|
|
262
|
+
color: colors.accentColor
|
|
263
|
+
}],
|
|
264
|
+
children: displayFormat
|
|
265
|
+
})]
|
|
266
|
+
}), showResetToToday && !isTodaySelected && /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
267
|
+
onPress: handleResetToToday,
|
|
268
|
+
style: styles.resetBtn,
|
|
269
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
270
|
+
style: [styles.resetText, {
|
|
271
|
+
color: colors.accentColor
|
|
272
|
+
}],
|
|
273
|
+
children: "Today"
|
|
274
|
+
})
|
|
275
|
+
})]
|
|
276
|
+
}), /*#__PURE__*/_jsx(GestureDetector, {
|
|
277
|
+
gesture: pan,
|
|
278
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
279
|
+
style: [styles.rulerContainer, {
|
|
280
|
+
height: rulerHeight
|
|
281
|
+
}],
|
|
282
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
283
|
+
style: [styles.centerIndicator, {
|
|
284
|
+
backgroundColor: colors.indicatorColor,
|
|
285
|
+
width: indicatorWidth,
|
|
286
|
+
height: indicatorHeight
|
|
287
|
+
}]
|
|
288
|
+
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
289
|
+
style: [styles.ticksWrapper, animatedStyle],
|
|
290
|
+
children: visibleTicks.map(tick => /*#__PURE__*/_jsx(Tick, {
|
|
291
|
+
offset: tick.offset,
|
|
292
|
+
isLabeled: tick.isLabeled,
|
|
293
|
+
isToday: tick.isToday,
|
|
294
|
+
isHighlighted: tick.isHighlighted,
|
|
295
|
+
dateStr: tick.dateStr,
|
|
296
|
+
tickSpacing: tickSpacing,
|
|
297
|
+
tickHeight: tickHeight,
|
|
298
|
+
tickTallHeight: tickTallHeight,
|
|
299
|
+
tickThickness: tickThickness,
|
|
300
|
+
tickColor: colors.tickColor,
|
|
301
|
+
tickTallColor: colors.tickTallColor,
|
|
302
|
+
labelColor: colors.labelColor,
|
|
303
|
+
accentColor: colors.accentColor,
|
|
304
|
+
todayDotSize: todayDotSize,
|
|
305
|
+
labelFontSize: labelFontSize,
|
|
306
|
+
rulerHeight: rulerHeight
|
|
307
|
+
}, tick.offset))
|
|
308
|
+
})]
|
|
309
|
+
})
|
|
310
|
+
})]
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
const styles = StyleSheet.create({
|
|
314
|
+
container: {
|
|
315
|
+
justifyContent: 'center',
|
|
316
|
+
alignItems: 'center',
|
|
317
|
+
overflow: 'hidden'
|
|
318
|
+
},
|
|
319
|
+
headerContainer: {
|
|
320
|
+
flexDirection: 'row',
|
|
321
|
+
alignItems: 'center',
|
|
322
|
+
justifyContent: 'center',
|
|
323
|
+
width: '100%',
|
|
324
|
+
paddingHorizontal: 20,
|
|
325
|
+
marginBottom: 20,
|
|
326
|
+
height: 40
|
|
327
|
+
},
|
|
328
|
+
dateHeader: {
|
|
329
|
+
alignItems: 'center'
|
|
330
|
+
},
|
|
331
|
+
yearText: {
|
|
332
|
+
fontSize: 12,
|
|
333
|
+
fontWeight: '500',
|
|
334
|
+
marginBottom: 2
|
|
335
|
+
},
|
|
336
|
+
dateText: {
|
|
337
|
+
fontSize: 18,
|
|
338
|
+
fontWeight: '600'
|
|
339
|
+
},
|
|
340
|
+
resetBtn: {
|
|
341
|
+
position: 'absolute',
|
|
342
|
+
right: 20,
|
|
343
|
+
paddingVertical: 6,
|
|
344
|
+
paddingHorizontal: 12,
|
|
345
|
+
borderRadius: 16,
|
|
346
|
+
backgroundColor: 'rgba(0,0,0,0.05)'
|
|
347
|
+
},
|
|
348
|
+
resetText: {
|
|
349
|
+
fontSize: 14,
|
|
350
|
+
fontWeight: '600'
|
|
351
|
+
},
|
|
352
|
+
rulerContainer: {
|
|
353
|
+
width: SCREEN_WIDTH,
|
|
354
|
+
position: 'relative',
|
|
355
|
+
flexDirection: 'row',
|
|
356
|
+
alignItems: 'flex-end',
|
|
357
|
+
justifyContent: 'center'
|
|
358
|
+
},
|
|
359
|
+
centerIndicator: {
|
|
360
|
+
position: 'absolute',
|
|
361
|
+
zIndex: 10,
|
|
362
|
+
bottom: 0
|
|
363
|
+
},
|
|
364
|
+
ticksWrapper: {
|
|
365
|
+
position: 'absolute',
|
|
366
|
+
height: '100%',
|
|
367
|
+
width: 0,
|
|
368
|
+
left: SCREEN_WIDTH / 2
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
//# sourceMappingURL=RulerDatePicker.js.map
|