195 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Vue
		
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Vue
		
	
	
import Select from '../select';
 | 
						|
import { Group, Button } from '../radio';
 | 
						|
import type { CalendarMode } from './generateCalendar';
 | 
						|
import type { Ref } from 'vue';
 | 
						|
import { defineComponent, ref } from 'vue';
 | 
						|
import type { Locale } from '../vc-picker/interface';
 | 
						|
import type { GenerateConfig } from '../vc-picker/generate';
 | 
						|
import { FormItemInputContext } from '../form/FormItemContext';
 | 
						|
 | 
						|
const YearSelectOffset = 10;
 | 
						|
const YearSelectTotal = 20;
 | 
						|
 | 
						|
interface SharedProps<DateType> {
 | 
						|
  prefixCls: string;
 | 
						|
  value: DateType;
 | 
						|
  validRange?: [DateType, DateType];
 | 
						|
  generateConfig: GenerateConfig<DateType>;
 | 
						|
  locale: Locale;
 | 
						|
  fullscreen: boolean;
 | 
						|
  divRef: Ref<HTMLDivElement>;
 | 
						|
  onChange: (year: DateType) => void;
 | 
						|
}
 | 
						|
 | 
						|
function YearSelect<DateType>(props: SharedProps<DateType>) {
 | 
						|
  const { fullscreen, validRange, generateConfig, locale, prefixCls, value, onChange, divRef } =
 | 
						|
    props;
 | 
						|
 | 
						|
  const year = generateConfig.getYear(value || generateConfig.getNow());
 | 
						|
 | 
						|
  let start = year - YearSelectOffset;
 | 
						|
  let end = start + YearSelectTotal;
 | 
						|
 | 
						|
  if (validRange) {
 | 
						|
    start = generateConfig.getYear(validRange[0]);
 | 
						|
    end = generateConfig.getYear(validRange[1]) + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  const suffix = locale && locale.year === 'ๅนด' ? 'ๅนด' : '';
 | 
						|
  const options: { label: string; value: number }[] = [];
 | 
						|
  for (let index = start; index < end; index++) {
 | 
						|
    options.push({ label: `${index}${suffix}`, value: index });
 | 
						|
  }
 | 
						|
  return (
 | 
						|
    <Select
 | 
						|
      size={fullscreen ? undefined : 'small'}
 | 
						|
      options={options}
 | 
						|
      value={year}
 | 
						|
      class={`${prefixCls}-year-select`}
 | 
						|
      onChange={(numYear: number) => {
 | 
						|
        let newDate = generateConfig.setYear(value, numYear);
 | 
						|
 | 
						|
        if (validRange) {
 | 
						|
          const [startDate, endDate] = validRange;
 | 
						|
          const newYear = generateConfig.getYear(newDate);
 | 
						|
          const newMonth = generateConfig.getMonth(newDate);
 | 
						|
          if (
 | 
						|
            newYear === generateConfig.getYear(endDate) &&
 | 
						|
            newMonth > generateConfig.getMonth(endDate)
 | 
						|
          ) {
 | 
						|
            newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(endDate));
 | 
						|
          }
 | 
						|
          if (
 | 
						|
            newYear === generateConfig.getYear(startDate) &&
 | 
						|
            newMonth < generateConfig.getMonth(startDate)
 | 
						|
          ) {
 | 
						|
            newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(startDate));
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        onChange(newDate);
 | 
						|
      }}
 | 
						|
      getPopupContainer={() => divRef!.value!}
 | 
						|
    />
 | 
						|
  );
 | 
						|
}
 | 
						|
YearSelect.inheritAttrs = false;
 | 
						|
 | 
						|
function MonthSelect<DateType>(props: SharedProps<DateType>) {
 | 
						|
  const { prefixCls, fullscreen, validRange, value, generateConfig, locale, onChange, divRef } =
 | 
						|
    props;
 | 
						|
  const month = generateConfig.getMonth(value || generateConfig.getNow());
 | 
						|
 | 
						|
  let start = 0;
 | 
						|
  let end = 11;
 | 
						|
 | 
						|
  if (validRange) {
 | 
						|
    const [rangeStart, rangeEnd] = validRange;
 | 
						|
    const currentYear = generateConfig.getYear(value);
 | 
						|
    if (generateConfig.getYear(rangeEnd) === currentYear) {
 | 
						|
      end = generateConfig.getMonth(rangeEnd);
 | 
						|
    }
 | 
						|
    if (generateConfig.getYear(rangeStart) === currentYear) {
 | 
						|
      start = generateConfig.getMonth(rangeStart);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const months = locale.shortMonths || generateConfig.locale.getShortMonths!(locale.locale);
 | 
						|
  const options: { label: string; value: number }[] = [];
 | 
						|
  for (let index = start; index <= end; index += 1) {
 | 
						|
    options.push({
 | 
						|
      label: months[index],
 | 
						|
      value: index,
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  return (
 | 
						|
    <Select
 | 
						|
      size={fullscreen ? undefined : 'small'}
 | 
						|
      class={`${prefixCls}-month-select`}
 | 
						|
      value={month}
 | 
						|
      options={options}
 | 
						|
      onChange={(newMonth: number) => {
 | 
						|
        onChange(generateConfig.setMonth(value, newMonth));
 | 
						|
      }}
 | 
						|
      getPopupContainer={() => divRef!.value!}
 | 
						|
    />
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
MonthSelect.inheritAttrs = false;
 | 
						|
 | 
						|
interface ModeSwitchProps<DateType> extends Omit<SharedProps<DateType>, 'onChange'> {
 | 
						|
  mode: CalendarMode;
 | 
						|
  onModeChange: (type: CalendarMode) => void;
 | 
						|
}
 | 
						|
 | 
						|
function ModeSwitch<DateType>(props: ModeSwitchProps<DateType>) {
 | 
						|
  const { prefixCls, locale, mode, fullscreen, onModeChange } = props;
 | 
						|
  return (
 | 
						|
    <Group
 | 
						|
      onChange={({ target: { value } }) => {
 | 
						|
        onModeChange(value);
 | 
						|
      }}
 | 
						|
      value={mode}
 | 
						|
      size={fullscreen ? undefined : 'small'}
 | 
						|
      class={`${prefixCls}-mode-switch`}
 | 
						|
    >
 | 
						|
      <Button value="month">{locale.month}</Button>
 | 
						|
      <Button value="year">{locale.year}</Button>
 | 
						|
    </Group>
 | 
						|
  );
 | 
						|
}
 | 
						|
ModeSwitch.inheritAttrs = false;
 | 
						|
 | 
						|
export interface CalendarHeaderProps<DateType> {
 | 
						|
  prefixCls: string;
 | 
						|
  value: DateType;
 | 
						|
  validRange?: [DateType, DateType];
 | 
						|
  generateConfig: GenerateConfig<DateType>;
 | 
						|
  locale: Locale;
 | 
						|
  mode: CalendarMode;
 | 
						|
  fullscreen: boolean;
 | 
						|
  onChange: (date: DateType) => void;
 | 
						|
  onModeChange: (mode: CalendarMode) => void;
 | 
						|
}
 | 
						|
 | 
						|
export default defineComponent<CalendarHeaderProps<any>>({
 | 
						|
  name: 'CalendarHeader',
 | 
						|
  inheritAttrs: false,
 | 
						|
  props: [
 | 
						|
    'mode',
 | 
						|
    'prefixCls',
 | 
						|
    'value',
 | 
						|
    'validRange',
 | 
						|
    'generateConfig',
 | 
						|
    'locale',
 | 
						|
    'mode',
 | 
						|
    'fullscreen',
 | 
						|
  ] as any,
 | 
						|
  setup(_props, { attrs }) {
 | 
						|
    const divRef = ref<HTMLDivElement>(null);
 | 
						|
    const formItemInputContext = FormItemInputContext.useInject();
 | 
						|
    FormItemInputContext.useProvide(formItemInputContext, { isFormItemInput: false });
 | 
						|
 | 
						|
    return () => {
 | 
						|
      const props = { ..._props, ...attrs };
 | 
						|
      const { prefixCls, fullscreen, mode, onChange, onModeChange } = props;
 | 
						|
      const sharedProps = {
 | 
						|
        ...props,
 | 
						|
        onChange,
 | 
						|
        fullscreen,
 | 
						|
        divRef,
 | 
						|
      } as any;
 | 
						|
 | 
						|
      return (
 | 
						|
        <div class={`${prefixCls}-header`} ref={divRef}>
 | 
						|
          <YearSelect {...sharedProps} />
 | 
						|
          {mode === 'month' && <MonthSelect {...sharedProps} />}
 | 
						|
          <ModeSwitch {...sharedProps} onModeChange={onModeChange} />
 | 
						|
        </div>
 | 
						|
      );
 | 
						|
    };
 | 
						|
  },
 | 
						|
});
 |