@elik56a/react-native-pickers 0.0.0-stage → 0.1.1

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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -2
  3. package/lib/date/Calendar.d.ts +89 -0
  4. package/lib/date/Calendar.d.ts.map +1 -0
  5. package/lib/date/Calendar.js +250 -0
  6. package/lib/date/Calendar.js.map +1 -0
  7. package/lib/date/DatePicker.d.ts +14 -0
  8. package/lib/date/DatePicker.d.ts.map +1 -0
  9. package/lib/date/DatePicker.js +17 -0
  10. package/lib/date/DatePicker.js.map +1 -0
  11. package/lib/date/DateWheelPicker.d.ts +29 -0
  12. package/lib/date/DateWheelPicker.d.ts.map +1 -0
  13. package/lib/date/DateWheelPicker.js +83 -0
  14. package/lib/date/DateWheelPicker.js.map +1 -0
  15. package/lib/emoji/EmojiPicker.d.ts +47 -0
  16. package/lib/emoji/EmojiPicker.d.ts.map +1 -0
  17. package/lib/emoji/EmojiPicker.js +161 -0
  18. package/lib/emoji/EmojiPicker.js.map +1 -0
  19. package/lib/emoji/data.d.ts +2 -0
  20. package/lib/emoji/data.d.ts.map +1 -0
  21. package/lib/emoji/data.js +4 -0
  22. package/lib/emoji/data.js.map +1 -0
  23. package/lib/emoji/emojis.d.ts +23 -0
  24. package/lib/emoji/emojis.d.ts.map +1 -0
  25. package/lib/emoji/emojis.js +100 -0
  26. package/lib/emoji/emojis.js.map +1 -0
  27. package/lib/index.d.ts +17 -0
  28. package/lib/index.d.ts.map +1 -0
  29. package/lib/index.js +17 -0
  30. package/lib/index.js.map +1 -0
  31. package/lib/select/SelectList.d.ts +60 -0
  32. package/lib/select/SelectList.d.ts.map +1 -0
  33. package/lib/select/SelectList.js +91 -0
  34. package/lib/select/SelectList.js.map +1 -0
  35. package/lib/select/SelectPicker.d.ts +35 -0
  36. package/lib/select/SelectPicker.d.ts.map +1 -0
  37. package/lib/select/SelectPicker.js +64 -0
  38. package/lib/select/SelectPicker.js.map +1 -0
  39. package/lib/select/filter.d.ts +3 -0
  40. package/lib/select/filter.d.ts.map +1 -0
  41. package/lib/select/filter.js +13 -0
  42. package/lib/select/filter.js.map +1 -0
  43. package/lib/sheet/BottomSheet.d.ts +29 -0
  44. package/lib/sheet/BottomSheet.d.ts.map +1 -0
  45. package/lib/sheet/BottomSheet.js +89 -0
  46. package/lib/sheet/BottomSheet.js.map +1 -0
  47. package/lib/sheet/PickerSheet.d.ts +26 -0
  48. package/lib/sheet/PickerSheet.d.ts.map +1 -0
  49. package/lib/sheet/PickerSheet.js +27 -0
  50. package/lib/sheet/PickerSheet.js.map +1 -0
  51. package/lib/sheet/sheets.d.ts +48 -0
  52. package/lib/sheet/sheets.d.ts.map +1 -0
  53. package/lib/sheet/sheets.js +58 -0
  54. package/lib/sheet/sheets.js.map +1 -0
  55. package/lib/theme.d.ts +81 -0
  56. package/lib/theme.d.ts.map +1 -0
  57. package/lib/theme.js +96 -0
  58. package/lib/theme.js.map +1 -0
  59. package/lib/time/TimePicker.d.ts +41 -0
  60. package/lib/time/TimePicker.d.ts.map +1 -0
  61. package/lib/time/TimePicker.js +105 -0
  62. package/lib/time/TimePicker.js.map +1 -0
  63. package/lib/types.d.ts +9 -0
  64. package/lib/types.d.ts.map +1 -0
  65. package/lib/types.js +2 -0
  66. package/lib/types.js.map +1 -0
  67. package/lib/utils/OwnScroll.d.ts +10 -0
  68. package/lib/utils/OwnScroll.d.ts.map +1 -0
  69. package/lib/utils/OwnScroll.js +13 -0
  70. package/lib/utils/OwnScroll.js.map +1 -0
  71. package/lib/utils/date.d.ts +30 -0
  72. package/lib/utils/date.d.ts.map +1 -0
  73. package/lib/utils/date.js +115 -0
  74. package/lib/utils/date.js.map +1 -0
  75. package/lib/wheel/MultiWheelPicker.d.ts +26 -0
  76. package/lib/wheel/MultiWheelPicker.d.ts.map +1 -0
  77. package/lib/wheel/MultiWheelPicker.js +28 -0
  78. package/lib/wheel/MultiWheelPicker.js.map +1 -0
  79. package/lib/wheel/WheelPicker.d.ts +59 -0
  80. package/lib/wheel/WheelPicker.d.ts.map +1 -0
  81. package/lib/wheel/WheelPicker.js +257 -0
  82. package/lib/wheel/WheelPicker.js.map +1 -0
  83. package/lib/wheel/typeToSelect.d.ts +8 -0
  84. package/lib/wheel/typeToSelect.d.ts.map +1 -0
  85. package/lib/wheel/typeToSelect.js +10 -0
  86. package/lib/wheel/typeToSelect.js.map +1 -0
  87. package/package.json +81 -4
  88. package/src/date/Calendar.tsx +586 -0
  89. package/src/date/DatePicker.tsx +22 -0
  90. package/src/date/DateWheelPicker.tsx +149 -0
  91. package/src/emoji/EmojiPicker.tsx +410 -0
  92. package/src/emoji/data.ts +3 -0
  93. package/src/emoji/emojis.ts +127 -0
  94. package/src/index.ts +16 -0
  95. package/src/select/SelectList.tsx +266 -0
  96. package/src/select/SelectPicker.tsx +203 -0
  97. package/src/select/filter.ts +17 -0
  98. package/src/sheet/BottomSheet.tsx +199 -0
  99. package/src/sheet/PickerSheet.tsx +86 -0
  100. package/src/sheet/sheets.tsx +218 -0
  101. package/src/theme.tsx +160 -0
  102. package/src/time/TimePicker.tsx +199 -0
  103. package/src/types.ts +10 -0
  104. package/src/utils/OwnScroll.tsx +14 -0
  105. package/src/utils/date.ts +131 -0
  106. package/src/wheel/MultiWheelPicker.tsx +96 -0
  107. package/src/wheel/WheelPicker.tsx +534 -0
  108. package/src/wheel/typeToSelect.ts +12 -0
@@ -0,0 +1,131 @@
1
+ /** Pure date helpers. All operate in local time and never mutate inputs. */
2
+
3
+ export const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
4
+ export const startOfMonth = (d: Date) => new Date(d.getFullYear(), d.getMonth(), 1);
5
+ export const daysInMonth = (year: number, month: number) => new Date(year, month + 1, 0).getDate();
6
+
7
+ export function addMonths(d: Date, months: number): Date {
8
+ const target = new Date(d.getFullYear(), d.getMonth() + months, 1);
9
+ const day = Math.min(d.getDate(), daysInMonth(target.getFullYear(), target.getMonth()));
10
+ return new Date(target.getFullYear(), target.getMonth(), day, d.getHours(), d.getMinutes(), d.getSeconds());
11
+ }
12
+
13
+ export const addDays = (d: Date, days: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + days, d.getHours(), d.getMinutes());
14
+
15
+ export const isSameDay = (a?: Date | null, b?: Date | null) =>
16
+ !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
17
+
18
+ export const isSameMonth = (a: Date, b: Date) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
19
+
20
+ export const compareDay = (a: Date, b: Date) => startOfDay(a).getTime() - startOfDay(b).getTime();
21
+
22
+ export function isBetweenDays(d: Date, start?: Date | null, end?: Date | null) {
23
+ if (!start || !end) return false;
24
+ const t = startOfDay(d).getTime();
25
+ return t > startOfDay(start).getTime() && t < startOfDay(end).getTime();
26
+ }
27
+
28
+ export function isOutOfRange(d: Date, min?: Date | null, max?: Date | null) {
29
+ return (!!min && compareDay(d, min) < 0) || (!!max && compareDay(d, max) > 0);
30
+ }
31
+
32
+ export function clampDate(d: Date, min?: Date | null, max?: Date | null) {
33
+ if (min && d.getTime() < min.getTime()) return new Date(min);
34
+ if (max && d.getTime() > max.getTime()) return new Date(max);
35
+ return d;
36
+ }
37
+
38
+ /** `YYYY-MM-DD` key in local time. */
39
+ export const toDateKey = (d: Date) =>
40
+ `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
41
+
42
+ /**
43
+ * 6x7 (or fewer rows) grid of dates for a month view.
44
+ * `firstDayOfWeek`: 0 = Sunday ... 6 = Saturday.
45
+ */
46
+ export function buildMonthGrid(year: number, month: number, firstDayOfWeek = 0, fixedWeeks = true): Date[][] {
47
+ const first = new Date(year, month, 1);
48
+ const lead = (first.getDay() - firstDayOfWeek + 7) % 7;
49
+ const count = daysInMonth(year, month);
50
+ const weeks = fixedWeeks ? 6 : Math.ceil((lead + count) / 7);
51
+ const grid: Date[][] = [];
52
+ for (let w = 0; w < weeks; w++) {
53
+ const row: Date[] = [];
54
+ for (let i = 0; i < 7; i++) row.push(new Date(year, month, 1 - lead + w * 7 + i));
55
+ grid.push(row);
56
+ }
57
+ return grid;
58
+ }
59
+
60
+ // ---------- Locale ----------
61
+
62
+ const fmtCache = new Map<string, Intl.DateTimeFormat>();
63
+ function fmt(locale: string | undefined, opts: Intl.DateTimeFormatOptions) {
64
+ const key = `${locale ?? ''}|${JSON.stringify(opts)}`;
65
+ let f = fmtCache.get(key);
66
+ if (!f) {
67
+ try {
68
+ f = new Intl.DateTimeFormat(locale, opts);
69
+ } catch {
70
+ f = new Intl.DateTimeFormat('en-US', opts);
71
+ }
72
+ fmtCache.set(key, f);
73
+ }
74
+ return f;
75
+ }
76
+
77
+ const EN_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
78
+ const EN_DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
79
+
80
+ function safe<T>(fn: () => T, fallback: T): T {
81
+ try {
82
+ const v = fn();
83
+ return v ?? fallback;
84
+ } catch {
85
+ return fallback;
86
+ }
87
+ }
88
+
89
+ export function getMonthNames(locale?: string, width: 'long' | 'short' = 'long'): string[] {
90
+ return EN_MONTHS.map((en, m) => safe(() => fmt(locale, { month: width }).format(new Date(2021, m, 1)), width === 'long' ? en : en.slice(0, 3)));
91
+ }
92
+
93
+ /** Weekday names indexed by JS day (0 = Sunday). */
94
+ export function getWeekdayNames(locale?: string, width: 'long' | 'short' | 'narrow' = 'short'): string[] {
95
+ // 2021-08-01 is a Sunday
96
+ return EN_DAYS.map((en, i) => safe(() => fmt(locale, { weekday: width }).format(new Date(2021, 7, 1 + i)), en));
97
+ }
98
+
99
+ export function formatMonthYear(d: Date, locale?: string) {
100
+ return safe(() => fmt(locale, { month: 'long', year: 'numeric' }).format(d), `${EN_MONTHS[d.getMonth()]} ${d.getFullYear()}`);
101
+ }
102
+
103
+ export function formatDate(d: Date, locale?: string, opts: Intl.DateTimeFormatOptions = { dateStyle: 'medium' } as Intl.DateTimeFormatOptions) {
104
+ return safe(() => fmt(locale, opts).format(d), toDateKey(d));
105
+ }
106
+
107
+ /** True when the locale prefers a 12-hour clock. */
108
+ export function uses12HourClock(locale?: string): boolean {
109
+ return safe(() => {
110
+ const parts = fmt(locale, { hour: 'numeric' }).formatToParts(new Date(2021, 0, 1, 15));
111
+ return parts.some((p) => p.type === 'dayPeriod');
112
+ }, false);
113
+ }
114
+
115
+ /** Best-effort first day of week from the locale (Intl.Locale weekInfo). */
116
+ export function getFirstDayOfWeek(locale?: string): number {
117
+ return safe(() => {
118
+ const L = (Intl as any).Locale;
119
+ if (!L || !locale) return 0;
120
+ const loc = new L(locale);
121
+ const info = loc.getWeekInfo?.() ?? loc.weekInfo;
122
+ if (!info?.firstDay) return 0;
123
+ return info.firstDay % 7; // Intl uses 1 = Monday ... 7 = Sunday
124
+ }, 0);
125
+ }
126
+
127
+ export function getDayPeriods(locale?: string): [string, string] {
128
+ const get = (h: number, fb: string) =>
129
+ safe(() => fmt(locale, { hour: 'numeric', hour12: true }).formatToParts(new Date(2021, 0, 1, h)).find((p) => p.type === 'dayPeriod')?.value ?? fb, fb);
130
+ return [get(9, 'AM'), get(15, 'PM')];
131
+ }
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import { StyleSheet, Text, View } from 'react-native';
3
+ import type { StyleProp, ViewStyle } from 'react-native';
4
+ import { textStyle, usePickerTheme } from '../theme';
5
+ import type { SlotStyles, ThemableProps } from '../types';
6
+ import { WheelPicker } from './WheelPicker';
7
+ import type { WheelPickerProps, WheelPickerSlot } from './WheelPicker';
8
+
9
+ export type WheelColumn<T = any> = Omit<WheelPickerProps<T>, 'itemHeight' | 'visibleItems' | 'variant' | 'showIndicator' | 'theme'> & {
10
+ key: string;
11
+ /** Flex weight of the column. Default: 1 */
12
+ flex?: number;
13
+ /** Fixed column width */
14
+ width?: number;
15
+ };
16
+
17
+ export type MultiWheelSlot = 'container' | 'indicator' | 'separator' | WheelPickerSlot;
18
+
19
+ export interface MultiWheelPickerProps extends ThemableProps {
20
+ columns: WheelColumn[];
21
+ /** Text/node rendered between columns, e.g. ':' for time */
22
+ separator?: React.ReactNode | ((leftIndex: number) => React.ReactNode);
23
+ itemHeight?: number;
24
+ visibleItems?: number;
25
+ variant?: '3d' | 'flat';
26
+ style?: StyleProp<ViewStyle>;
27
+ styles?: SlotStyles<MultiWheelSlot>;
28
+ testID?: string;
29
+ }
30
+
31
+ /** Several wheels sharing one selection band (time, date, units...). */
32
+ export function MultiWheelPicker({
33
+ columns,
34
+ separator,
35
+ itemHeight = 40,
36
+ visibleItems = 5,
37
+ variant = '3d',
38
+ style,
39
+ styles: slots,
40
+ theme: themeOverride,
41
+ testID,
42
+ }: MultiWheelPickerProps) {
43
+ const theme = usePickerTheme(themeOverride);
44
+ const vis = visibleItems % 2 === 0 ? visibleItems + 1 : visibleItems;
45
+ return (
46
+ <View style={[{ height: itemHeight * vis }, style, slots?.container]} testID={testID}>
47
+ <View pointerEvents="none" style={[StyleSheet.absoluteFill, { justifyContent: 'center' }]}>
48
+ <View
49
+ style={[
50
+ { height: itemHeight, borderRadius: theme.radius.md, backgroundColor: theme.colors.indicator, marginHorizontal: theme.spacing.xs },
51
+ slots?.indicator,
52
+ ]}
53
+ />
54
+ </View>
55
+ <View style={s.row}>
56
+ {columns.map(({ key, flex, width, styles: colSlots, ...col }, i) => {
57
+ const sep = i > 0 && separator !== undefined ? (typeof separator === 'function' ? separator(i - 1) : separator) : null;
58
+ return (
59
+ <React.Fragment key={key}>
60
+ {sep !== null && sep !== undefined && sep !== false ? (
61
+ <View style={s.sep} pointerEvents="none">
62
+ {typeof sep === 'string' ? (
63
+ <Text style={[textStyle(theme, 'lg', 'bold'), slots?.separator]}>{sep}</Text>
64
+ ) : (
65
+ sep
66
+ )}
67
+ </View>
68
+ ) : null}
69
+ <WheelPicker
70
+ {...col}
71
+ theme={themeOverride}
72
+ itemHeight={itemHeight}
73
+ visibleItems={vis}
74
+ variant={variant}
75
+ showIndicator={false}
76
+ style={[width !== undefined ? { width } : { flex: flex ?? 1 }, col.style]}
77
+ styles={{
78
+ item: slots?.item,
79
+ itemText: slots?.itemText,
80
+ selectedItemText: slots?.selectedItemText,
81
+ disabledItemText: slots?.disabledItemText,
82
+ ...colSlots,
83
+ }}
84
+ />
85
+ </React.Fragment>
86
+ );
87
+ })}
88
+ </View>
89
+ </View>
90
+ );
91
+ }
92
+
93
+ const s = StyleSheet.create({
94
+ row: { flexDirection: 'row', flex: 1 },
95
+ sep: { justifyContent: 'center', paddingHorizontal: 2 },
96
+ });