generateCalendar.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. "use client";
  2. import * as React from 'react';
  3. import classNames from 'classnames';
  4. import { PickerPanel as RCPickerPanel } from 'rc-picker';
  5. import useMergedState from "rc-util/es/hooks/useMergedState";
  6. import { devUseWarning } from '../_util/warning';
  7. import { useComponentConfig } from '../config-provider/context';
  8. import { useLocale } from '../locale';
  9. import CalendarHeader from './Header';
  10. import enUS from './locale/en_US';
  11. import useStyle from './style';
  12. const isSameYear = (date1, date2, config) => {
  13. const {
  14. getYear
  15. } = config;
  16. return date1 && date2 && getYear(date1) === getYear(date2);
  17. };
  18. const isSameMonth = (date1, date2, config) => {
  19. const {
  20. getMonth
  21. } = config;
  22. return isSameYear(date1, date2, config) && getMonth(date1) === getMonth(date2);
  23. };
  24. const isSameDate = (date1, date2, config) => {
  25. const {
  26. getDate
  27. } = config;
  28. return isSameMonth(date1, date2, config) && getDate(date1) === getDate(date2);
  29. };
  30. const generateCalendar = generateConfig => {
  31. const Calendar = props => {
  32. const {
  33. prefixCls: customizePrefixCls,
  34. className,
  35. rootClassName,
  36. style,
  37. dateFullCellRender,
  38. dateCellRender,
  39. monthFullCellRender,
  40. monthCellRender,
  41. cellRender,
  42. fullCellRender,
  43. headerRender,
  44. value,
  45. defaultValue,
  46. disabledDate,
  47. mode,
  48. validRange,
  49. fullscreen = true,
  50. showWeek,
  51. onChange,
  52. onPanelChange,
  53. onSelect
  54. } = props;
  55. const {
  56. getPrefixCls,
  57. direction,
  58. className: contextClassName,
  59. style: contextStyle
  60. } = useComponentConfig('calendar');
  61. const prefixCls = getPrefixCls('picker', customizePrefixCls);
  62. const calendarPrefixCls = `${prefixCls}-calendar`;
  63. const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, calendarPrefixCls);
  64. const today = generateConfig.getNow();
  65. // ====================== Warning =======================
  66. if (process.env.NODE_ENV !== 'production') {
  67. const warning = devUseWarning('Calendar');
  68. [['dateFullCellRender', 'fullCellRender'], ['dateCellRender', 'cellRender'], ['monthFullCellRender', 'fullCellRender'], ['monthCellRender', 'cellRender']].forEach(([deprecatedName, newName]) => {
  69. warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
  70. });
  71. }
  72. // ====================== State =======================
  73. // Value
  74. const [mergedValue, setMergedValue] = useMergedState(() => value || generateConfig.getNow(), {
  75. defaultValue,
  76. value
  77. });
  78. // Mode
  79. const [mergedMode, setMergedMode] = useMergedState('month', {
  80. value: mode
  81. });
  82. const panelMode = React.useMemo(() => mergedMode === 'year' ? 'month' : 'date', [mergedMode]);
  83. // Disabled Date
  84. const mergedDisabledDate = React.useCallback(date => {
  85. const notInRange = validRange ? generateConfig.isAfter(validRange[0], date) || generateConfig.isAfter(date, validRange[1]) : false;
  86. return notInRange || !!(disabledDate === null || disabledDate === void 0 ? void 0 : disabledDate(date));
  87. }, [disabledDate, validRange]);
  88. // ====================== Events ======================
  89. const triggerPanelChange = (date, newMode) => {
  90. onPanelChange === null || onPanelChange === void 0 ? void 0 : onPanelChange(date, newMode);
  91. };
  92. const triggerChange = date => {
  93. setMergedValue(date);
  94. if (!isSameDate(date, mergedValue, generateConfig)) {
  95. // Trigger when month panel switch month
  96. if (panelMode === 'date' && !isSameMonth(date, mergedValue, generateConfig) || panelMode === 'month' && !isSameYear(date, mergedValue, generateConfig)) {
  97. triggerPanelChange(date, mergedMode);
  98. }
  99. onChange === null || onChange === void 0 ? void 0 : onChange(date);
  100. }
  101. };
  102. const triggerModeChange = newMode => {
  103. setMergedMode(newMode);
  104. triggerPanelChange(mergedValue, newMode);
  105. };
  106. const onInternalSelect = (date, source) => {
  107. triggerChange(date);
  108. onSelect === null || onSelect === void 0 ? void 0 : onSelect(date, {
  109. source
  110. });
  111. };
  112. // ====================== Render ======================
  113. const dateRender = React.useCallback((date, info) => {
  114. if (fullCellRender) {
  115. return fullCellRender(date, info);
  116. }
  117. if (dateFullCellRender) {
  118. return dateFullCellRender(date);
  119. }
  120. return /*#__PURE__*/React.createElement("div", {
  121. className: classNames(`${prefixCls}-cell-inner`, `${calendarPrefixCls}-date`, {
  122. [`${calendarPrefixCls}-date-today`]: isSameDate(today, date, generateConfig)
  123. })
  124. }, /*#__PURE__*/React.createElement("div", {
  125. className: `${calendarPrefixCls}-date-value`
  126. }, String(generateConfig.getDate(date)).padStart(2, '0')), /*#__PURE__*/React.createElement("div", {
  127. className: `${calendarPrefixCls}-date-content`
  128. }, cellRender ? cellRender(date, info) : dateCellRender === null || dateCellRender === void 0 ? void 0 : dateCellRender(date)));
  129. }, [dateFullCellRender, dateCellRender, cellRender, fullCellRender]);
  130. const monthRender = React.useCallback((date, info) => {
  131. if (fullCellRender) {
  132. return fullCellRender(date, info);
  133. }
  134. if (monthFullCellRender) {
  135. return monthFullCellRender(date);
  136. }
  137. const months = info.locale.shortMonths || generateConfig.locale.getShortMonths(info.locale.locale);
  138. return /*#__PURE__*/React.createElement("div", {
  139. className: classNames(`${prefixCls}-cell-inner`, `${calendarPrefixCls}-date`, {
  140. [`${calendarPrefixCls}-date-today`]: isSameMonth(today, date, generateConfig)
  141. })
  142. }, /*#__PURE__*/React.createElement("div", {
  143. className: `${calendarPrefixCls}-date-value`
  144. }, months[generateConfig.getMonth(date)]), /*#__PURE__*/React.createElement("div", {
  145. className: `${calendarPrefixCls}-date-content`
  146. }, cellRender ? cellRender(date, info) : monthCellRender === null || monthCellRender === void 0 ? void 0 : monthCellRender(date)));
  147. }, [monthFullCellRender, monthCellRender, cellRender, fullCellRender]);
  148. const [contextLocale] = useLocale('Calendar', enUS);
  149. const locale = Object.assign(Object.assign({}, contextLocale), props.locale);
  150. const mergedCellRender = (current, info) => {
  151. if (info.type === 'date') {
  152. return dateRender(current, info);
  153. }
  154. if (info.type === 'month') {
  155. return monthRender(current, Object.assign(Object.assign({}, info), {
  156. locale: locale === null || locale === void 0 ? void 0 : locale.lang
  157. }));
  158. }
  159. };
  160. return wrapCSSVar(/*#__PURE__*/React.createElement("div", {
  161. className: classNames(calendarPrefixCls, {
  162. [`${calendarPrefixCls}-full`]: fullscreen,
  163. [`${calendarPrefixCls}-mini`]: !fullscreen,
  164. [`${calendarPrefixCls}-rtl`]: direction === 'rtl'
  165. }, contextClassName, className, rootClassName, hashId, cssVarCls),
  166. style: Object.assign(Object.assign({}, contextStyle), style)
  167. }, headerRender ? headerRender({
  168. value: mergedValue,
  169. type: mergedMode,
  170. onChange: nextDate => {
  171. onInternalSelect(nextDate, 'customize');
  172. },
  173. onTypeChange: triggerModeChange
  174. }) : (/*#__PURE__*/React.createElement(CalendarHeader, {
  175. prefixCls: calendarPrefixCls,
  176. value: mergedValue,
  177. generateConfig: generateConfig,
  178. mode: mergedMode,
  179. fullscreen: fullscreen,
  180. locale: locale === null || locale === void 0 ? void 0 : locale.lang,
  181. validRange: validRange,
  182. onChange: onInternalSelect,
  183. onModeChange: triggerModeChange
  184. })), /*#__PURE__*/React.createElement(RCPickerPanel, {
  185. value: mergedValue,
  186. prefixCls: prefixCls,
  187. locale: locale === null || locale === void 0 ? void 0 : locale.lang,
  188. generateConfig: generateConfig,
  189. cellRender: mergedCellRender,
  190. onSelect: nextDate => {
  191. onInternalSelect(nextDate, panelMode);
  192. },
  193. mode: panelMode,
  194. picker: panelMode,
  195. disabledDate: mergedDisabledDate,
  196. hideHeader: true,
  197. showWeek: showWeek
  198. })));
  199. };
  200. if (process.env.NODE_ENV !== 'production') {
  201. Calendar.displayName = 'Calendar';
  202. }
  203. return Calendar;
  204. };
  205. export default generateCalendar;