New Huajishe Check ChaoXing

This commit is contained in:
e2hang
2025-10-01 10:01:52 +08:00
parent 240b884eac
commit 80be8ae3cf
1094 changed files with 61709 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
:: BASE_DOC ::
## API
### Calendar Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
auto-close | Boolean | true | `0.34.0` | N
confirm-btn | String / Object / Slot | '' | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
first-day-of-week | Number | 0 | \- | N
format | Function | - | Typescript`CalendarFormatType ` `type CalendarFormatType = (day: TDate) => TDate` `type TDateType = 'selected' \| 'disabled' \| 'start' \| 'centre' \| 'end' \| ''` `interface TDate { date: Date; day: number; type: TDateType; className?: string; prefix?: string; suffix?: string;}`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
locale-text | Object | - | Typescript`CalendarLocaleText` `interface CalendarLocaleText {title?: string; weekdays?: string[]; monthTitle?: string; months?: string[]; confirm?: string;}`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
max-date | Number | - | \- | N
min-date | Number | - | \- | N
switch-mode | String | none | options: none/month/year-month | N
title | String / Slot | - | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
type | String | 'single' | options: single/multiple/range | N
use-popup | Boolean | true | `0.32.0` | N
using-custom-navbar | Boolean | false | \- | N
value | Number / Array | - | Typescript`number \| number[]` | N
default-value | Number / Array | undefined | uncontrolled property。Typescript`number \| number[]` | N
visible | Boolean | false | \- | N
### Calendar Events
name | params | description
-- | -- | --
change | `(value: timestamp)` | `0.28.0`
close | `(trigger: CalendarTrigger)` | `0.34.0`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts)。<br/>`type CalendarTrigger = 'close-btn' \| 'confirm-btn' \| 'overlay'`<br/>
confirm | `(value: timestamp)` | \-
panel-change | `(year: number; month: number)` | `1.8.4`
scroll | `({scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY})` | `1.4.6`。triggered when scrolling
select | `(value: timestamp)` | `0.28.0`
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-calendar-active-color | @brand-color | -
--td-calendar-bg-color | @bg-color-container | -
--td-calendar-days-color | @text-color-secondary | -
--td-calendar-item-centre-color | @brand-color-light | -
--td-calendar-item-disabled-color | @text-color-disabled | -
--td-calendar-item-suffix-color | @text-color-placeholder | -
--td-calendar-radius | 24rpx | -
--td-calendar-selected-color | @text-color-anti | -
--td-calendar-switch-mode-icon-color | @brand-color | -
--td-calendar-switch-mode-icon-disabled-color | @brand-color-disabled | -
--td-calendar-title-color | @text-color-primary | -
--td-calendar-title-font-size | 18px | -

View File

@@ -0,0 +1,120 @@
---
title: Calendar 日历
description: 按照日历形式展示数据或日期的容器。
spline: form
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-100%25-blue" /></span>
<div style="background: #ecf2fe; display: flex; align-items: center; line-height: 20px; padding: 14px 24px; border-radius: 3px; color: #555a65">
<svg fill="none" viewBox="0 0 16 16" width="16px" height="16px" style="margin-right: 5px">
<path fill="#0052d9" d="M8 15A7 7 0 108 1a7 7 0 000 14zM7.4 4h1.2v1.2H7.4V4zm.1 2.5h1V12h-1V6.5z" fillOpacity="0.9"></path>
</svg>
该组件于 0.22.0 版本上线,请留意版本。
</div>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-calendar": "tdesign-miniprogram/calendar/calendar"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/jb5E2imk7QSV" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
#### 单个选择日历
{{ base }}
#### 多个选择日历
{{ multiple }}
#### 带单行/双行描述的日历
{{ custom-text }}
#### 带翻页功能的日历
{{ switch-mode }}
#### 可选择区间日期的日历
{{ range }}
### 组件样式
#### 国际化
{{ local-text }}
#### 含不可选的日历
{{ custom-range }}
#### 不使用 Popup
{{ without-popup }}
## API
### Calendar Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
auto-close | Boolean | true | `0.34.0`。自动关闭;在点击关闭按钮、确认按钮、遮罩层时自动关闭,不需要手动设置 visible | N
confirm-btn | String / Object / Slot | '' | 确认按钮。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
first-day-of-week | Number | 0 | 第一天从星期几开始,默认 0 = 周日 | N
format | Function | - | 用于格式化日期的函数。TS 类型:`CalendarFormatType ` `type CalendarFormatType = (day: TDate) => TDate` `type TDateType = 'selected' \| 'disabled' \| 'start' \| 'centre' \| 'end' \| ''` `interface TDate { date: Date; day: number; type: TDateType; className?: string; prefix?: string; suffix?: string;}`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
locale-text | Object | - | 国际化文案。TS 类型:`CalendarLocaleText` `interface CalendarLocaleText {title?: string; weekdays?: string[]; monthTitle?: string; months?: string[]; confirm?: string;}`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts) | N
max-date | Number | - | 最大可选的日期,不传则默认半年后 | N
min-date | Number | - | 最小可选的日期,不传则默认今天 | N
switch-mode | String | none | 切换模式。 `none` 表示水平方向平铺展示所有月份; `month` 表示支持按月切换, `year-month` 表示既按年切换也支持按月切换。可选项none/month/year-month | N
title | String / Slot | - | 标题,不传默认为“请选择日期”。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
type | String | 'single' | 日历的选择类型single = 单选multiple = 多选; range = 区间选择。可选项single/multiple/range | N
use-popup | Boolean | true | `0.32.0`。是否使用弹出层包裹日历 | N
using-custom-navbar | Boolean | false | 是否使用了自定义导航栏 | N
value | Number / Array | - | 当前选择的日期,不传则选用 minDate 属性值或今天优先级minDate > today。当 type = multiple 或 range 时传入数组。TS 类型:`number \| number[]` | N
default-value | Number / Array | undefined | 当前选择的日期,不传则选用 minDate 属性值或今天优先级minDate > today。当 type = multiple 或 range 时传入数组。非受控属性。TS 类型:`number \| number[]` | N
visible | Boolean | false | 是否显示日历;`usePopup` 为 true 时有效 | N
### Calendar Events
名称 | 参数 | 描述
-- | -- | --
change | `(value: timestamp)` | `0.28.0`。不显示 confirm-btn 时,完成选择时触发(暂不支持 type = multiple
close | `(trigger: CalendarTrigger)` | `0.34.0`。关闭按钮时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/calendar/type.ts)。<br/>`type CalendarTrigger = 'close-btn' \| 'confirm-btn' \| 'overlay'`<br/>
confirm | `(value: timestamp)` | 点击确认按钮时触发
panel-change | `(year: number; month: number)` | `1.8.4`。切换月或年时触发switch-mode 不为 none 时有效)
scroll | `({scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY})` | `1.4.6`。滚动时触发
select | `(value: timestamp)` | `0.28.0`。点击日期时触发
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-calendar-active-color | @brand-color | 选中项背景色
--td-calendar-bg-color | @bg-color-container | -
--td-calendar-days-color | @text-color-secondary | -
--td-calendar-item-centre-color | @brand-color-light | -
--td-calendar-item-disabled-color | @text-color-disabled | -
--td-calendar-item-suffix-color | @text-color-placeholder | -
--td-calendar-radius | 24rpx | -
--td-calendar-selected-color | @text-color-anti | -
--td-calendar-switch-mode-icon-color | @brand-color | -
--td-calendar-switch-mode-icon-disabled-color | @brand-color-disabled | -
--td-calendar-title-color | @text-color-primary | -
--td-calendar-title-font-size | 18px | -

View File

@@ -0,0 +1,45 @@
<wxs src="../common/utils.wxs" module="_" />
<template name="calendar-header">
<view class="{{class}} {{classPrefix}} {{switchMode !== 'none' ? classPrefix + '__with-action' : ''}}" id="{{tId}}">
<view class="{{classPrefix}}__action" wx:if="{{switchMode !== 'none'}}">
<view
wx:if="{{switchMode === 'year-month'}}"
class="{{_.cls(classPrefix + '__icon', [['disabled', preYearBtnDisable]])}}"
data-disabled="{{preYearBtnDisable}}"
data-type="pre-year"
bindtap="handleSwitchModeChange"
>
<t-icon name="chevron-left-double" />
</view>
<view
class="{{_.cls(classPrefix + '__icon', [['disabled', prevMonthBtnDisable]])}}"
data-disabled="{{prevMonthBtnDisable}}"
data-type="pre-month"
bindtap="handleSwitchModeChange"
>
<t-icon name="chevron-left" />
</view>
</view>
<view class="{{classPrefix}}__title"> {{ title }}</view>
<view class="{{classPrefix}}__action" wx:if="{{switchMode !== 'none'}}">
<view
class="{{_.cls(classPrefix + '__icon', [['disabled', nextMonthBtnDisable]])}}"
data-disabled="{{nextMonthBtnDisable}}"
data-type="next-month"
bindtap="handleSwitchModeChange"
>
<t-icon name="chevron-right" />
</view>
<view
wx:if="{{switchMode === 'year-month'}}"
class="{{_.cls(classPrefix + '__icon', [['disabled', nextYearBtnDisable]])}}"
data-disabled="{{nextYearBtnDisable}}"
data-type="next-year"
bindtap="handleSwitchModeChange"
>
<t-icon name="chevron-right-double" />
</view>
</view>
</view>
</template>

View File

@@ -0,0 +1,62 @@
/// <reference types="miniprogram-api-typings" />
import { SuperComponent } from '../common/src/index';
import { TdCalendarProps } from './type';
export interface CalendarProps extends TdCalendarProps {
}
export default class Calendar extends SuperComponent {
behaviors: string[];
externalClasses: string[];
options: WechatMiniprogram.Component.ComponentOptions;
properties: TdCalendarProps;
data: {
prefix: string;
classPrefix: string;
months: any[];
scrollIntoView: string;
innerConfirmBtn: {};
realLocalText: {};
currentMonth: {};
actionButtons: {
preYearBtnDisable: boolean;
prevMonthBtnDisable: boolean;
nextMonthBtnDisable: boolean;
nextYearBtnDisable: boolean;
};
};
controlledProps: {
key: string;
event: string;
}[];
lifetimes: {
created(): void;
ready(): void;
};
observers: {
type(v: any): void;
confirmBtn(v: any): void;
'firstDayOfWeek,minDate,maxDate'(firstDayOfWeek: any, minDate: any, maxDate: any): void;
value(v: any): void;
visible(v: any): void;
format(v: any): void;
};
methods: {
initialValue(): void;
scrollIntoView(): void;
getCurrentYearAndMonth(v: Date): {
year: number;
month: number;
};
updateActionButton(value: Date): void;
calcCurrentMonth(newValue?: any): void;
calcMonths(): void;
close(trigger: any): void;
onVisibleChange(): void;
handleClose(): void;
handleSelect(e: any): void;
onTplButtonTap(): void;
toTime(val: any): any;
onScroll(e: any): void;
getCurrentDate(): any;
handleSwitchModeChange(e: any): void;
};
}

View File

@@ -0,0 +1,261 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
import TCalendar from '../common/shared/calendar/index';
import useCustomNavbar from '../mixins/using-custom-navbar';
import { getPrevMonth, getPrevYear, getNextMonth, getNextYear } from './utils';
const { prefix } = config;
const name = `${prefix}-calendar`;
const defaultLocaleText = {
title: '请选择日期',
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
monthTitle: '{year} 年 {month}',
months: ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月'],
confirm: '确认',
};
let Calendar = class Calendar extends SuperComponent {
constructor() {
super(...arguments);
this.behaviors = [useCustomNavbar];
this.externalClasses = [`${prefix}-class`];
this.options = {
multipleSlots: true,
};
this.properties = props;
this.data = {
prefix,
classPrefix: name,
months: [],
scrollIntoView: '',
innerConfirmBtn: {},
realLocalText: {},
currentMonth: {},
actionButtons: {
preYearBtnDisable: false,
prevMonthBtnDisable: false,
nextMonthBtnDisable: false,
nextYearBtnDisable: false,
},
};
this.controlledProps = [
{
key: 'value',
event: 'confirm',
},
{
key: 'value',
event: 'change',
},
];
this.lifetimes = {
created() {
this.base = new TCalendar(this.properties);
},
ready() {
const realLocalText = Object.assign(Object.assign({}, defaultLocaleText), this.properties.localeText);
this.initialValue();
this.setData({
days: this.base.getDays(realLocalText.weekdays),
realLocalText,
});
this.calcMonths();
if (this.data.switchMode !== 'none') {
this.calcCurrentMonth();
}
if (!this.data.usePopup) {
this.scrollIntoView();
}
},
};
this.observers = {
type(v) {
this.base.type = v;
},
confirmBtn(v) {
if (typeof v === 'string') {
this.setData({ innerConfirmBtn: v === 'slot' ? 'slot' : { content: v } });
}
else if (typeof v === 'object') {
this.setData({ innerConfirmBtn: v });
}
},
'firstDayOfWeek,minDate,maxDate'(firstDayOfWeek, minDate, maxDate) {
firstDayOfWeek && (this.base.firstDayOfWeek = firstDayOfWeek);
minDate && (this.base.minDate = minDate);
maxDate && (this.base.maxDate = maxDate);
this.calcMonths();
},
value(v) {
this.base.value = v;
this.calcMonths();
},
visible(v) {
if (v) {
this.scrollIntoView();
this.base.value = this.data.value;
this.calcMonths();
}
},
format(v) {
const { usePopup, visible } = this.data;
this.base.format = v;
if (!usePopup || visible) {
this.calcMonths();
}
},
};
this.methods = {
initialValue() {
const { value, type, minDate } = this.data;
if (!value) {
const today = new Date();
const now = minDate || new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
const initialValue = type === 'single' ? now : [now];
if (type === 'range') {
initialValue[1] = now + 24 * 3600 * 1000;
}
this.setData({
value: initialValue,
});
this.base.value = initialValue;
}
},
scrollIntoView() {
const { value } = this.data;
if (!value)
return;
const date = new Date(Array.isArray(value) ? value[0] : value);
if (date) {
this.setData({
scrollIntoView: `year_${date.getFullYear()}_month_${date.getMonth()}`,
});
}
},
getCurrentYearAndMonth(v) {
const date = new Date(v);
return { year: date.getFullYear(), month: date.getMonth() };
},
updateActionButton(value) {
const _min = this.getCurrentYearAndMonth(this.base.minDate);
const _max = this.getCurrentYearAndMonth(this.base.maxDate);
const _minTimestamp = new Date(_min.year, _min.month, 1).getTime();
const _maxTimestamp = new Date(_max.year, _max.month, 1).getTime();
const _prevYearTimestamp = getPrevYear(value).getTime();
const _prevMonthTimestamp = getPrevMonth(value).getTime();
const _nextMonthTimestamp = getNextMonth(value).getTime();
const _nextYearTimestamp = getNextYear(value).getTime();
const preYearBtnDisable = _prevYearTimestamp < _minTimestamp || _prevMonthTimestamp < _minTimestamp;
const prevMonthBtnDisable = _prevMonthTimestamp < _minTimestamp;
const nextYearBtnDisable = _nextMonthTimestamp > _maxTimestamp || _nextYearTimestamp > _maxTimestamp;
const nextMonthBtnDisable = _nextMonthTimestamp > _maxTimestamp;
this.setData({
actionButtons: {
preYearBtnDisable,
prevMonthBtnDisable,
nextYearBtnDisable,
nextMonthBtnDisable,
},
});
},
calcCurrentMonth(newValue) {
const date = newValue || this.getCurrentDate();
const { year, month } = this.getCurrentYearAndMonth(date);
const currentMonth = this.data.months.filter((item) => item.year === year && item.month === month);
this.updateActionButton(date);
this.setData({
currentMonth: currentMonth.length > 0 ? currentMonth : [this.data.months[0]],
});
},
calcMonths() {
const months = this.base.getMonths();
this.setData({
months,
});
},
close(trigger) {
if (this.data.autoClose) {
this.setData({ visible: false });
}
this.triggerEvent('close', { trigger });
},
onVisibleChange() {
this.close('overlay');
},
handleClose() {
this.close('close-btn');
},
handleSelect(e) {
const { date, year, month } = e.currentTarget.dataset;
if (date.type === 'disabled')
return;
const rawValue = this.base.select({ cellType: date.type, year, month, date: date.day });
const value = this.toTime(rawValue);
this.calcMonths();
if (this.data.switchMode !== 'none') {
const date = this.getCurrentDate();
this.calcCurrentMonth(date);
}
if (this.data.confirmBtn == null) {
if (this.data.type === 'single' || rawValue.length === 2) {
this.setData({ visible: false });
this._trigger('change', { value });
}
}
this.triggerEvent('select', { value });
},
onTplButtonTap() {
const rawValue = this.base.getTrimValue();
const value = this.toTime(rawValue);
this.close('confirm-btn');
this._trigger('confirm', { value });
},
toTime(val) {
if (Array.isArray(val)) {
return val.map((item) => item.getTime());
}
return val.getTime();
},
onScroll(e) {
this.triggerEvent('scroll', e.detail);
},
getCurrentDate() {
var _a, _b;
let time = Array.isArray(this.base.value) ? this.base.value[0] : this.base.value;
if (this.data.currentMonth.length > 0) {
const year = (_a = this.data.currentMonth[0]) === null || _a === void 0 ? void 0 : _a.year;
const month = (_b = this.data.currentMonth[0]) === null || _b === void 0 ? void 0 : _b.month;
time = new Date(year, month, 1).getTime();
}
return time;
},
handleSwitchModeChange(e) {
const { type, disabled } = e.currentTarget.dataset;
if (disabled)
return;
const date = this.getCurrentDate();
const funcMap = {
'pre-year': () => getPrevYear(date),
'pre-month': () => getPrevMonth(date),
'next-month': () => getNextMonth(date),
'next-year': () => getNextYear(date),
};
const newValue = funcMap[type]();
if (!newValue)
return;
const { year, month } = this.getCurrentYearAndMonth(newValue);
this.triggerEvent('panel-change', { year, month: month + 1 });
this.calcCurrentMonth(newValue);
},
};
}
};
Calendar = __decorate([
wxComponent()
], Calendar);
export default Calendar;

View File

@@ -0,0 +1,9 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-popup": "../popup/popup",
"t-button": "../button/button",
"t-icon": "../icon/icon"
}
}

View File

@@ -0,0 +1,16 @@
<wxs src="./calendar.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<t-popup
wx:if="{{usePopup}}"
class="class"
visible="{{visible}}"
usingCustomNavbar="{{usingCustomNavbar}}"
bind:visible-change="onVisibleChange"
placement="bottom"
>
<include src="./template.wxml" />
</t-popup>
<block wx:else>
<include src="./template.wxml" />
</block>

View File

@@ -0,0 +1,44 @@
function getDateLabel(monthItem, dateItem) {
var weekdayText = ['日', '一', '二', '三', '四', '五', '六'];
var weekday = (monthItem.weekdayOfFirstDay + dateItem.day - 1) % 7;
var label = monthItem.month + 1 + '月' + dateItem.day + '日, 星期' + weekdayText[weekday];
if (dateItem.type === 'start') {
label = '开始日期:' + label;
}
if (dateItem.type === 'end') {
label = '结束日期:' + label;
}
if (isDateSelected(dateItem)) {
label = '已选中, ' + label;
}
if (dateItem.prefix) {
label += ', ' + dateItem.prefix;
}
if (dateItem.suffix) {
label += ', ' + dateItem.suffix;
}
return label;
}
function isDateSelected(dateItem) {
return ['start', 'end', 'selected', 'centre'].indexOf(dateItem.type) >= 0;
}
function getMonthTitle(year, month, pattern = '') {
// prettier-ignore
var REGEXP = getRegExp('\{year\}|\{month\}', 'g');
return pattern.replace(REGEXP, function (match) {
var replacements = {
'{year}': year,
'{month}': month < 10 ? '0' + month : month,
};
return replacements[match] || match;
});
}
module.exports = {
getDateLabel: getDateLabel,
isDateSelected: isDateSelected,
getMonthTitle: getMonthTitle,
};

View File

@@ -0,0 +1,240 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-calendar {
width: inherit;
position: relative;
z-index: 9999;
background: var(--td-calendar-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
overflow-x: hidden;
}
.t-calendar--popup {
border-top-left-radius: var(--td-calendar-radius, 24rpx);
border-top-right-radius: var(--td-calendar-radius, 24rpx);
}
.t-calendar__title {
display: flex;
align-items: center;
justify-content: center;
font-size: var(--td-calendar-title-font-size, 18px);
font-weight: 600;
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
height: 52rpx;
padding: 32rpx;
}
.t-calendar__title:focus {
outline: 0;
}
.t-calendar__close-btn {
position: absolute;
top: 32rpx;
right: 32rpx;
margin: -24rpx;
padding: 24rpx;
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
}
.t-calendar__days {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-column-gap: 8rpx;
padding: 0 32rpx;
text-align: center;
line-height: 92rpx;
}
.t-calendar__days-item {
height: 92rpx;
font-size: 28rpx;
color: var(--td-calendar-days-color, var(--td-text-color-secondary, var(--td-font-gray-2, rgba(0, 0, 0, 0.6))));
}
.t-calendar__content {
min-height: 400rpx;
display: flex;
flex-direction: column;
}
.t-calendar__month {
font-size: 28rpx;
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
font-weight: 600;
padding: 32rpx 0 0;
}
.t-calendar__months {
height: 712rpx;
padding: 0 32rpx 32rpx;
box-sizing: border-box;
}
.t-calendar__months::-webkit-scrollbar {
display: none;
}
.t-calendar__dates {
flex: 1;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-column-gap: 8rpx;
}
.t-calendar__dates-item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
height: 120rpx;
line-height: 48rpx;
font-weight: 600;
margin-top: 16rpx;
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
cursor: pointer;
-webkit-tap-highlight-color: transparent;
-webkit-user-select: none;
user-select: none;
}
.t-calendar__dates-item-prefix,
.t-calendar__dates-item-suffix {
position: absolute;
font-size: 20rpx;
line-height: 32rpx;
width: 100%;
text-align: center;
font-weight: 400;
}
.t-calendar__dates-item-prefix {
top: 8rpx;
}
.t-calendar__dates-item-suffix {
bottom: 8rpx;
color: var(--td-calendar-item-suffix-color, var(--td-text-color-placeholder, var(--td-font-gray-3, rgba(0, 0, 0, 0.4))));
}
.t-calendar__dates-item-suffix--selected,
.t-calendar__dates-item-suffix--start,
.t-calendar__dates-item-suffix--end {
color: var(--td-calendar-selected-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
}
.t-calendar__dates-item-suffix--disabled {
color: var(--td-calendar-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
}
.t-calendar__dates-item--selected,
.t-calendar__dates-item--start,
.t-calendar__dates-item--end {
background: var(--td-calendar-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
color: var(--td-calendar-selected-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
}
.t-calendar__dates-item--start {
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) 0 0 var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
}
.t-calendar__dates-item--end {
border-radius: 0 var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) 0;
}
.t-calendar__dates-item--start + .t-calendar__dates-item--end::before {
content: '';
display: block;
position: absolute;
top: 0;
width: 8rpx;
height: 100%;
background: var(--td-calendar-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
}
.t-calendar__dates-item--start + .t-calendar__dates-item--end:before {
left: -8rpx;
}
.t-calendar__dates-item--centre {
border-radius: 0;
background-color: var(--td-calendar-item-centre-color, var(--td-brand-color-light, var(--td-primary-color-1, #f2f3ff)));
}
.t-calendar__dates-item--centre::before,
.t-calendar__dates-item--centre::after {
content: '';
display: block;
position: absolute;
top: 0;
width: 8rpx;
height: 100%;
background-color: var(--td-calendar-item-centre-color, var(--td-brand-color-light, var(--td-primary-color-1, #f2f3ff)));
}
.t-calendar__dates-item--centre:before {
left: -8rpx;
}
.t-calendar__dates-item--centre:after {
right: -8rpx;
}
.t-calendar__dates-item--disabled {
color: var(--td-calendar-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
cursor: default;
}
.t-calendar__footer {
padding: 32rpx;
}
.t-calendar-switch-mode--none > .t-calendar__months {
height: 60vh;
}
.t-calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
line-height: 44rpx;
}
.t-calendar-header__with-action {
padding: 0rpx 32rpx 16rpx 32rpx;
box-sizing: border-box;
position: relative;
}
.t-calendar-header__with-action::after {
content: '';
display: block;
position: absolute;
top: unset;
bottom: 0;
left: unset;
right: unset;
background-color: var(--td-border-color, var(--td-gray-color-3, #e7e7e7));
}
.t-calendar-header__with-action::after {
height: 1px;
left: 0;
right: 0;
transform: scaleY(0.5);
}
.t-calendar-header__with-action .t-calendar-header__title {
flex: 1;
text-align: center;
font-size: 28rpx;
font-weight: 600;
}
.t-calendar-header__action {
display: flex;
font-size: 40rpx;
color: var(--td-calendar-switch-mode-icon-color, var(--td-text-color-secondary, var(--td-font-gray-2, rgba(0, 0, 0, 0.6))));
}
.t-calendar-header__icon {
padding: 16rpx;
}
.t-calendar-header__icon--disabled {
color: var(--td-calendar-switch-mode-icon-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
}
.t-calendar-header__title {
text-align: left;
}

View File

@@ -0,0 +1,2 @@
export * from './type';
export * from './calendar';

View File

@@ -0,0 +1,2 @@
export * from './type';
export * from './calendar';

View File

@@ -0,0 +1,3 @@
import { TdCalendarProps } from './type';
declare const props: TdCalendarProps;
export default props;

View File

@@ -0,0 +1,57 @@
const props = {
autoClose: {
type: Boolean,
value: true,
},
confirmBtn: {
type: null,
value: '',
},
firstDayOfWeek: {
type: Number,
value: 0,
},
format: {
type: null,
},
localeText: {
type: Object,
},
maxDate: {
type: Number,
},
minDate: {
type: Number,
},
switchMode: {
type: String,
value: 'none',
},
title: {
type: String,
},
type: {
type: String,
value: 'single',
},
usePopup: {
type: Boolean,
value: true,
},
usingCustomNavbar: {
type: Boolean,
value: false,
},
value: {
type: null,
value: null,
},
defaultValue: {
type: null,
},
visible: {
type: Boolean,
value: false,
},
};
export default props;

View File

@@ -0,0 +1,80 @@
<wxs src="./calendar.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<import src="../common/template/button.wxml" />
<import src="./calendar-header.wxml" />
<view
class="{{_.cls(classPrefix, [['popup', usePopup]])}} {{classPrefix}}-switch-mode--{{switchMode}} class {{prefix}}-class"
style="{{_._style([style, customStyle])}}"
>
<view class="{{classPrefix}}__title" tabindex="0">
<slot name="title" />
<text wx:if="{{title || realLocalText.title}}">{{ title || realLocalText.title }}</text>
</view>
<t-icon
wx:if="{{usePopup}}"
name="close"
class="{{classPrefix}}__close-btn"
size="48rpx"
aria-role="button"
aria-label="关闭"
bind:tap="handleClose"
/>
<template
wx:if="{{switchMode !== 'none'}}"
is="calendar-header"
data="{{ classPrefix: classPrefix + '-header', switchMode, ...actionButtons, title: _this.getMonthTitle(currentMonth[0].year, realLocalText.months[currentMonth[0].month], realLocalText.monthTitle)}}"
/>
<view aria-hidden class="{{classPrefix}}__days">
<view wx:for="{{days}}" wx:key="index" class="{{classPrefix}}__days-item">{{ item }}</view>
</view>
<scroll-view
class="{{classPrefix}}__months"
scroll-into-view="{{scrollIntoView}}"
scroll-y
enhanced
show-scrollbar="{{false}}"
bindscroll="onScroll"
>
<block wx:for="{{ switchMode === 'none' ? months : currentMonth}}" wx:key="index">
<template
wx:if="{{switchMode === 'none'}}"
is="calendar-header"
data="{{class: classPrefix + '__month', classPrefix: classPrefix + '-header', tId: 'year_' + item.year + '_month_' + item.month, switchMode, ...actionButtons, title: _this.getMonthTitle(item.year, realLocalText.months[item.month], realLocalText.monthTitle) }}"
/>
<view class="{{classPrefix}}__dates">
<view wx:for="{{(item.weekdayOfFirstDay - firstDayOfWeek + 7) % 7}}" wx:key="index" />
<block wx:for="{{item.months}}" wx:for-index="dateIndex" wx:for-item="dateItem" wx:key="dateIndex">
<view
class="{{classPrefix}}__dates-item {{dateItem.className}} {{classPrefix}}__dates-item--{{dateItem.type}}"
data-year="{{item.year}}"
data-month="{{item.month}}"
data-date="{{dateItem}}"
aria-role="button"
aria-label="{{_this.getDateLabel(item, dateItem)}}"
aria-disabled="{{dateItem.type === 'disabled'}}"
bind:tap="handleSelect"
>
<view wx:if="{{dateItem.prefix}}" class="{{classPrefix}}__dates-item-prefix">{{ dateItem.prefix }}</view>
{{ dateItem.day }}
<view
wx:if="{{dateItem.suffix}}"
class="{{classPrefix}}__dates-item-suffix {{classPrefix}}__dates-item-suffix--{{dateItem.type}}"
>
{{ dateItem.suffix }}
</view>
</view>
</block>
</view>
</block>
</scroll-view>
<view wx:if="{{innerConfirmBtn != null && usePopup}}" class="{{classPrefix}}__footer">
<slot wx:if="{{innerConfirmBtn === 'slot'}}" name="confirm-btn" />
<block wx:elif="{{innerConfirmBtn}}">
<template
is="button"
data="{{ block: true, theme: 'primary', rootClass: 't-calendar__confirm-btn', content: realLocalText.confirm, ...innerConfirmBtn }}"
/>
</block>
</view>
</view>

View File

@@ -0,0 +1,80 @@
import { ButtonProps } from '../button/index';
export interface TdCalendarProps {
autoClose?: {
type: BooleanConstructor;
value?: boolean;
};
confirmBtn?: {
type: null;
value?: string | ButtonProps | null;
};
firstDayOfWeek?: {
type: NumberConstructor;
value?: number;
};
format?: {
type: undefined;
value?: CalendarFormatType;
};
localeText?: {
type: ObjectConstructor;
value?: CalendarLocaleText;
};
maxDate?: {
type: NumberConstructor;
value?: number;
};
minDate?: {
type: NumberConstructor;
value?: number;
};
switchMode?: {
type: StringConstructor;
value?: 'none' | 'month' | 'year-month';
};
title?: {
type: StringConstructor;
value?: string;
};
type?: {
type: StringConstructor;
value?: 'single' | 'multiple' | 'range';
};
usePopup?: {
type: BooleanConstructor;
value?: boolean;
};
usingCustomNavbar?: {
type: BooleanConstructor;
value?: boolean;
};
value?: {
type: null;
value?: number | number[];
};
defaultValue?: {
type: null;
value?: number | number[];
};
visible?: {
type: BooleanConstructor;
value?: boolean;
};
}
export declare type CalendarFormatType = (day: TDate) => TDate;
export declare type TDateType = 'selected' | 'disabled' | 'start' | 'centre' | 'end' | '';
export interface TDate {
date: Date;
day: number;
type: TDateType;
className?: string;
prefix?: string;
suffix?: string;
}
export interface CalendarLocaleText {
title?: string;
weekdays?: string[];
monthTitle?: string;
months?: string[];
confirm?: string;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,6 @@
export declare function getMonthByOffset(date: Date, offset: number): Date;
export declare function getYearByOffset(date: Date, offset: number): Date;
export declare const getPrevMonth: (date: Date) => Date;
export declare const getNextMonth: (date: Date) => Date;
export declare const getPrevYear: (date: Date) => Date;
export declare const getNextYear: (date: Date) => Date;

View File

@@ -0,0 +1,16 @@
export function getMonthByOffset(date, offset) {
const _date = new Date(date);
_date.setMonth(_date.getMonth() + offset);
_date.setDate(1);
return _date;
}
export function getYearByOffset(date, offset) {
const _date = new Date(date);
_date.setFullYear(_date.getFullYear() + offset);
_date.setDate(1);
return _date;
}
export const getPrevMonth = (date) => getMonthByOffset(date, -1);
export const getNextMonth = (date) => getMonthByOffset(date, 1);
export const getPrevYear = (date) => getYearByOffset(date, -1);
export const getNextYear = (date) => getYearByOffset(date, 1);