Skip to content

Commit 10e3c33

Browse files
committed
feat: Add custom classes support for next and previous buttons (resolves #883)
- refactor: Deprecate custom class props in favor of `ui` prop
1 parent 0ab075a commit 10e3c33

File tree

11 files changed

+93
-4
lines changed

11 files changed

+93
-4
lines changed

index.d.ts

+24
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ export interface RangeConfig {
107107
autoRange?: string | number;
108108
}
109109

110+
export type CustomClass = string | string[];
111+
112+
export interface UIOptions {
113+
navBtnNext: CustomClass;
114+
navBtnPrev: CustomClass;
115+
calendar: CustomClass;
116+
calendarCell: CustomClass;
117+
menu: CustomClass;
118+
input: CustomClass;
119+
}
120+
110121
export interface VueDatePickerProps {
111122
uid?: string;
112123
name?: string;
@@ -136,9 +147,21 @@ export interface VueDatePickerProps {
136147
required?: boolean;
137148
format?: string | ((date: Date) => string) | ((dates: Date[]) => string);
138149
previewFormat?: string | ((date: Date) => string) | ((dates: Date[]) => string);
150+
/**
151+
* @deprecated
152+
*/
139153
inputClassName?: string;
154+
/**
155+
* @deprecated
156+
*/
140157
menuClassName?: string;
158+
/**
159+
* @deprecated
160+
*/
141161
calendarClassName?: string;
162+
/**
163+
* @deprecated
164+
*/
142165
calendarCellClassName?: string;
143166
hideInputIcon?: boolean;
144167
state?: boolean;
@@ -331,6 +354,7 @@ export interface VueDatePickerProps {
331354
loading?: boolean;
332355
onInternalModelChange?: (...args: any[]) => void;
333356
enableMinutes?: boolean;
357+
ui?: Partial<UIOptions>;
334358
}
335359

336360
export type DatePickerInstance = ComponentPublicInstance<PublicMethods> | null;

src/VueDatePicker/components/DatePicker/DpCalendar.vue

+2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
defaultedMultiCalendars,
176176
defaultedWeekNumbers,
177177
defaultedMultiDates,
178+
defaultedUI,
178179
} = useDefaults(props);
179180
180181
const showMakerTooltip = ref<Date | null>(null);
@@ -240,6 +241,7 @@
240241
const calendarWrapClass = computed(
241242
(): DynamicClass => ({
242243
[props.calendarClassName]: !!props.calendarClassName,
244+
...(defaultedUI.value.calendar ?? {}),
243245
}),
244246
);
245247

src/VueDatePicker/components/DatePicker/DpHeader.vue

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
v-if="showLeftIcon(defaultedMultiCalendars, instance) && !vertical"
1818
:aria-label="defaultedAriaLabels?.prevMonth"
1919
:disabled="isDisabled(false)"
20+
:class="defaultedUI?.navBtnPrev"
2021
@activate="handleMonthYearChange(false, true)"
2122
@set-ref="setElRefs($event, 0)"
2223
>
@@ -87,6 +88,7 @@
8788
v-if="showLeftIcon(defaultedMultiCalendars, instance) && vertical"
8889
:aria-label="defaultedAriaLabels?.prevMonth"
8990
:disabled="isDisabled(false)"
91+
:class="defaultedUI?.navBtnPrev"
9092
@activate="handleMonthYearChange(false, true)"
9193
>
9294
<slot v-if="$slots['arrow-up']" name="arrow-up" />
@@ -97,6 +99,7 @@
9799
ref="rightIcon"
98100
:disabled="isDisabled(true)"
99101
:aria-label="defaultedAriaLabels?.nextMonth"
102+
:class="defaultedUI?.navBtnNext"
100103
@activate="handleMonthYearChange(true, true)"
101104
@set-ref="setElRefs($event, disableYearSelect ? 2 : 3)"
102105
>
@@ -167,6 +170,7 @@
167170
defaultedConfig,
168171
defaultedHighlight,
169172
propDates,
173+
defaultedUI,
170174
} = useDefaults(props);
171175
const { transitionName, showTransition } = useTransitions(defaultedTransitions);
172176
const { buildMatrix } = useArrowNavigation();

src/VueDatePicker/components/DatepickerInput.vue

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
defaultedConfig,
121121
defaultedRange,
122122
defaultedMultiDates,
123+
defaultedUI,
123124
getDefaultPattern,
124125
getDefaultStartTime,
125126
} = useDefaults(props);
@@ -143,6 +144,7 @@
143144
dp__input_focus: isFocused.value || props.isMenuOpen,
144145
dp__input_reg: !defaultedTextInput.value.enabled,
145146
[props.inputClassName]: !!props.inputClassName,
147+
...(defaultedUI.value.input ?? {}),
146148
}),
147149
);
148150

src/VueDatePicker/components/DatepickerMenu.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@
190190
191191
const { setMenuFocused, setShiftKey, control } = useState();
192192
const slots = useSlots();
193-
const { defaultedTextInput, defaultedInline, defaultedConfig } = useDefaults(props);
193+
const { defaultedTextInput, defaultedInline, defaultedConfig, defaultedUI } = useDefaults(props);
194194
195195
const calendarWrapperRef = ref(null);
196196
const calendarWidth = ref(0);
@@ -291,6 +291,7 @@
291291
dp__menu_index: !defaultedInline.value.enabled,
292292
dp__relative: defaultedInline.value.enabled,
293293
[props.menuClassName]: !!props.menuClassName,
294+
...(defaultedUI.value.menu ?? {}),
294295
}),
295296
);
296297

src/VueDatePicker/components/shared/YearModePicker.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
ref="mpPrevIconRef"
66
:aria-label="defaultedAriaLabels?.prevYear"
77
:disabled="isDisabled(false)"
8+
:class="defaultedUI?.navBtnPrev"
89
@activate="handleYear(false)"
910
>
1011
<slot v-if="$slots['arrow-left']" name="arrow-left" />
@@ -27,6 +28,7 @@
2728
ref="mpNextIconRef"
2829
:aria-label="defaultedAriaLabels?.nextYear"
2930
:disabled="isDisabled(true)"
31+
:class="defaultedUI?.navBtnNext"
3032
@activate="handleYear(true)"
3133
>
3234
<slot v-if="$slots['arrow-right']" name="arrow-right" />
@@ -80,7 +82,8 @@
8082
});
8183
8284
const { showRightIcon, showLeftIcon } = useCommon();
83-
const { defaultedConfig, defaultedMultiCalendars, defaultedAriaLabels, defaultedTransitions } = useDefaults(props);
85+
const { defaultedConfig, defaultedMultiCalendars, defaultedAriaLabels, defaultedTransitions, defaultedUI } =
86+
useDefaults(props);
8487
const { showTransition, transitionName } = useTransitions(defaultedTransitions);
8588
8689
const toggleYearPicker = (flow = false, show?: boolean) => {

src/VueDatePicker/composables/calendar-class.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@ import type { ICalendarDay, InternalModuleValue } from '@/interfaces';
1111
import type { PickerBasePropsType } from '@/props';
1212

1313
export const useCalendarClass = (modelValue: WritableComputedRef<InternalModuleValue>, props: PickerBasePropsType) => {
14-
const { defaultedMultiCalendars, defaultedMultiDates, defaultedHighlight, defaultedTz, propDates, defaultedRange } =
15-
useDefaults(props);
14+
const {
15+
defaultedMultiCalendars,
16+
defaultedMultiDates,
17+
defaultedUI,
18+
defaultedHighlight,
19+
defaultedTz,
20+
propDates,
21+
defaultedRange,
22+
} = useDefaults(props);
1623
const { isDisabled } = useValidation(props);
1724
// Track hovered date
1825
const hoveredDate = ref<Date | null>(null);
@@ -366,6 +373,7 @@ export const useCalendarClass = (modelValue: WritableComputedRef<InternalModuleV
366373
...getModeClasses(day),
367374
[props.dayClass ? props.dayClass(day.value, props.internalModelValue) : '']: true,
368375
[props.calendarCellClassName]: !!props.calendarCellClassName,
376+
...(defaultedUI.value.calendarCell ?? {}),
369377
};
370378
};
371379

src/VueDatePicker/composables/defaults.ts

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getDefaultRangeOptions,
1515
getDefaultTextInputOptions,
1616
getDefaultTimeZone,
17+
getDefaultUI,
1718
getDefaultWeekNumbers,
1819
mapPropDates,
1920
} from '@/utils/defaults';
@@ -109,6 +110,8 @@ export const useDefaults = (props: AllPropsType | PickerBasePropsType) => {
109110
}),
110111
);
111112

113+
const defaultedUI = computed(() => getDefaultUI(props.ui));
114+
112115
return {
113116
defaultedTransitions,
114117
defaultedMultiCalendars,
@@ -126,6 +129,7 @@ export const useDefaults = (props: AllPropsType | PickerBasePropsType) => {
126129
propDates,
127130
defaultedTz,
128131
defaultedMultiDates,
132+
defaultedUI,
129133
getDefaultPattern,
130134
getDefaultStartTime,
131135
};

src/VueDatePicker/interfaces.ts

+17
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,20 @@ export interface MapPropDatesOpts {
380380
timezone: TimeZoneConfig | undefined;
381381
isSpecific?: boolean;
382382
}
383+
384+
export type CustomClass = string | string[];
385+
386+
export interface UIOpts {
387+
navBtnNext: CustomClass;
388+
navBtnPrev: CustomClass;
389+
calendar: CustomClass;
390+
calendarCell: CustomClass;
391+
menu: CustomClass;
392+
input: CustomClass;
393+
}
394+
395+
export type UIKey = keyof UIOpts;
396+
397+
export type UIParsed = {
398+
[K in keyof UIOpts]: Record<string, boolean>;
399+
};

src/VueDatePicker/props.ts

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type {
3030
TimeZoneProp,
3131
DisabledDatesProp,
3232
MultiDatesProp,
33+
UIOpts,
3334
} from '@/interfaces';
3435

3536
export const AllProps = {
@@ -168,6 +169,7 @@ export const AllProps = {
168169
loading: { type: Boolean as PropType<boolean>, default: false },
169170
onInternalModelChange: { type: [Function, Object] as PropType<(...args: any[]) => void>, default: null },
170171
enableMinutes: { type: Boolean as PropType<boolean>, default: true },
172+
ui: { type: Object as PropType<Partial<UIOpts>>, default: () => ({}) },
171173
};
172174

173175
export const PickerBaseProps = {

src/VueDatePicker/utils/defaults.ts

+22
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import type {
2727
MultiDatesProp,
2828
MultiDatesDefault,
2929
MapPropDatesOpts,
30+
UIOpts,
31+
UIKey,
32+
UIParsed,
3033
} from '@/interfaces';
3134
import { getDate } from '@/utils/date-utils';
3235
import { dateToTimezoneSafe, sanitizeDateToLocal } from '@/utils/timezone';
@@ -306,3 +309,22 @@ export const getDefaultMultiDates = (
306309
dragSelect: multiDates.dragSelect ?? true,
307310
};
308311
};
312+
313+
export const getDefaultUI = (ui: Partial<UIOpts>): UIParsed => {
314+
const defaulted = {
315+
...Object.fromEntries(
316+
Object.keys(ui).map((item) => {
317+
const key = item as keyof UIOpts;
318+
const value = ui[key];
319+
const val = (
320+
typeof ui[key] === 'string'
321+
? { [value as string]: true }
322+
: Object.fromEntries((value as string[]).map((k) => [k, true]))
323+
) as Record<string, boolean>;
324+
return [item, val];
325+
}),
326+
),
327+
};
328+
329+
return defaulted as UIParsed;
330+
};

0 commit comments

Comments
 (0)