@idealyst/datepicker 11.2.120 → 11.2.121

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": "@idealyst/datepicker",
3
- "version": "11.2.120",
3
+ "version": "11.2.121",
4
4
  "description": "Cross-platform date and time picker components for React and React Native",
5
5
  "documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/datepicker#readme",
6
6
  "readme": "README.md",
@@ -36,7 +36,7 @@
36
36
  "publish:npm": "npm publish"
37
37
  },
38
38
  "peerDependencies": {
39
- "@idealyst/theme": "^11.2.120",
39
+ "@idealyst/theme": "^11.2.121",
40
40
  "@mdi/js": ">=7.0.0",
41
41
  "@mdi/react": ">=1.6.0",
42
42
  "react": ">=16.8.0",
@@ -69,7 +69,7 @@
69
69
  }
70
70
  },
71
71
  "devDependencies": {
72
- "@idealyst/theme": "^11.2.120",
72
+ "@idealyst/theme": "^11.2.121",
73
73
  "@mdi/js": "^7.4.47",
74
74
  "@mdi/react": "^1.6.1",
75
75
  "@types/react": "^19.1.0",
@@ -101,15 +101,21 @@ export const DateInput: React.FC<DateInputProps> = ({
101
101
  )}
102
102
  {pressable ? (
103
103
  <TouchableOpacity
104
- style={inputContainerStyle}
105
104
  onPress={() => !disabled && setOpen(true)}
106
105
  disabled={disabled}
107
106
  activeOpacity={0.7}
108
107
  >
109
- <Text style={[textInputStyle, !value && { color: (styles.pressableText as any)({ disabled, size }).placeholderColor }]}>
110
- {value ? formatDate(value) : placeholder}
111
- </Text>
112
- <MaterialDesignIcons name="calendar" size={iconStyle.width} style={iconStyle} />
108
+ <View style={inputContainerStyle} pointerEvents="none">
109
+ <TextInput
110
+ value={formatDate(value ?? undefined)}
111
+ placeholder={placeholder}
112
+ editable={false}
113
+ style={textInputStyle}
114
+ />
115
+ <View style={iconButtonStyle}>
116
+ <MaterialDesignIcons name="calendar" size={iconStyle.width} style={iconStyle} />
117
+ </View>
118
+ </View>
113
119
  </TouchableOpacity>
114
120
  ) : (
115
121
  <View style={inputContainerStyle}>
@@ -109,29 +109,31 @@ export const DateInput: React.FC<DateInputProps> = ({
109
109
  const errorProps = getWebProps([errorTextStyle]);
110
110
  const popoverProps = getWebProps([popoverContentStyle]);
111
111
 
112
- // Pressable text style (reuses input style but renders as a button)
113
- const pressableTextStyle = (styles.pressableText as any)({ disabled, size });
114
- const pressableTextProps = getWebProps([pressableTextStyle]);
115
-
116
112
  return (
117
113
  <div style={flattenStyle(style)}>
118
114
  {label && (
119
115
  <span {...labelProps}>{label}</span>
120
116
  )}
121
117
  {pressable ? (
122
- <button
123
- type="button"
124
- {...containerProps}
125
- ref={triggerRef as any}
126
- style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
118
+ <div
119
+ ref={triggerRef}
127
120
  onClick={() => !disabled && setOpen(!open)}
128
- disabled={disabled}
121
+ style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
129
122
  >
130
- <span {...pressableTextProps} style={!value ? { color: pressableTextStyle.placeholderColor } : undefined}>
131
- {value ? formatDate(value) : placeholder}
132
- </span>
133
- <IconSvg path={mdiCalendar} size={iconSize} color={iconColor} />
134
- </button>
123
+ <div {...containerProps} style={{ pointerEvents: 'none' }}>
124
+ <input
125
+ type="text"
126
+ value={formatDate(value ?? undefined)}
127
+ placeholder={placeholder}
128
+ readOnly
129
+ tabIndex={-1}
130
+ {...inputProps}
131
+ />
132
+ <div {...iconButtonProps}>
133
+ <IconSvg path={mdiCalendar} size={iconSize} color={iconColor} />
134
+ </div>
135
+ </div>
136
+ </div>
135
137
  ) : (
136
138
  <div {...containerProps} ref={triggerRef}>
137
139
  <input
@@ -81,11 +81,13 @@ export const DatePicker: React.FC<DatePickerProps> = ({
81
81
  days.push({ date: new Date(year, month, day, 12, 0, 0, 0), isCurrentMonth: true });
82
82
  }
83
83
 
84
- // Next month padding (always fill to 42 days = 6 rows for consistent height)
84
+ // Next month padding (fill to complete last week)
85
85
  // Use noon (12:00) to avoid timezone issues when date crosses day boundaries
86
- const totalCells = 42;
87
- for (let day = 1; days.length < totalCells; day++) {
88
- days.push({ date: new Date(year, month + 1, day, 12, 0, 0, 0), isCurrentMonth: false });
86
+ const remaining = 7 - (days.length % 7);
87
+ if (remaining < 7) {
88
+ for (let day = 1; day <= remaining; day++) {
89
+ days.push({ date: new Date(year, month + 1, day, 12, 0, 0, 0), isCurrentMonth: false });
90
+ }
89
91
  }
90
92
 
91
93
  return { days, monthShort: MONTHS[month], year };
@@ -73,10 +73,12 @@ export const datePickerCalendarStyles = defineStyle('DatePickerCalendar', (theme
73
73
  },
74
74
  }),
75
75
 
76
- // Calendar grid
76
+ // Calendar grid - fixed height so rows flex evenly regardless of 5 or 6 weeks
77
77
  calendarGrid: (_props: DatePickerDynamicProps) => ({
78
78
  flexDirection: 'row' as const,
79
79
  flexWrap: 'wrap' as const,
80
+ height: 252, // 6 rows × 42px
81
+ alignContent: 'space-evenly' as const,
80
82
  _web: {
81
83
  display: 'flex',
82
84
  },
@@ -263,15 +265,12 @@ export const datePickerCalendarStyles = defineStyle('DatePickerCalendar', (theme
263
265
  },
264
266
  }),
265
267
 
266
- // Today styling - outlined circle (no fill)
268
+ // Today styling - subtle gray background
267
269
  todayDay: (_props: DatePickerDynamicProps) => ({
268
- borderWidth: 1,
269
- borderColor: theme.intents.primary.primary,
270
270
  borderRadius: 16,
271
- backgroundColor: 'transparent',
271
+ backgroundColor: theme.colors.pallet.gray?.[200] ?? theme.colors.surface.secondary,
272
272
  _web: {
273
- background: 'transparent',
274
- boxSizing: 'border-box',
273
+ background: theme.colors.pallet.gray?.[200] ?? theme.colors.surface.secondary,
275
274
  },
276
275
  }),
277
276
 
@@ -62,11 +62,13 @@ export const DatePicker: React.FC<DatePickerProps> = ({
62
62
  days.push({ date: new Date(year, month, day, 12, 0, 0, 0), isCurrentMonth: true });
63
63
  }
64
64
 
65
- // Next month padding (always fill to 42 days = 6 rows for consistent height)
65
+ // Next month padding (fill to complete last week)
66
66
  // Use noon (12:00) to avoid timezone issues when date crosses day boundaries
67
- const totalCells = 42;
68
- for (let day = 1; days.length < totalCells; day++) {
69
- days.push({ date: new Date(year, month + 1, day, 12, 0, 0, 0), isCurrentMonth: false });
67
+ const remaining = 7 - (days.length % 7);
68
+ if (remaining < 7) {
69
+ for (let day = 1; day <= remaining; day++) {
70
+ days.push({ date: new Date(year, month + 1, day, 12, 0, 0, 0), isCurrentMonth: false });
71
+ }
70
72
  }
71
73
 
72
74
  return { days, monthShort: MONTHS[month], year };
@@ -195,35 +195,6 @@ export const dateTimeInputStyles = defineStyle('DateTimeInput', (theme: Theme) =
195
195
  color: theme.intents.primary.primary,
196
196
  }),
197
197
 
198
- // Pressable text (used when pressable=true instead of a text input)
199
- pressableText: (_props: InputDynamicProps) => ({
200
- flex: 1,
201
- minWidth: 0,
202
- color: theme.colors.text.primary,
203
- fontWeight: '400' as const,
204
- textAlign: 'left' as const,
205
- // Default font size for when size variant isn't specified
206
- fontSize: theme.sizes.input.md.fontSize,
207
- // Placeholder color for native when no value is set
208
- placeholderColor: theme.colors.text.tertiary,
209
- _web: {
210
- overflow: 'hidden',
211
- textOverflow: 'ellipsis',
212
- whiteSpace: 'nowrap',
213
- pointerEvents: 'none',
214
- },
215
- variants: {
216
- disabled: {
217
- true: { color: theme.colors.text.tertiary },
218
- false: { color: theme.colors.text.primary },
219
- },
220
- // $iterator expands for each input size
221
- size: {
222
- fontSize: theme.sizes.$input.fontSize,
223
- },
224
- },
225
- }),
226
-
227
198
  // Icon color helper
228
199
  iconColor: (_props: InputDynamicProps) => ({
229
200
  color: theme.colors.text.secondary,
@@ -121,15 +121,21 @@ export const TimeInput: React.FC<TimeInputProps> = ({
121
121
  )}
122
122
  {pressable ? (
123
123
  <TouchableOpacity
124
- style={inputContainerStyle}
125
124
  onPress={() => !disabled && setOpen(true)}
126
125
  disabled={disabled}
127
126
  activeOpacity={0.7}
128
127
  >
129
- <Text style={[textInputStyle, !value && { color: (styles.pressableText as any)({ disabled, size }).placeholderColor }]}>
130
- {value ? formatTime(value) : placeholder}
131
- </Text>
132
- <MaterialDesignIcons name="clock-outline" size={iconStyle.width} style={iconStyle} />
128
+ <View style={inputContainerStyle} pointerEvents="none">
129
+ <TextInput
130
+ value={formatTime(value ?? undefined)}
131
+ placeholder={placeholder}
132
+ editable={false}
133
+ style={textInputStyle}
134
+ />
135
+ <View style={iconButtonStyle}>
136
+ <MaterialDesignIcons name="clock-outline" size={iconStyle.width} style={iconStyle} />
137
+ </View>
138
+ </View>
133
139
  </TouchableOpacity>
134
140
  ) : (
135
141
  <View style={inputContainerStyle}>
@@ -133,29 +133,31 @@ export const TimeInput: React.FC<TimeInputProps> = ({
133
133
  const errorProps = getWebProps([errorTextStyle]);
134
134
  const popoverProps = getWebProps([popoverContentStyle]);
135
135
 
136
- // Pressable text style (reuses input style but renders as a button)
137
- const pressableTextStyle = (styles.pressableText as any)({ disabled, size });
138
- const pressableTextProps = getWebProps([pressableTextStyle]);
139
-
140
136
  return (
141
137
  <div style={style as React.CSSProperties}>
142
138
  {label && (
143
139
  <span {...labelProps}>{label}</span>
144
140
  )}
145
141
  {pressable ? (
146
- <button
147
- type="button"
148
- {...containerProps}
149
- ref={triggerRef as any}
150
- style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
142
+ <div
143
+ ref={triggerRef}
151
144
  onClick={() => !disabled && setOpen(!open)}
152
- disabled={disabled}
145
+ style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
153
146
  >
154
- <span {...pressableTextProps} style={!value ? { color: pressableTextStyle.placeholderColor } : undefined}>
155
- {value ? formatTime(value) : placeholder}
156
- </span>
157
- <IconSvg path={mdiClockOutline} size={iconSize} color={iconColor} />
158
- </button>
147
+ <div {...containerProps} style={{ pointerEvents: 'none' }}>
148
+ <input
149
+ type="text"
150
+ value={formatTime(value ?? undefined)}
151
+ placeholder={placeholder}
152
+ readOnly
153
+ tabIndex={-1}
154
+ {...inputProps}
155
+ />
156
+ <div {...iconButtonProps}>
157
+ <IconSvg path={mdiClockOutline} size={iconSize} color={iconColor} />
158
+ </div>
159
+ </div>
160
+ </div>
159
161
  ) : (
160
162
  <div {...containerProps} ref={triggerRef}>
161
163
  <input