This commit is contained in:
Ling53666
2025-08-18 09:11:51 +08:00
commit 02554225da
2516 changed files with 133155 additions and 0 deletions

View File

@ -0,0 +1,67 @@
<import-sjs
from="./index.sjs"
name="helper"
></import-sjs>
<ant-popup
className="ant-actionsheet-popup"
visible="{{visible}}"
position="bottom"
zIndex="{{zIndex}}"
onClose="onClose"
>
<view
style="{{style}}"
class="ant-actionsheet {{className ? className : ''}} {{helper.isIconMode(actions) ? 'ant-actionsheet-icon' : ''}}"
>
<slot name="title">
<view
a:if="{{title}}"
class="ant-actionsheet-title-wrap"
>
<view class="ant-actionsheet-title-content">{{title}}</view>
</view>
</slot>
<view class="ant-actionsheet-list">
<block
a:for="{{actions}}"
a:for-index="index"
a:for-item="item"
key="{{index}}"
>
<view
class="ant-actionsheet-list-item {{item.disabled ? 'ant-actionsheet-list-item-disabled' : ''}}"
hoverClass="{{item.disabled ? '' : 'ant-actionsheet-list-item-active'}}"
onTap="onAction"
data-index="{{index}}"
data-item="{{item}}"
>
<view
a:if="{{helper.isIconMode(actions)}}"
class="ant-actionsheet-list-item-icon"
style="background-image: url('{{item.icon}}')"
></view>
<view class="ant-actionsheet-list-item-content">
<view class="ant-actionsheet-list-item-title {{item.danger ? 'ant-actionsheet-list-item-title-danger' : ''}}">
{{item.text}}
</view>
<view
a:if="{{item.description}}"
class="ant-actionsheet-list-item-description"
>
{{item.description}}
</view>
</view>
</view>
</block>
</view>
<view class="ant-actionsheet-cancel-gap"></view>
<slot name="cancelText">
<view
class="ant-actionsheet-cancel"
onTap="onClose"
>
{{cancelText}}
</view>
</slot>
</view>
</ant-popup>

View File

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

View File

@ -0,0 +1,14 @@
import { Component, triggerEventOnly, triggerEventValues } from '../_util/simply';
import { ActionSheetDefaultProps } from './props';
Component(ActionSheetDefaultProps, {
onAction: function (e) {
var _a = e.currentTarget.dataset, item = _a.item, index = _a.index;
if (item === null || item === void 0 ? void 0 : item.disabled)
return;
triggerEventOnly(this, 'close', e);
triggerEventValues(this, 'action', [item, index], e);
},
onClose: function (e) {
triggerEventOnly(this, 'close', e);
}
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ant-popup": "../Popup/index"
}
}

View File

@ -0,0 +1,96 @@
@import (reference) './variable.less';
@import (reference) '../style/mixins/hairline.less';
@actionsheetPrefix: ant-actionsheet;
.@{actionsheetPrefix} {
padding-left: 24 * @rpx;
padding-right: 24 * @rpx;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
&-title-wrap {
text-align: center;
position: relative;
margin: 0 -24 * @rpx;
}
&-title-content {
display: inline-block;
text-align: left;
padding: 36 * @rpx 30 * @rpx;
font-size: 30 * @rpx;
color: @COLOR_TEXT_ASSIST;
.hairline('bottom', @COLOR_BORDER);
}
&-list {
margin: 0 -24 * @rpx;
}
&-list-item {
color: @COLOR_TEXT_PRIMARY;
padding: 32 * @rpx 30 * @rpx;
text-align: center;
position: relative;
font-size: 36 * @rpx;
.hairline('bottom', @COLOR_BORDER);
&-title-danger {
color: @actionsheet-danger-color;
font-weight: bold;
}
&-description {
color: @COLOR_TEXT_ASSIST;
font-size: 28 * @rpx;
line-height: 40 * @rpx;
margin-top: 8 * @rpx;
}
&-active {
background-color: @COLOR_BORDER;
}
&:last-child {
&&:after {
display: none;
}
}
}
&-list-item-disabled {
.@{actionsheetPrefix}-list-item-icon,
.@{actionsheetPrefix}-list-item-content {
opacity: @opacity-disabled;
}
}
&-cancel-gap {
height: 16 * @rpx;
background: @COLOR_BACKGROUND;
margin: 0 -24 * @rpx;
}
&-cancel {
color: @COLOR_TEXT_PRIMARY;
padding: 32 * @rpx 30 * @rpx;
font-size: 36 * @rpx;
text-align: center;
margin: 0 -24 * @rpx;
&:active {
background-color: @COLOR_BORDER;
}
}
}
.@{actionsheetPrefix}-icon {
.@{actionsheetPrefix}-title-wrap {
text-align: left;
}
.@{actionsheetPrefix}-list-item {
display: flex;
align-items: center;
&-icon {
height: @actionsheet-icon-height;
flex: 0 0 @actionsheet-icon-width;
margin-right: 24 * @rpx;
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
}
&-content {
text-align: left;
}
}
}

View File

@ -0,0 +1,8 @@
function isIconMode(actions) {
return actions.some(function (action) {
return !!action.icon;
});
}
export default {
isIconMode: isIconMode
};

View File

@ -0,0 +1,43 @@
import { IBaseProps } from '../_util/base';
export interface IActionItem {
text: string;
icon: string;
description?: string;
danger?: boolean;
disabled?: boolean;
}
/**
* @description 头像,可展示头像以及用户名等简要信息。
*/
export interface IActionSheetProps extends IBaseProps {
/**
* @description 标题
* @default ""
*/
title: string;
/**
* @description 面板选项列表
* @default []
*/
actions: IActionItem[];
/**
* @description 取消按钮文字
* @default []
*/
cancelText: string;
/**
* @description 是否显示
* @default false
*/
visible: boolean;
zIndex: number;
/**
* @description 点击选项时触发,禁用或加载状态下不会触发
*/
onAction: (aciton: IActionItem, index: number, e: any) => void;
/**
* @description 关闭时触发
*/
onClose: (e: any) => void;
}
export declare const ActionSheetDefaultProps: Partial<IActionSheetProps>;

View File

@ -0,0 +1,8 @@
export var ActionSheetDefaultProps = {
title: '',
actions: [],
cancelText: '取消',
visible: false,
// 弹窗层级
zIndex: 998,
};

View File

@ -0,0 +1,5 @@
@import (reference) '../style/themes/index.less';
@actionsheet-danger-color: @COLOR_RED;
@actionsheet-icon-width: 48 * @rpx;
@actionsheet-icon-height: 48 * @rpx;

View File

@ -0,0 +1,13 @@
<import-sjs
from="./index.sjs"
name="utils"
></import-sjs>
<view
class="ant-avatar {{className ? className : ''}}"
style="{{style}}"
>
<image
class="ant-avatar-image {{utils.getClass(size)}}"
src="{{src || utils.defaultSrc}}"
></image>
</view>

View File

@ -0,0 +1 @@
import '../_util/assert-component2';

View File

@ -0,0 +1,4 @@
import '../_util/assert-component2';
import { Component } from '../_util/simply';
import { AvatarDefaultProps } from './props';
Component(AvatarDefaultProps);

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,33 @@
@import (reference) './variable.less';
@avatarPrefix: ant-avatar;
.@{avatarPrefix} {
display: inline-flex;
align-items: center;
&-image {
width: @avatar-size-medium;
height: @avatar-size-medium;
border-radius: @avatar-img-radius;
// 头像大小设置
&-x-small {
width: @avatar-size-x-small;
height: @avatar-size-x-small;
}
&-small {
width: @avatar-size-small;
height: @avatar-size-small;
}
&-medium {
width: @avatar-size-medium;
height: @avatar-size-medium;
}
&-large {
width: @avatar-size-large;
height: @avatar-size-large;
}
}
&-circle {
border-radius: 100vh;
}
}

View File

@ -0,0 +1,12 @@
function getClass(size) {
var list = ['x-small', 'small', 'medium', 'large'];
if (list.indexOf(size) >= 0) {
return "ant-avatar-image-".concat(size);
}
return 'ant-avatar-image-medium';
}
var defaultSrc = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTIwcHgiIGhlaWdodD0iMTIwcHgiIHZpZXdCb3g9IjAgMCAxMjAgMTIwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPuS/oeaBr+Wxleekujo0MC/lpLTlg49BdmF0YXIv5Y2V5Zu+OjEv5bC65a+4OuWkpzwvdGl0bGU+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNOCwwIEwxMTIsMCBDMTE2LjQxODI3OCwtOC4xMTYyNDUwMWUtMTYgMTIwLDMuNTgxNzIyIDEyMCw4IEwxMjAsMTEyIEMxMjAsMTE2LjQxODI3OCAxMTYuNDE4Mjc4LDEyMCAxMTIsMTIwIEw4LDEyMCBDMy41ODE3MjIsMTIwIDUuNDEwODMwMDFlLTE2LDExNi40MTgyNzggMCwxMTIgTDAsOCBDLTUuNDEwODMwMDFlLTE2LDMuNTgxNzIyIDMuNTgxNzIyLDguMTE2MjQ1MDFlLTE2IDgsMCBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0i5aS05YOPIj4KICAgICAgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8dXNlIGlkPSJNYXNrIiBmaWxsPSIjRUVFRUVFIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8cGF0aCBkPSJNNjAuNzc4Mjk5MywyMS44MTgxODE4IEw1OS4yMjE2NTIzLDIxLjgxODE4MTggTDU4LjU3ODQzNTksMjEuODI5OTY0MSBMNTguNTc4NDM1NywyMS44Mjk5NjQxIEM0OS44MDIxNTI3LDIyLjE3NDgzNiA0Mi44NjQ3OTEzLDI5LjQxMDY0NyA0Mi44NjUyMDQzLDM4LjIxOTE2MzMgTDQyLjg2NTIwNDMsNDcuNDI0MDc1MSBMNDIuODg1NzYzNyw0OC4yMzQxMDc0IEw0Mi44ODU3NjI3LDQ4LjIzNDA4NTYgQzQzLjA5MDQ4MjMsNTIuNTUwMjgwNCA0NC45MjExODc0LDU2LjYyNzYzNTUgNDguMDA3OTc5LDU5LjY0MjI3OTQgTDUyLjExMTA1ODEsNjMuNjUxMjA1MiBMNTIuMzc1MzkzNiw2My45NDI4MTY3IEM1Mi44NzQ2OTQ0LDY0LjU1MjU0OTcgNTMuMTQ3ODQxMSw2NS4zMTgzOTg0IDUzLjE0Nzg0MTEsNjYuMTEzNzA2NiBMNTMuMTQ3ODQxMSw2Ni42NzMzNjQ1IEw1My4xMjE0MDc2LDY3LjA3NjkwODEgTDUzLjEyMTQwNzYsNjcuMDc2OTA3OSBDNTIuOTg3ODc0NSw2OC4xNTYyNzIxIDUyLjMzMDE4ODEsNjkuMDk5MzI3MyA1MS4zNjUwNDk2LDY5LjU5NTM3MDUgTDI1LjU1MTE3Myw4Mi44MzI3NjM1IEwyNS4xMDQ3MzkzLDgzLjA4MzEzNjUgTDI1LjEwNDczOTUsODMuMDgzMTM2NCBDMjMuMDY0NzcxNSw4NC4zMjk4MTQgMjEuODE5NDYyMiw4Ni41NTIwMDEgMjEuODE4MTgxOCw4OC45NDc3ODUyIEwyMS44MTgxODE4LDkwLjA5NjU1NzcgTDIxLjgzNTgwNDIsOTAuNTM4MzkzMiBDMjIuMDU5MDIwNCw5My4yODk1NTEzIDI0LjM1NTgwMjcsOTUuNDU0NTQ1NSAyNy4xNTc3NTksOTUuNDU0NTQ1NSBMOTIuODQyMjQxLDk1LjQ1NDU0NTUgTDkyLjg0MjI0MSw5NS40NTQ1NDU1IEM5NS43OTAwNjM3LDk1LjQ1NDU0NTUgOTguMTgwMTkzNiw5My4wNTg4MDI3IDk4LjE4MTgxODIsOTAuMTAyNDM5NiBMOTguMTgxODE4Miw4OC45NTM2NjcyIEM5OC4xODE4MTgyLDg2LjM3MDQwNjYgOTYuNzQyNjYyOCw4NC4wMDUxMDkxIDk0LjQ0ODgwODgsODIuODMyNzY3NSBMNjguNjM0OTMyMyw2OS41OTUzNzQ1IEw2OC42MzQ5MzIsNjkuNTk1Mzc0NCBDNjcuNTM5NzExNSw2OS4wMzM5NjU3IDY2Ljg1MDk3MDIsNjcuOTAzOTcyNyA2Ni44NTIxNDA0LDY2LjY3MDQyMyBMNjYuODUyMTQwNCw2Ni4xMTA3NjUxIEM2Ni44NTIxNDA0LDY1LjE4NTg1NTYgNjcuMjI4MDg0Nyw2NC4yOTkyMzk0IDY3Ljg4ODkyMzUsNjMuNjUxMjE4NSBMNzEuOTkyMDAyNSw1OS42NDIyOTI3IEw3MS45OTIwMDI5LDU5LjY0MjI5MjQgQzc1LjI3ODYwMTksNTYuNDMxNjgwNiA3Ny4xMzIxODU3LDUyLjAyNTQyMDQgNzcuMTMxODU1Myw0Ny40MjQwNjIyIEw3Ny4xMzE4NTUzLDM4LjIxOTE1MDQgTDc3LjEzMTg1NTMsMzguMjE5MTUxIEM3Ny4xMzE4NTUzLDI5LjE2MTE2MzMgNjkuODEwMTE5OCwyMS44MTgxODE4IDYwLjc3ODI5ODcsMjEuODE4MTgxOCBMNjAuNzc4Mjk5MywyMS44MTgxODE4IFoiIGlkPSLlvaLnirYiIGZpbGw9IiNDQ0NDQ0MiIGZpbGwtcnVsZT0ibm9uemVybyIgbWFzaz0idXJsKCNtYXNrLTIpIj48L3BhdGg+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=';
export default {
getClass: getClass,
defaultSrc: defaultSrc
};

View File

@ -0,0 +1,16 @@
import { IBaseProps } from '../_util/base';
/**
* @description 头像,可展示头像以及用户名等简要信息。
*/
export interface IAvatarProps extends IBaseProps {
/**
* @description 尺寸x-small(80*80) small(88*88) medium(104*104) large(120*120)
* @default "medium"
*/
size: 'x-small' | 'small' | 'medium' | 'large';
/**
* @description 头像地址,默认为灰色的内置图片
*/
src: string;
}
export declare const AvatarDefaultProps: Partial<IAvatarProps>;

View File

@ -0,0 +1,4 @@
export var AvatarDefaultProps = {
size: 'medium',
src: '',
};

View File

@ -0,0 +1,12 @@
@import (reference) '../style/themes/index.less';
// 头像圆角
@avatar-img-radius: @corner-radius-md;
// 头像大小 80rpx
@avatar-size-x-small: @size-10;
// 头像大小 88rpx
@avatar-size-small: @size-11;
// 头像大小 104rpx
@avatar-size-medium: @size-13;
// 头像大小 120rpx
@avatar-size-large: @size-15;

View File

@ -0,0 +1,56 @@
<import-sjs
from="./index.sjs"
name="_sjs"
></import-sjs>
<view
class="ant-badge {{className || ''}}"
style="{{style}}"
>
<view class="ant-badge-body">
<slot></slot>
</view>
<view
a:if="{{type === 'dot'}}"
class="ant-badge-content"
style="{{_sjs.setPositionStyle(position, offsetX, offsetY)}}"
>
<view
class="ant-badge-dot {{stroke ? 'ant-badge-dot-stroke' : ''}}"
style="{{bgColor ? 'background-color: ' + bgColor + ';' : ''}}"
></view>
</view>
<view
a:else
class="ant-badge-content ant-badge-content-not-dot {{type === 'bubble' ? 'ant-badge-content-' + position + '-bubble' : ''}} {{stroke ? 'ant-badge-content-stroke' : ''}}"
style="{{bgColor ? 'background-color: ' + bgColor + ';' : ''}} {{_sjs.setBubbleStyle(type, position)}};{{_sjs.setPositionStyle(position, offsetX, offsetY)}}"
>
<view class="ant-badge-icon-container"></view>
<view class="ant-badge-content-text">
<slot name="text">
<block a:if="{{text}}">
<view
a:if="{{type === 'number'}}"
class="ant-badge-number"
>
<!--display: inline-->
<text a:if="{{_sjs.getOverCount(text)}}">99+</text>
<!--display: inline-->
<text a:else>{{text}}</text>
</view>
<view
a:if="{{type === 'text'}}"
class="ant-badge-text"
>
{{text}}
</view>
<view
a:if="{{type === 'bubble'}}"
class="ant-badge-bubble"
>
{{text}}
</view>
</block>
</slot>
</view>
</view>
</view>

View File

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

View File

@ -0,0 +1,3 @@
import { Component } from '../_util/simply';
import { BadgeFunctionalProps } from './props';
Component(BadgeFunctionalProps);

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,69 @@
@import (reference) './variable.less';
@badgePrefix: ant-badge;
.@{badgePrefix} {
display: inline-block;
position: relative;
&-content {
position: absolute;
display: flex;
height: 28 * @rpx;
align-self: center;
align-items: center;
font-size: 18 * @rpx;
padding: 4 * @rpx 8 * @rpx;
box-sizing: border-box;
word-break: keep-all;
justify-content: center;
top: 0;
left: 100%;
transform: translate(-50%, -50%);
&-stroke {
border: 2 * @rpx solid @COLOR_WHITE;
}
&-text {
padding-left: 4 * @rpx;
&:empty {
display: none;
}
.ant-badge-icon-container:empty ~ & {
padding-left: 0;
}
}
.ant-icon {
font-size: 18 * @rpx;
color: @COLOR_WHITE;
}
&-not-dot {
min-width: 28 * @rpx;
height: 28 * @rpx;
border-radius: 28 * @rpx;
display: flex;
background-color: @badge-background-color;
}
}
&-dot {
width: 20 * @rpx;
height: 20 * @rpx;
border-radius: 50%;
background-color: @badge-background-color;
&-stroke {
border: 2 * @rpx solid @COLOR_WHITE;
}
}
&-number,
&-text,
&-bubble {
color: @COLOR_WHITE;
}
}

View File

@ -0,0 +1,54 @@
function setPositionStyle(position) {
var offsetX = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '-50%';
var offsetY = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '-50%';
var transformStyle = "transform: translate(calc(".concat(offsetX, "), calc(").concat(offsetY, "));");
switch (position) {
case 'top-left':
return "top: 0; left: 0; ".concat(transformStyle);
case 'top-center':
return "top: 0; left: 50%; ".concat(transformStyle);
case 'top-right':
return "top: 0; left: 100%; ".concat(transformStyle);
case 'left':
return "top: 50%; left: 0; ".concat(transformStyle);
case 'right':
return "top: 50%; left: 100%; ".concat(transformStyle);
case 'bottom-left':
return "top: 100%; left: 0; ".concat(transformStyle);
case 'bottom-center':
return "top: 100%; left: 50%; ".concat(transformStyle);
case 'bottom-right':
return "top: 100%; left: 100%; ".concat(transformStyle);
default:
return "top: 0; left: 0; ".concat(transformStyle);
}
}
function setBubbleStyle(type, position) {
if (type !== 'bubble') return '';
switch (position) {
case 'top-left':
return 'border-bottom-right-radius: 0;';
case 'top-right':
return 'border-bottom-left-radius: 0;';
case 'bottom-left':
return 'border-top-right-radius: 0;';
case 'bottom-right':
return 'border-top-left-radius: 0;';
default:
return '';
}
}
function getOverCount(text) {
var overCount = false;
if (typeof text === 'number') {
if (text >= 100) {
overCount = true;
}
}
return overCount;
}
export default {
setPositionStyle: setPositionStyle,
setBubbleStyle: setBubbleStyle,
getOverCount: getOverCount
};

View File

@ -0,0 +1,41 @@
import { IBaseProps } from '../_util/base';
/**
* @description 徽标,红点、数字或文字。用于告诉用户待处理的事物或更新数。
*/
export interface IBadgeProps extends IBaseProps {
/**
* @description badge 类型
* @default dot
*/
type: 'dot' | 'number' | 'text' | 'bubble';
/**
* @description 红点内容,为空时表示只显示红点;可以是数字,也可以是文字;如果是数字,超过 99 会自动变成 ...
*/
text: string | number;
/**
* @description 相对于 children 所在访问left-top(左上角) top-right(右上角)
* @default "top-right"
*/
position: 'top-left' | 'top-center' | 'top-right' | 'left' | 'right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
/**
* @description 水平方向偏移量(字符串类型,需要带上像素单位)
* @default "-50%"
*/
offsetX: string;
/**
* @description 垂直方向偏移量(字符串类型,需要带上像素单位)
* @default "-50%"
*/
offsetY: number | string;
/**
* @description 是否有描边
* @default false
*/
stroke: boolean;
/**
* @description 背景色
*/
bgColor: string;
}
export declare const BadgeDefaultProps: Partial<IBadgeProps>;
export declare const BadgeFunctionalProps: Partial<IBadgeProps>;

View File

@ -0,0 +1,15 @@
export var BadgeDefaultProps = {
position: 'top-right',
stroke: false,
type: 'dot',
bgColor: '',
};
export var BadgeFunctionalProps = {
type: 'dot',
text: null,
position: 'top-right',
offsetX: null,
offsetY: null,
stroke: false,
bgColor: '',
};

View File

@ -0,0 +1,6 @@
@import (reference) '../style/themes/index.less';
// 字体颜色,同时作用于 stroke 边框
@badge-text-color: @COLOR_WHITE;
// 背景颜色
@badge-background-color: @COLOR_RED;

View File

@ -0,0 +1,46 @@
<import-sjs
from="./index.sjs"
name="utils"
></import-sjs>
<button
formType="{{formType}}"
hoverClass="{{utils.getHoverClass(loading, type, activeClassName)}}"
scope="{{scope}}"
onTap="{{onTap ? 'onTap' : ''}}"
onGetAuthorize="onGetAuthorize"
onFollowLifestyle="onFollowLifestyle"
onError="onError"
onGetUserInfo="onGetUserInfo"
onGetPhoneNumber="onGetPhoneNumber"
catchTap="{{catchTap ? 'catchTap' : ''}}"
publicId="{{publicId}}"
openType="{{openType}}"
class="ant-button {{inline ? 'ant-button-inline ' + utils.getClass(size) : ''}} {{'ant-button-' + type + (danger ? '-danger' : '')}} {{disabled || loading ? 'ant-button-disabled' : ''}} {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-button-wrap">
<ant-icon
a:if="{{!!icon}}"
type="{{icon}}"
></ant-icon>
<view class="ant-button-content-text {{icon ? 'ant-button-content-text-margin' : ''}}">
<slot></slot>
<view
a:if="{{!inline && subText}}"
class="ant-button-content-subtext"
>
{{subText}}
</view>
</view>
<view
a:if="{{loading}}"
class="ant-button-content-loading-container"
>
<loading
type="mini"
color="currentColor"
className="ant-button-content-loading"
></loading>
</view>
</view>
</button>

View File

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

View File

@ -0,0 +1,55 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { ButtonDefaultProps } from './props';
import fmtEvent from '../_util/fmtEvent';
Component({
props: ButtonDefaultProps,
methods: {
onTap: function (e) {
var _a = this.props, onTap = _a.onTap, disabled = _a.disabled, loading = _a.loading, onDisabledTap = _a.onDisabledTap;
if (disabled && onDisabledTap) {
var event_1 = fmtEvent(this.props, e);
onDisabledTap(event_1);
}
if (onTap && !disabled && !loading) {
var event_2 = fmtEvent(this.props, e);
return onTap(event_2);
}
},
catchTap: function (e) {
var _a = this.props, catchTap = _a.catchTap, disabled = _a.disabled, loading = _a.loading, onDisabledTap = _a.onDisabledTap;
if (disabled && onDisabledTap) {
var event_3 = fmtEvent(this.props, e);
onDisabledTap(event_3);
}
if (catchTap && !disabled && !loading) {
var event_4 = fmtEvent(this.props, e);
return catchTap(event_4);
}
},
onGetAuthorize: function (e) {
if (this.props.onGetAuthorize) {
this.props.onGetAuthorize(fmtEvent(this.props, e));
}
},
onFollowLifestyle: function (e) {
if (this.props.onFollowLifestyle) {
this.props.onFollowLifestyle(fmtEvent(this.props, e));
}
},
onError: function (e) {
if (this.props.onError) {
this.props.onError(fmtEvent(this.props, e));
}
},
onGetUserInfo: function (e) {
if (this.props.onGetUserInfo) {
this.props.onGetUserInfo(fmtEvent(this.props, e));
}
},
onGetPhoneNumber: function (e) {
if (this.props.onGetPhoneNumber) {
this.props.onGetPhoneNumber(fmtEvent(this.props, e));
}
},
},
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"loading": "../Loading/index",
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,136 @@
@import (reference) './variable.less';
@buttonPrefix: ant-button;
.@{buttonPrefix} {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: auto;
line-height: normal;
padding: @button-padding;
border-radius: @button-corner-radius;
border: 0 none;
box-sizing: border-box;
font-size: 36 * @rpx;
z-index: 2;
&-large {
font-size: 36 * @rpx;
padding: 24 * @rpx 24 * @rpx 24 * @rpx 24 * @rpx;
}
&-medium {
font-size: 34 * @rpx;
padding: 16 * @rpx 24 * @rpx 16 * @rpx 24 * @rpx;
}
&-small {
font-size: 30 * @rpx;
padding: 8 * @rpx 24 * @rpx 8 * @rpx 24 * @rpx;
}
&-primary {
color: @button-primary-color;
background-color: @button-primary-background-color;
box-shadow: inset 0 0 0 @button-border-size @COLOR_BRAND1;
}
&-default {
color: @COLOR_BRAND1;
background-color: @COLOR_CARD;
box-shadow: inset 0 0 0 @button-border-size @COLOR_BRAND1;
}
&-text {
color: @COLOR_BRAND1;
background-color: transparent;
box-shadow: none;
}
&-primary-danger {
color: @button-danger-color;
background-color: @COLOR_RED;
box-shadow: inset 0 0 0 @button-border-size @COLOR_RED;
}
&-default-danger {
color: @COLOR_RED;
background-color: @COLOR_CARD;
box-shadow: inset 0 0 0 @button-border-size @COLOR_RED;
}
&-text-danger {
color: @COLOR_RED;
background-color: transparent;
box-shadow: none;
}
&-text-active {
background-color: fade(@COLOR_WHITE_CHANGE, 92);
}
&-active {
filter: brightness(0.92);
}
&-disabled {
opacity: @button-disabled-opacity;
}
&-wrap {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
&-content-text-margin {
margin-left: @h-spacing-standard;
}
&-content-text {
&:empty {
margin-left: 0;
width: 0;
opacity: 0;
&::after {
content: '\00a0';
}
}
}
&-content-subtext {
font-size: @button-subtext-size;
opacity: 0.6;
}
&-content-loading-container {
display: flex;
justify-content: center;
align-items: center;
width: 33px;
height: 16px;
margin-left: 8px;
}
&-content-loading {
position: relative;
}
&-inline {
display: inline-block;
border-radius: @button-inline-corner;
.@{buttonPrefix}-content-loading-container {
width: 16px;
height: 16px;
}
.@{buttonPrefix}-content-loading {
transform: scale(0.5);
}
}
}

View File

@ -0,0 +1,24 @@
function getClass(size) {
var list = ['small', 'medium', 'large'];
if (list.indexOf(size) >= 0) {
return "ant-button-".concat(size);
}
return 'ant-button-medium';
}
function getHoverClass(loading, type, activeClassName) {
if (loading) {
return '';
}
var className = 'ant-button-active';
if (type === 'text') {
className += ' ant-button-text-active';
}
if (activeClassName) {
className += ' ' + activeClassName;
}
return className;
}
export default {
getClass: getClass,
getHoverClass: getHoverClass
};

View File

@ -0,0 +1,85 @@
import { IBaseProps } from '../_util/base';
/**
* @description 按钮,用户只需单击一下即可执行操作并做出选择。
* 常用于表单提交、界面跳转、模块引导点击。具体用法和小程序框架中 button 保持一致,在 button 基础上做了样式的封装。
* 封装后的按钮可改变按钮形态、增加 loading以及内置了几种不同样式的按钮。
*/
export interface IButtonProps extends IBaseProps {
/**
* @description 按钮类型
* @default default
*/
type?: 'default' | 'primary' | 'text';
/**
* @description 是否禁用
* @default false
*/
disabled?: boolean;
/**
* @description 按下时的类名
*/
activeClassName?: string;
/**
* @description 辅助文字,显示在第二行
*/
subText?: string;
/**
* @description 内联,不撑满父级宽度
* @default false
*/
inline?: boolean;
/**
* @description 内联尺寸
* @default medium
*/
size?: 'small' | 'medium' | 'large';
/**
* @description 按钮左侧图标
*/
icon?: string;
/**
* @description 是否加载中,加载中时不可点击
* @default false
*/
loading?: boolean;
/**
* @description 是否为危险按钮,危险按钮的颜色会变成红色
* @default false
*/
danger?: boolean;
/**
* @description 按钮原生类型,在表单提交时有效
* @default button
*/
formType?: 'button' | 'submit' | 'reset';
/**
* @description 点击回调
*/
onTap?: (event: any) => void;
/**
* @description 点击回调
*/
catchTap?: (event: any) => void;
/**
* @description 禁用时点击回调
*/
onDisabledTap?: (event: any) => void;
/**
* @description 生活号 id必须是当前小程序同主体且已关联的生活号open-type="lifestyle" 时有效。
*/
publicId?: string;
/**
* @description 开放能力。
*/
openType?: string;
/**
* @description 当 openType 为 getAuthorize 时有效。
*/
scope?: string;
onGetAuthorize?: (event: any) => void;
onFollowLifestyle?: (event: any) => void;
onError?: (event: any) => void;
onGetUserInfo?: (event: any) => void;
onGetPhoneNumber?: (event: any) => void;
}
export declare const ButtonDefaultProps: Partial<IButtonProps>;

View File

@ -0,0 +1,5 @@
export var ButtonDefaultProps = {
type: 'default',
formType: 'button',
size: 'medium',
};

View File

@ -0,0 +1,85 @@
@import (reference) '../style/themes/index.less';
/* size | 按钮内间距 */
@button-padding: @size-3;
/* corner-radius| 按钮圆角 */
@button-corner-radius: @corner-radius-md;
/* font-size | 副标题字号 */
@button-subtext-size: @font-size-subcontent;
/* color | 按钮边框宽度 */
@button-border-size: @border-width-standard;
/* opacity | disable状态不透明度 */
@button-disabled-opacity: @opacity-disabled;
/* color | 默认按钮文字色 */
@button-color: @COLOR_TEXT_PRIMARY;
/* color | 默认按钮背景色 */
@button-background-color: @COLOR_WHITE_CHANGE;
/* color | 默认按钮边框色 */
@button-border-color: @COLOR_BORDER;
/* color |primary按钮背景色 */
@button-primary-background-color: @COLOR_BRAND1;
/* color |primary按钮边框色 */
@button-primary-border-color: @COLOR_BRAND1;
/* color |primary按钮文字色 */
@button-primary-color: @COLOR_WHITE;
/* color |ghost按钮边框色 */
@button-ghost-border-color: @COLOR_BRAND1;
/* color |ghost按钮文字色 */
@button-ghost-color: @COLOR_BRAND1;
/* color |danger按钮背景色 */
@button-danger-background-color: @COLOR_RED;
/* color |danger按钮边框色 */
@button-danger-border-color: @COLOR_RED;
/* color |danger按钮文字色 */
@button-danger-color: @COLOR_WHITE;
/* color |danger-ghost按钮边框色 */
@button-danger-ghost-border-color: @COLOR_RED;
/* color |danger-ghost按钮文字色 */
@button-danger-ghost-color: @COLOR_RED;
/* color |light按钮背景色 */
@button-light-background-color: @COLOR_WATHET;
/* color |light按钮边框色 */
@button-light-border-color: @COLOR_WATHET;
/* color |light按钮文字色 */
@button-light-color: @COLOR_BRAND1;
/* size | 胶囊按钮圆角 */
@button-inline-corner: @corner-radius-md;
/* size | 胶囊按钮水平内间距 */
@button-inline-padding-h: @size-3;
/* size | 胶囊按钮垂直内间距 */
@button-inline-padding-v: @size-1;
/* font-size | 胶囊按钮大字号 */
@button-inline-size-large: @font-size-subtitle;
/* font-size | 胶囊按钮中字号 */
@button-inline-size-medium: @font-size-content;
/* font-size | 胶囊按钮小字号 */
@button-inline-size-small: @font-size-subcontent;
/* 图标尺寸 */
@button-icon-size: 44 * @rpx;

View File

@ -0,0 +1,84 @@
function keys(obj) {
if (typeof Object.keys === 'function') {
return Object.keys(obj);
}
}
function getClassName(value, index, showSelectableDatesOnly) {
var isSelected = value.isSelected,
isSelectedBegin = value.isSelectedBegin,
isSelectedEnd = value.isSelectedEnd,
isRowBegin = value.isRowBegin,
isRowEnd = value.isRowEnd,
inThisMonth = value.inThisMonth,
isToday = value.isToday,
disabled = value.disabled,
className = value.className,
isRange = value.isRange;
var classNames = {
disabled: disabled,
today: inThisMonth && isToday,
selected: inThisMonth && isSelected,
'selected-begin': inThisMonth && isSelectedBegin,
'selected-end': inThisMonth && isSelectedEnd,
'selected-row-begin': inThisMonth && isRowBegin && isSelected,
'selected-row-end': inThisMonth && isRowEnd && isSelected,
hidden: !inThisMonth || showSelectableDatesOnly && !isRange,
'row-end': index % 7 === 6
};
var result = "ant-calendar-cell ".concat(className || '');
keys(classNames).forEach(function (key) {
if (classNames[key]) {
result += " ant-calendar-cell-".concat(key);
}
});
return result;
}
function getSpaceClassName(index, items) {
var isNotEnd = index % 7 !== 6;
var nextItem = items[index + 1];
var nextSelected = nextItem && nextItem.isSelected && nextItem.inThisMonth;
var isSelected = items[index].isSelected;
var classNames = {
active: isNotEnd && isSelected && nextSelected
};
var result = 'ant-calendar-cell-space';
keys(classNames).forEach(function (key) {
if (classNames[key]) {
result += " ant-calendar-cell-space-".concat(key);
}
});
return result;
}
function getMarkCellClassName(index, items) {
if (items[index].length - 1 === index) {
return "ant-calendar-mark-cell ant-calendar-mark-cell-last";
}
return 'ant-calendar-mark-cell';
}
function isDisplay(index, items) {
// 找到需要当前月需要展示的日期最大最小索引
var _items_reduce = items.reduce(function (res, item) {
// !item.inThisMonth 被隐藏掉的日期
// !item.isRange 不在传入范围内的日期
if (!(!item.inThisMonth || !item.isRange)) {
if (res.minIndex === null || res.maxIndex === null) {
res.minIndex = item.index;
res.maxIndex = item.index;
}
res.minIndex = Math.min(res.minIndex, item.index);
res.maxIndex = Math.max(res.maxIndex, item.index);
}
return res;
}, {
minIndex: null,
maxIndex: null
});
if (_items_reduce.maxIndex === null || _items_reduce.maxIndex === null) return true;
return index >= Math.floor(_items_reduce.minIndex / 7) * 7 && index < Math.ceil(_items_reduce.maxIndex / 7) * 7;
}
export default {
getSpaceClassName: getSpaceClassName,
getClassName: getClassName,
getMarkCellClassName: getMarkCellClassName,
isDisplay: isDisplay
};

View File

@ -0,0 +1,110 @@
<import-sjs
from="./helper.sjs"
name="helper"
></import-sjs>
<import-sjs
from="./scroll.sjs"
name="scroll"
></import-sjs>
<view
class="ant-calendar {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-calendar-mark">
<block
a:for="{{markItems}}"
a:for-index="index"
a:for-item="item"
>
<view class="{{helper.getMarkCellClassName(index, markItems)}}">
<!--display: inline-->
<text>{{item}}</text>
</view>
</block>
</view>
<view
a:if="{{!!elementSize}}"
class="ant-calendar-sticky"
>
<view class="ant-calendar-sticky-title">
<slot name="calendarTitle">
<view class="ant-calendar-title">
{{monthList[headerState].title}}
</view>
</slot>
</view>
</view>
<scroll-view
scrollY="{{true}}"
class="ant-calendar-body"
data-elementsize="{{elementSize}}"
data-monthlist="{{monthList}}"
onScroll="{{scroll.handleScroll}}"
scrollIntoView="{{scrollIntoViewId}}"
scrollWithAnimation
scrollAnimationDuration="{{300}}"
disableLowerScroll="out-of-bounds"
disableUpperScroll="out-of-bounds"
ref="handleRef"
>
<block
a:for="{{monthList}}"
a:for-index="index"
a:for-item="currentMonth"
>
<view
class="ant-calendar-body-container {{currentMonth.className || ''}}"
style="{{currentMonth.style || ''}}"
>
<view class="ant-calendar-title-container">
<slot name="calendarTitle">
<view class="ant-calendar-title">{{currentMonth.title}}</view>
</slot>
</view>
<view class="ant-calendar-cells">
<block
a:for="{{currentMonth.cells}}"
a:for-index="index"
a:for-item="item"
>
<block a:if="{{helper.isDisplay(index, currentMonth.cells)}}">
<view
class="{{helper.getClassName(item, index, showSelectableDatesOnly)}}"
id="id_{{item.time}}"
data-time="{{item}}"
onTap="clickCell"
>
<view class="ant-calendar-cell-container">
<view class="ant-calendar-cell-top">
<!--display: inline-->
<text
a:if="{{item.top}}"
class="ant-calendar-cell-top-text {{item.top.className ? item.top.className : ''}}"
>{{item.top.label}}</text>
</view>
<view class="ant-calendar-cell-center">{{item.date}}</view>
<view class="ant-calendar-cell-bottom">
<slot
name="cell-bottom"
cell="{{item}}"
>
<!--display: inline-->
<text
a:if="{{item.bottom}}"
class="{{item.bottom.className}}"
>{{item.bottom.label}}</text>
</slot>
</view>
</view>
</view>
<view
a:if="{{index % 7 !== 6}}"
class="{{helper.getSpaceClassName(index, currentMonth.cells)}}"
></view>
</block>
</block>
</view>
</view>
</block>
</scroll-view>
</view>

View File

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

View File

@ -0,0 +1,213 @@
import { __assign, __awaiter, __generator, __spreadArray } from "tslib";
import dayjs from 'dayjs';
import equal from 'fast-deep-equal';
import { Component, triggerEvent, getValueFromProps } from '../_util/simply';
import { defaultLocaleText, CalendarDefaultProps, } from './props';
import { getMonthListFromRange, getSelectionModeFromValue, renderCells, getScrollIntoViewId, } from './utils';
import mixinValue from '../mixins/value';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
Component(CalendarDefaultProps, {
getInstance: function () {
if (this.$id) {
return my;
}
return this;
},
getBoundingClientRect: function (query) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(this.getInstance(), query)];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
},
scrollIntoView: function (value) {
this.updateScrollIntoViewId(getScrollIntoViewId(value));
},
clickCell: function (e) {
var _a, _b;
var time = e.currentTarget.dataset.time;
var clickDate = dayjs(time.time);
if (time.disabled) {
return;
}
var value = this.getValue();
var selectionModeFromValue = getSelectionModeFromValue(value);
var selectionMode = (_b = (_a = getValueFromProps(this, 'selectionMode')) !== null && _a !== void 0 ? _a : selectionModeFromValue) !== null && _b !== void 0 ? _b : 'range';
if (selectionMode === 'range') {
if (Array.isArray(value)) {
if (value.length === 1) {
var current = value[0];
if (dayjs(clickDate.toDate().getTime()).isBefore(dayjs(current))) {
this.updateValue([clickDate.toDate().getTime()]);
}
else {
this.updateValue([value[0], clickDate.toDate().getTime()]);
}
}
else {
this.updateValue([clickDate.toDate().getTime()]);
}
}
else {
this.updateValue([clickDate.toDate().getTime()]);
}
}
else if (selectionMode === 'single') {
this.updateValue(clickDate.toDate().getTime());
}
},
setCurrentMonth: function (e) {
this.setData({ headerState: e.month });
},
measurement: function () {
var elementSize = this.data.elementSize;
// 组件如果内嵌在 slot 里, 一定会被渲染出来, 但是此时 cellHight 为 0
// 此时需要重新计算
if (!elementSize || elementSize.cellHight === 0) {
this.measurementFn();
}
},
measurementFn: function () {
var _this = this;
Promise.all([
this.getBoundingClientRect('.ant-calendar-body-container'),
this.getBoundingClientRect('.ant-calendar-cells'),
this.getBoundingClientRect('.ant-calendar-title-container'),
])
.then(function (_a) {
var bodyContainer = _a[0], cellContainer = _a[1], Title = _a[2];
// 滚动的时候 top 和 bottom 等尺寸会变
// 所以只能依赖 height 来计算
var paddingHeight = bodyContainer.height - cellContainer.height - Title.height;
var monthTitleHeight = Title.height + paddingHeight;
var cellHight = cellContainer.height / (_this.data.monthList[0].cells.length / 7);
_this.setData({
elementSize: {
monthTitleHeight: monthTitleHeight,
cellHight: cellHight,
paddingHeight: paddingHeight,
},
});
})
.catch(function () {
_this.setData({ elementSize: null });
});
},
// scroll 触发滚动之后需要重置 scrollIntoViewId
updateScrollIntoViewId: function (id) {
var _this = this;
this.setData({ scrollIntoViewId: id });
var timer = setTimeout(function () {
_this.setData({ scrollIntoViewId: '' });
clearTimeout(timer);
});
},
updateValue: function (newValue) {
triggerEvent(this, 'change', newValue);
if (!this.isControlled()) {
this.update(newValue);
}
},
updateData: function () {
var _a = getValueFromProps(this, [
'monthRange',
'localeText',
'weekStartsOn',
'onFormatter',
'onMonthFormatter',
]), monthRange = _a[0], plocaleText = _a[1], pweekStartsOn = _a[2], onFormatter = _a[3], onMonthFormatter = _a[4];
var localeText = Object.assign({}, defaultLocaleText, plocaleText);
var markItems = __spreadArray([], localeText.weekdayNames, true);
var weekStartsOn = pweekStartsOn;
if (weekStartsOn === 'Sunday') {
var item = markItems.pop();
if (item)
markItems.unshift(item);
}
var value = this.getValue();
var start = dayjs(monthRange === null || monthRange === void 0 ? void 0 : monthRange[0]).startOf('d');
var end = dayjs(monthRange === null || monthRange === void 0 ? void 0 : monthRange[1]).startOf('d');
var monthRangeList = getMonthListFromRange(start, end);
var monthList = monthRangeList.map(function (p) {
var cells = renderCells(p, weekStartsOn, value, localeText,
// 如果monthRange传入异常用内置的时间范围
start.isAfter(end) || start.isSame(end)
? [monthRangeList[0], dayjs(monthRangeList[1]).endOf('month')]
: [start, end]);
if (onFormatter && typeof onFormatter === 'function') {
cells = cells.map(function (o) {
var _a;
var time = o.time, top = o.top, bottom = o.bottom, disabled = o.disabled, isSelectedBegin = o.isSelectedBegin, isSelectedEnd = o.isSelectedEnd, isSelected = o.isSelected, className = o.className, isRange = o.isRange;
var newState = (_a = onFormatter({
time: time,
top: top ? __assign({}, top) : undefined,
bottom: bottom ? __assign({}, bottom) : undefined,
disabled: disabled,
isSelectedBegin: isSelectedBegin,
isSelectedEnd: isSelectedEnd,
isSelected: isSelected,
className: className,
isRange: isRange,
}, value)) !== null && _a !== void 0 ? _a : {};
var result = __assign({}, o);
if (typeof newState === 'object') {
// 只允许修改的字段字段
['top', 'bottom', 'disabled', 'className'].forEach(function (key) {
if (key in newState) {
result[key] = newState[key];
}
});
}
return result;
});
}
var month = {
title: p.format(localeText.title),
className: '',
cells: cells,
};
if (onMonthFormatter && typeof onMonthFormatter === 'function') {
month = __assign(__assign({}, month), onMonthFormatter(p));
}
return month;
});
this.setData({ markItems: markItems, monthList: monthList });
},
}, {
elementSize: null,
markItems: [],
monthList: [],
headerState: 0,
scrollIntoViewId: '',
}, [mixinValue()], {
didMount: function () {
this.updateData();
this.measurementFn();
// 初始化默认值时,滚动到选中位置
var _a = getValueFromProps(this, [
'value',
'defaultValue',
]), value = _a[0], defaultValue = _a[1];
if (this.isControlled()) {
this.updateScrollIntoViewId(getScrollIntoViewId(value));
}
else {
defaultValue &&
this.updateScrollIntoViewId(getScrollIntoViewId(defaultValue));
}
},
didUpdate: function (prevProps, prevData) {
if (!this.isEqualValue(prevData)) {
// 滚动到已选的位置
var changedScrollIntoView = getValueFromProps(this, 'changedScrollIntoView');
changedScrollIntoView &&
this.updateScrollIntoViewId(getScrollIntoViewId(this.getValue()));
}
if (!equal(prevProps, this.props) || !this.isEqualValue(prevData)) {
this.updateData();
}
},
});

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,175 @@
@import (reference) './variable.less';
@checkboxItemPrefix: ant-calendar;
.@{checkboxItemPrefix} {
color: @COLOR_TEXT_PRIMARY;
position: relative;
display: flex;
flex-direction: column;
height: 100%;
&-body {
flex: 1;
}
&-sticky {
position: absolute;
top: 0px;
left: 0px;
max-height: @calendar-month-title-height;
width: 100%;
overflow: hidden;
top: @calendar-weekday-names-height;
z-index: @calendar-sticky-title-z-index;
}
&-mark {
height: @calendar-weekday-names-height;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
font-size: @calendar-weekday-names-font-size;
padding: 0 @calendar-cells-padding;
& &-cell {
flex: 1;
text-align: center;
width: calc((100% - 6 * @calendar-cell-space-size) / 7);
margin-right: @calendar-cell-space-size;
}
& &-cell-last {
margin-right: 0;
}
}
&-title {
color: @COLOR_TEXT_PRIMARY_DEFAULT;
font-size: @font-size-title;
height: @calendar-month-title-height;
line-height: @calendar-month-title-height;
padding-left: @calendar-weekday-names-left-padding;
margin-bottom: @calendar-weekday-names-bottom-margin;
background: @calendar-weekday-names-background-color;
}
&-cells {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
padding: 0 @calendar-cells-padding;
}
&-cell-space {
width: @calendar-cell-space-size;
height: @calendar-cell-height;
}
&-cell-space-active {
background: fade(@COLOR_BRAND1, 10%);
}
&-cell {
box-sizing: border-box;
width: calc((100% - 6 * @calendar-cell-space-size) / 7);
height: @calendar-cell-height;
margin-bottom: @calendar-cell-bottom-margin;
position: relative;
&-container {
box-sizing: border-box;
padding-top: @calendar-cell-top-padding;
height: 100%;
}
&-top {
color: @COLOR_TEXT_ASSIST_DEFAULT;
text-align: center;
font-size: @calendar-cell-top-font-size;
height: @calendar-cell-top-height;
&-text {
white-space: nowrap;
}
}
&-center {
text-align: center;
height: @calendar-cell-center-height;
font-size: @calendar-cell-center-font-size;
}
&-bottom {
color: @COLOR_TEXT_ASSIST_DEFAULT;
text-align: center;
font-size: @calendar-cell-bottom-font-size;
height: @calendar-cell-bottom-height;
}
&-selected {
background: fade(@COLOR_BRAND1, 10%);
}
&-selected-begin {
border-top-left-radius: @corner-radius-md;
border-bottom-left-radius: @corner-radius-md;
background: fade(@COLOR_BRAND1, 10%);
}
&-selected-end {
border-top-right-radius: @corner-radius-md;
border-bottom-right-radius: @corner-radius-md;
color: @COLOR_WHITE_DEFAULT;
}
&-selected-row-end {
border-top-right-radius: @corner-radius-md;
border-bottom-right-radius: @corner-radius-md;
}
&-selected-row-begin {
border-top-left-radius: @corner-radius-md;
border-bottom-left-radius: @corner-radius-md;
}
&-selected-begin &-container {
background: @COLOR_BRAND1_DEFAULT;
border-radius: @corner-radius-md;
color: @COLOR_WHITE_DEFAULT;
}
&-selected-end &-container {
background: @COLOR_BRAND1_DEFAULT;
border-radius: @corner-radius-md;
color: @COLOR_WHITE_DEFAULT;
}
&-selected-end &-top {
color: @COLOR_WHITE_DEFAULT;
}
&-selected-begin &-top {
color: @COLOR_WHITE_DEFAULT;
}
&-selected-end &-bottom {
color: @COLOR_WHITE_DEFAULT;
}
&-selected-begin &-bottom {
color: @COLOR_WHITE_DEFAULT;
}
}
&-cell-disabled {
opacity: @calendar-cell-disabled-opacity;
}
&-cell-hidden {
opacity: 0;
pointer-events: none;
}
}

View File

@ -0,0 +1,173 @@
import { IBaseProps } from '../_util/base';
export interface CalendarDate {
year: number;
month: number;
date: number;
}
export declare const defaultLocaleText: {
weekdayNames: string[];
title: string;
today: string;
start: string;
end: string;
startAndEnd: string;
};
export interface LocaleText {
/**
* 星期的名称。从周一到周日
* 默认为 ['一', '二', '三', '四', '五', '六', '日']
*/
weekdayNames: string[];
/**
* 月份标题的格式。 默认为 'YYYY年MM月'
*/
title: string;
/**
* 今日的文案。 默认为 '今日'
*/
today: string;
/**
* 开始的文案。 默认为 '开始'
*/
start: string;
/**
* 结束的文案。 默认为 '结束'
*/
startAndEnd: string;
/**
* 开始/结束的文案。 默认为 '开始/结束'
*/
end: string;
}
export interface CellState {
/**
* 类名
*/
className?: string;
/**
* 是否被禁止
*/
disabled: boolean;
/**
* 日历单元格的顶部内容
*/
top?: {
label: string;
className?: string;
};
/**
* 日历单元格的底部内容
*/
bottom?: {
label: string;
className?: string;
};
/**
* 时间戳
*/
time: number;
/**
* 日期
*/
date: number;
/**
* 是否被选择
*/
isSelected: boolean;
/**
* 是否是选择区间的开始
*/
isSelectedBegin: boolean;
/**
* 是否是选择区间的结束
*/
isSelectedEnd: boolean;
/**
* 是否是每一行的第一个
*/
isRowBegin: boolean;
isRowEnd: boolean;
inThisMonth: boolean;
/**
* 是否在传入范围内
*/
isRange: boolean;
index: number;
}
export type CalendarValue = number | number[];
export type SelectionMode = 'single' | 'range';
export interface ICalendarProps extends IBaseProps {
/**
* 初始值
*/
defaultValue?: CalendarValue;
/**
* 日历选择的日期,受控模式
*/
value?: CalendarValue;
/**
* 设置选择模式,单选或者连续区间, 默认为 'range'
*/
selectionMode?: SelectionMode;
/**
* 月份范围,默认为最近 3 个月
* 格式为时间戳
* @default [本月第一天的时间戳, 3个月后第一天的时间戳]
*/
monthRange?: [number, number];
/**
* 星期栏,以周几作为第一天显示,默认为 'Sunday'
*/
weekStartsOn?: 'Sunday' | 'Monday';
/**
* 国际化文案
*/
localeText?: Partial<LocaleText>;
/**
* 选中值改变后滚动视图
*/
changedScrollIntoView?: boolean;
/**
* 只展示在可选范围内的日期
*/
showSelectableDatesOnly?: boolean;
/**
* 日期变化回调
*/
onChange?: (date: CalendarValue) => void;
/**
* onFormatter 用于设置单元格的自定义数据
* @param cell 原始数据
* @param currentValue 当前的 value
* @returns 返回新的数据
*/
onFormatter?: (cell: Pick<CellState, 'className' | 'disabled' | 'top' | 'bottom' | 'time' | 'isSelectedBegin' | 'isSelectedEnd' | 'isSelected'>, currentValue: CalendarValue) => Pick<CellState, 'disabled' | 'top' | 'bottom'>;
/**
* onMonthFormatter 用于设置月份的自定义数据
* @param month 原始数据
* @returns 返回新的数据
*/
onMonthFormatter?: (month: any) => {
title?: string;
className?: string;
};
}
export declare const CalendarDefaultProps: {
defaultValue: any;
value: any;
selectionMode: string;
monthRange: [number, number];
weekStartsOn: string;
localeText: {
weekdayNames: string[];
title: string;
today: string;
start: string;
end: string;
startAndEnd: string;
};
onFormatter: any;
onMonthFormatter: any;
changedScrollIntoView: any;
showSelectableDatesOnly: boolean;
};

View File

@ -0,0 +1,21 @@
import { defaultMonthRange } from './utils';
export var defaultLocaleText = {
weekdayNames: ['一', '二', '三', '四', '五', '六', '日'],
title: 'YYYY年MM月',
today: '今日',
start: '开始',
end: '结束',
startAndEnd: '开始/结束',
};
export var CalendarDefaultProps = {
defaultValue: null,
value: null,
selectionMode: 'range',
monthRange: defaultMonthRange(),
weekStartsOn: 'Sunday',
localeText: defaultLocaleText,
onFormatter: null,
onMonthFormatter: null,
changedScrollIntoView: null,
showSelectableDatesOnly: false,
};

View File

@ -0,0 +1,45 @@
function handleScroll(event, ownerComponent) {
var currentScroll = event.detail.scrollTop;
var dataset = event.instance.getDataset();
var elementSize = dataset.elementsize,
monthList = dataset.monthlist;
if (!elementSize) {
return;
}
// 组件如果内嵌在 slot 里, 一定会被渲染出来, 但是此时 cellHight 为 0
if (elementSize.cellHight === 0) {
ownerComponent.callMethod('measurement');
return;
}
var instance = ownerComponent.selectComponent('.ant-calendar-sticky-title');
var sticky = ownerComponent.selectComponent('.ant-calendar-sticky');
if (sticky) {
sticky.setStyle({
display: currentScroll < 0 ? 'none' : 'block'
});
}
var monthHeight = elementSize.monthTitleHeight;
var paddingHeight = elementSize.paddingHeight;
var cellHeight = elementSize.cellHight;
var heightList = monthList.map(function (p) {
return monthHeight + cellHeight * p.cells.length / 7;
});
for (var i = 0; i < heightList.length; i++) {
if (currentScroll < heightList[i]) {
var topHeight = currentScroll - heightList[i] + monthHeight - paddingHeight;
topHeight = Math.max(topHeight, 0);
instance.setStyle({
transform: "translateY(-".concat(topHeight, "px)")
});
ownerComponent.callMethod('setCurrentMonth', {
month: topHeight > monthHeight * 0.8 ? i + 1 : i
});
break;
} else {
currentScroll = currentScroll - heightList[i];
}
}
}
export default {
handleScroll: handleScroll
};

View File

@ -0,0 +1,14 @@
import { Dayjs } from 'dayjs';
import { CellState, LocaleText, SelectionMode, CalendarValue } from './props';
export declare function getMonthListFromRange(start: Dayjs, end: Dayjs): Dayjs[];
export declare function defaultMonthRange(): [number, number];
/**
*
* @param month 月份的某一天
* @param weekStartsOn 日历以星期几开始
* @returns 获取当月日历所有的日子
*/
export declare function getDate(month: Dayjs, weekStartsOn: string): Dayjs[];
export declare function renderCells(cellsMonth: Dayjs, weekStartsOn: string, value: CalendarValue, localeText: LocaleText, monthRangeList: Dayjs[]): CellState[];
export declare function getSelectionModeFromValue(value?: CalendarValue): SelectionMode;
export declare function getScrollIntoViewId(value: CalendarValue): string;

View File

@ -0,0 +1,157 @@
import dayjs from 'dayjs';
import { isoWeekday } from '../_util/dayjs/iso-weekday';
export function getMonthListFromRange(start, end) {
if (start.isAfter(end))
throw new Error("Start time can't be later than end time.");
var result = [];
var current = start.date(1);
while (!current.isAfter(end)) {
result.push(current.date(1));
current = current.add(1, 'month');
}
return result;
}
export function defaultMonthRange() {
var start = dayjs().startOf('date');
var end = dayjs().startOf('date').add(2, 'month');
return [start.toDate().getTime(), end.toDate().getTime()];
}
/**
*
* @param month 月份的某一天
* @param weekStartsOn 日历以星期几开始
* @returns 获取当月日历所有的日子
*/
export function getDate(month, weekStartsOn) {
var startOfMonth = month.date(1);
var cells = [];
var iterator = startOfMonth
.subtract(isoWeekday(startOfMonth) % 7, 'day')
.startOf('day');
if (weekStartsOn === 'Monday') {
iterator = iterator.add(1, 'day');
if (iterator.isSame(startOfMonth, 'month') &&
!iterator.isSame(startOfMonth.startOf('date'), 'date')) {
iterator = iterator.add(-7, 'days');
}
}
var diffDay = startOfMonth.date(1).add(1, 'month').diff(iterator, 'day');
var lintCount = Math.ceil(diffDay / 7);
while (cells.length < lintCount * 7) {
cells.push(iterator);
iterator = iterator.add(1, 'day');
}
return cells;
}
export function renderCells(cellsMonth, weekStartsOn, value, localeText, monthRangeList) {
var _a;
var rangeStartDate = monthRangeList[0], rangeEndDate = monthRangeList[1];
var rowBeginDay = 0;
var rowEndDay = 6;
if (weekStartsOn === 'Monday') {
rowBeginDay = 1;
rowEndDay = 0;
}
var dates = getDate(cellsMonth, weekStartsOn);
if (!value) {
return dates.map(function (d, index) {
var isToday = dayjs().isSame(d, 'day');
var isRowBegin = d.isSame(cellsMonth.startOf('month'), 'date') ||
d.day() === rowBeginDay;
var isRowEnd = d.isSame(cellsMonth.endOf('month'), 'date') || d.day() === rowEndDay;
var top;
if (isToday) {
top = {
label: localeText.today,
};
}
return {
index: index,
disabled: false,
time: d.toDate().getTime(),
date: d.get('date'),
isSelected: false,
isSelectedBegin: false,
top: top,
isSelectedEnd: false,
inThisMonth: d.month() === cellsMonth.month(),
isRowBegin: isRowBegin,
isRowEnd: isRowEnd,
isRange: (d.isSame(rangeStartDate) || d.isAfter(rangeStartDate)) &&
(d.isSame(rangeEndDate) || d.isBefore(rangeEndDate)),
};
});
}
var selectBegin;
var selectEnd;
if (Array.isArray(value)) {
selectBegin = dayjs(value[0]);
selectEnd = dayjs((_a = value[1]) !== null && _a !== void 0 ? _a : value[0]);
}
else {
selectBegin = dayjs(value);
selectEnd = dayjs(value);
}
return dates.map(function (d, index) {
var isToday = dayjs().isSame(d, 'day');
var isRowBegin = d.isSame(cellsMonth.startOf('month'), 'date') || d.day() === rowBeginDay;
var isRowEnd = d.isSame(cellsMonth.endOf('month'), 'date') || d.day() === rowEndDay;
var isSelectedBegin = selectBegin.isSame(d, 'day');
var isSelectedEnd = selectEnd.isSame(d, 'day');
var isSelected = (!!selectBegin.isBefore(d, 'day') && !!selectEnd.isAfter(d, 'day')) ||
isSelectedBegin ||
isSelectedEnd;
var inThisMonth = d.month() === cellsMonth.month();
var time = d.toDate().getTime();
var topLabel = isToday ? localeText.today : '';
if (Array.isArray(value)) {
if (isSelectedBegin) {
if (isSelectedEnd && value.length === 2) {
topLabel = localeText.startAndEnd;
}
else {
topLabel = localeText.start;
}
}
else {
if (isSelectedEnd) {
topLabel = localeText.end;
}
}
}
return {
index: index,
disabled: false,
time: time,
date: d.get('date'),
isSelected: isSelected,
isSelectedBegin: isSelectedBegin,
top: { label: topLabel },
isSelectedEnd: isSelectedEnd,
inThisMonth: inThisMonth,
isRowBegin: isRowBegin,
isRowEnd: isRowEnd,
isRange: (d.isSame(rangeStartDate) || d.isAfter(rangeStartDate)) &&
(d.isSame(rangeEndDate) || d.isBefore(rangeEndDate)),
};
});
}
export function getSelectionModeFromValue(value) {
if (Array.isArray(value)) {
return 'range';
}
if (typeof value === 'number') {
return 'single';
}
return null;
}
// 获取滚动视图的元素id
export function getScrollIntoViewId(value) {
// 已选中时间滚动到可视区域内微信不支持id为数字开头
return "id_".concat(value &&
dayjs(Array.isArray(value) ? value[0] : value)
.startOf('d')
.subtract(7, 'd') // 需要定位的地方往前推7天让已选中时间定位到中间位置
.toDate()
.getTime());
}

View File

@ -0,0 +1,24 @@
@import (reference) '../style/themes/index.less';
/* size | 按钮内间距 */
@calendar-cell-top-height: 25 * @rpx;
@calendar-cell-top-font-size: 18 * @rpx;
@calendar-cell-bottom-height: 25 * @rpx;
@calendar-cell-bottom-font-size: 18 * @rpx;
@calendar-cell-center-height: 45 * @rpx;
@calendar-cell-center-font-size: 32 * @rpx;
@calendar-cell-top-padding: 7 * @rpx;
@calendar-cell-space-size: 10 * @rpx;
@calendar-cell-bottom-margin: 8 * @rpx;
@calendar-cell-height: (25 + 25 + 45 + 7 + 8) * @rpx;
@calendar-cell-disabled-opacity: @opacity-disabled;
@calendar-cells-padding: 16 * @rpx;
@calendar-sticky-title-z-index: 1000;
@calendar-month-title-height: 82 * @rpx;
@calendar-weekday-names-height: 88 * @rpx;
@calendar-weekday-names-font-size: 28 * @rpx;
@calendar-weekday-names-background-color: #f8f8f8;
@calendar-weekday-names-bottom-margin: 8 * @rpx;
@calendar-weekday-names-left-padding: @size-5;

View File

@ -0,0 +1,70 @@
<import-sjs
from="../index.sjs"
name="componentUtils"
></import-sjs>
<list
className="ant-checkbox-group {{className ? className : ''}} ant-checkbox-group-{{position}}"
style="{{style}}"
>
<checkbox-group
name="{{name}}"
value="{{mixin.value}}"
>
<view class="ant-checkbox-group-body">
<block a:if="{{position === 'vertical'}}">
<block
a:for="{{options}}"
a:for-index="index"
a:for-item="item"
>
<list-item>
<ant-checkbox
color="{{color}}"
checked="{{componentUtils.getCheckboxChecked(item, mixin.value)}}"
data-index="{{index}}"
value="{{item.value}}"
disabled="{{disabled || item.disabled}}"
onChange="onChange"
>
<slot
name="label"
value="{{item}}"
index="{{index}}"
>
<view class="ant-checkbox-group-item-label-default">
{{item.label}}
</view>
</slot>
</ant-checkbox>
</list-item>
</block>
</block>
<block a:else>
<block
a:for="{{options}}"
a:for-index="index"
a:for-item="item"
>
<ant-checkbox
color="{{color}}"
checked="{{componentUtils.getCheckboxChecked(item, mixin.value)}}"
data-index="{{index}}"
value="{{item.value}}"
disabled="{{disabled || item.disabled}}"
onChange="onChange"
>
<slot
name="label"
value="{{item}}"
index="{{index}}"
>
<view class="ant-checkbox-group-item-label-default">
{{item.label}}
</view>
</slot>
</ant-checkbox>
</block>
</block>
</view>
</checkbox-group>
</list>

View File

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

View File

@ -0,0 +1,36 @@
import { __spreadArray } from "tslib";
import { Component, triggerEvent, getValueFromProps } from '../../_util/simply';
import { CheckboxGroupDefaultProps } from './props';
import mixinValue from '../../mixins/value';
Component(CheckboxGroupDefaultProps, {
onChange: function (args, e) {
if (getValueFromProps(this, 'disabled')) {
return;
}
var event;
event = e;
var currentValue = this.getValue();
var index = event.currentTarget.dataset.index;
var selectValue = getValueFromProps(this, 'options')[index].value;
if (currentValue.indexOf(selectValue) > -1) {
currentValue = currentValue.filter(function (v) { return v !== selectValue; });
}
else {
currentValue = __spreadArray(__spreadArray([], currentValue, true), [selectValue], false);
}
if (!this.isControlled()) {
this.update(currentValue);
}
triggerEvent(this, 'change', currentValue, e);
},
}, null, [
mixinValue({
transformValue: function (val) {
var value = val || [];
return {
needUpdate: true,
value: value,
};
},
}),
]);

View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"list": "../../List/index",
"list-item": "../../List/ListItem/index",
"ant-checkbox": "../index"
}
}

View File

@ -0,0 +1,50 @@
@import (reference) '../variable.less';
@checkGroupPrefix: ant-checkbox-group;
.@{checkGroupPrefix} {
&-horizontal {
.@{checkGroupPrefix}-body {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.ant-list-item-line {
padding-right: 0;
}
.ant-checkbox-item {
flex-flow: 0;
}
.ant-list-item-line::after {
display: none;
}
}
}
&-header:empty,
&-footer:empty {
display: none;
}
&-header,
&-footer {
display: flex;
align-items: center;
padding: @v-spacing-standard @v-spacing-large;
line-height: 1.4;
font-size: 30 * @rpx;
color: @checkbox-header-color;
}
&-body {
position: relative;
overflow: hidden;
.ant-checkbox-item-content {
.ant-checkbox-group-item-label-default:not(:nth-child(1)) {
display: none;
}
}
}
}

View File

@ -0,0 +1,15 @@
import { IBaseProps } from '../../_util/base';
export interface ICheckboxGroupProps extends IBaseProps {
value: string[];
defaultValue: string[];
disabled?: boolean;
position: 'horizontal' | 'vertical';
color: string;
options: {
label?: string;
value?: string;
disabled?: boolean;
}[];
onChange?: (value: string[], e: any) => void;
}
export declare const CheckboxGroupDefaultProps: Partial<ICheckboxGroupProps>;

View File

@ -0,0 +1,8 @@
export var CheckboxGroupDefaultProps = {
value: null,
defaultValue: [],
disabled: false,
position: 'vertical',
color: '',
options: [],
};

View File

@ -0,0 +1,35 @@
<import-sjs
from="./index.sjs"
name="componentUtils"
></import-sjs>
<label
class="ant-checkbox-item {{className || ''}}"
style="{{style || ''}}"
>
<view class="ant-checkbox-item-container">
<view class="ant-checkbox-item-wrap">
<checkbox
class="ant-checkbox-item-base"
value="{{value}}"
onChange="onChange"
checked="{{mixin.value}}"
disabled="{{disabled}}"
></checkbox>
<view class="ant-checkbox-item-fake">
<view
class="ant-checkbox-item-fake-{{componentUtils.getClassName(mixin.value, disabled)}}"
style="{{mixin.value && !disabled && color ? 'background:' + color : ''}}"
>
<ant-icon
a:if="{{mixin.value}}"
type="CheckOutline"
className="ant-checkbox-item-fake-{{componentUtils.getClassName(mixin.value, disabled)}}-icon"
></ant-icon>
</view>
</view>
</view>
<view class="ant-checkbox-item-content {{disabled ? 'ant-checkbox-item-disabled' : ''}}">
<slot></slot>
</view>
</view>
</label>

View File

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

View File

@ -0,0 +1,17 @@
import { CheckboxDefaultProps } from './props';
import { Component, triggerEvent } from '../_util/simply';
import mixinValue from '../mixins/value';
Component(CheckboxDefaultProps, {
onChange: function (e) {
var value = !this.getValue();
if (!this.isControlled()) {
this.update(value);
}
triggerEvent(this, 'change', value, e);
},
}, null, [
mixinValue({
valueKey: 'checked',
defaultValueKey: 'defaultChecked',
}),
]);

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,92 @@
@import (reference) './variable.less';
@checkboxItemPrefix: ant-checkbox-item;
.@{checkboxItemPrefix} {
color: @COLOR_TEXT_PRIMARY;
margin-right: 16 * @rpx;
&-container {
display: flex;
align-items: center;
}
&-content {
padding-left: 10 * @rpx;
text-align: left;
}
&-wrap {
position: relative;
width: @checkbox-size;
height: @checkbox-size;
flex: 0 0 @checkbox-size;
}
&-base {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
&-fake {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
display: flex;
justify-content: center;
align-items: center;
&-icon {
background-color: @COLOR_CARD;
border: @checkbox-border-width solid @checkbox-border-color;
border-radius: @checkbox-corner-radius;
width: 100%;
height: 100%;
box-sizing: border-box;
}
&-checkedIcon {
border-radius: @checkbox-corner-radius;
background-color: @checkbox-background-color;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
&-icon {
color: @COLOR_WHITE;
font-size: 28 * @rpx;
}
}
&-disbaledIcon {
box-sizing: border-box;
border: @checkbox-border-width solid @checkbox-border-color;
border-radius: @checkbox-corner-radius;
width: 100%;
height: 100%;
background-color: @checkbox-disabled-background;
}
&-disabledCheckedIcon {
box-sizing: border-box;
border: @checkbox-border-width solid @checkbox-border-color;
background-color: @checkbox-disabled-background;
border-radius: @checkbox-corner-radius;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
&-icon {
color: @checkbox-border-color;
font-size: 28 * @rpx;
}
}
}
&-disabled {
opacity: @opacity-disabled;
}
}

View File

@ -0,0 +1,21 @@
function getClassName(checked, disabled) {
if (!checked && !disabled) {
return 'icon';
}
if (checked && !disabled) {
return 'checkedIcon';
}
if (!checked && disabled) {
return 'disbaledIcon';
}
if (checked && disabled) {
return 'disabledCheckedIcon';
}
}
function getCheckboxChecked(item, value) {
return (value || []).indexOf(item.value) > -1;
}
export default {
getClassName: getClassName,
getCheckboxChecked: getCheckboxChecked
};

View File

@ -0,0 +1,13 @@
import { IBaseProps } from '../_util/base';
/**
* @description 复选框,表单组件。
*/
export interface ICheckboxProps extends IBaseProps {
value?: any;
checked: boolean;
defaultChecked?: boolean;
disabled: boolean;
color: string;
onChange?: (checked: boolean, e: any) => void;
}
export declare const CheckboxDefaultProps: Partial<ICheckboxProps>;

View File

@ -0,0 +1,7 @@
export var CheckboxDefaultProps = {
value: null,
checked: null,
defaultChecked: null,
disabled: false,
color: '',
};

View File

@ -0,0 +1,21 @@
@import (reference) '../style/themes/index.less';
// header 颜色
@checkbox-header-color: @COLOR_TEXT_ASSIST;
/* size | 大小 */
@checkbox-size: @icon-size-sm;
/* corner-radius | 圆角 */
@checkbox-corner-radius: @corner-radius-circle;
/* border-width | 边框宽度 */
@checkbox-border-width: @border-width-standard;
/* color | 边框颜色 */
@checkbox-border-color: @COLOR_TEXT_WEAK;
/* color | check状态背景色 */
@checkbox-background-color: @COLOR_BRAND1;
/* color | disabled状态背景色 */
@checkbox-disabled-background: @COLOR_GREY_CARD;

View File

@ -0,0 +1,23 @@
<view
class="ant-checklist-item"
onTap="{{item.disabled || item.readonly ? '' : 'onChecklistItemClick'}}"
hoverClass="{{item.disabled || item.readonly ? '' : 'ant-checklist-item-hover'}}"
hoverStartTime="{{20}}"
hoverStayTime="{{40}}"
>
<view class="ant-checklist-item-content {{item.disabled ? 'ant-checklist-item-content-disabled' : ''}}">
<view class="ant-checklist-item-content-box">
<slot
name="content"
item="{{item}}"
></slot>
</view>
<view
a:if="{{checked}}"
class="ant-checklist-item-content-icon"
>
<slot name="icon"></slot>
</view>
</view>
<view class="ant-checklist-item-line"></view>
</view>

View File

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

View File

@ -0,0 +1,7 @@
import { Component, triggerEvent, getValueFromProps } from '../../_util/simply';
import { ChecklistItemDefaultProps } from './props';
Component(ChecklistItemDefaultProps, {
onChecklistItemClick: function () {
triggerEvent(this, 'change', getValueFromProps(this, 'item'));
},
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"icon": "../../Icon/index"
}
}

View File

@ -0,0 +1,77 @@
@import (reference) '../variable.less';
@import (reference) '../../style/mixins/hairline.less';
@checklistItemPrefix: ant-checklist-item;
.@{checklistItemPrefix} {
background-color: @COLOR_CARD;
&-hover {
background-color: @COLOR_BORDER;
}
&-content {
display: flex;
align-items: center;
padding: @v-spacing-large @h-spacing-large;
color: @COLOR_TEXT_PRIMARY;
&-disabled {
opacity: @opacity-disabled;
}
}
&-content-box {
flex: 1;
}
&-content-box-nut {
display: flex;
align-items: center;
}
&-image {
width: @size-9;
height: @size-9;
border-radius: @corner-radius-md;
}
&-text {
flex: 1;
margin-left: @h-spacing-large;
&-no-image {
margin-left: 0;
}
&-title {
color: @COLOR_TEXT_PRIMARY;
font-size: @font-size-list;
line-height: 48 * @rpx;
}
&-description {
font-size: @font-size-content;
color: @COLOR_TEXT_ASSIST;
margin-top: 2 * @rpx;
line-height: 36 * @rpx;
}
}
&-checked {
&-disabled {
opacity: @opacity-disabled;
}
}
&:last-child {
.ant-checklist-item-line {
display: none;
}
}
&-line {
margin-left: @h-spacing-large;
position: relative;
.hairline('bottom', @COLOR_BORDER);
}
}

View File

@ -0,0 +1,14 @@
import { IBaseProps } from '../../_util/base';
import { ChecklistItem } from '../props';
/**
* @description 可勾选列表单项
*/
export interface IChecklistItemProps extends IBaseProps {
item: ChecklistItem;
checked: boolean;
/**
* @description 当项选项值改变时触发
*/
onChange: (item: ChecklistItem) => void;
}
export declare const ChecklistItemDefaultProps: Partial<IChecklistItemProps>;

View File

@ -0,0 +1,4 @@
export var ChecklistItemDefaultProps = {
item: null,
checked: false,
};

View File

@ -0,0 +1,57 @@
<import-sjs
from="./index.sjs"
name="utils"
></import-sjs>
<view
class="ant-checklist {{className || ''}}"
style="{{style || ''}}"
>
<view class="ant-checklist-body">
<block
a:for="{{options}}"
a:for-index="index"
a:for-item="item"
>
<ant-checklist-item
checked="{{utils.getChecked(item.value, mixin.value, multiple)}}"
item="{{item}}"
onChange="onChange"
>
<view
slot="content"
class="ant-checklist-item-content-box-nut"
>
<slot
name="content"
item="{{item}}"
>
<image
a:if="{{item.image}}"
class="ant-checklist-item-image"
src="{{item.image}}"
></image>
<view class="ant-checklist-item-text {{item.image ? '' : 'ant-checklist-item-text-no-image'}}">
<view class="ant-checklist-item-text-title {{item.disabled ? 'ant-checklist-item-text-disabled' : ''}}">
{{item.title}}
</view>
<view
a:if="{{item.description}}"
class="ant-checklist-item-text-description {{item.disabled ? 'ant-checklist-item-text-disabled' : ''}}"
>
{{item.description}}
</view>
</view>
</slot>
</view>
<view slot="icon">
<slot name="icon">
<ant-icon
type="CheckOutline"
className="ant-checklist-item-check-icon"
></ant-icon>
</slot>
</view>
</ant-checklist-item>
</block>
</view>
</view>

View File

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

View File

@ -0,0 +1,49 @@
import { __spreadArray } from "tslib";
import { Component, triggerEventValues, getValueFromProps, } from '../_util/simply';
import { ChecklistDefaultProps } from './props';
import mixinValue from '../mixins/value';
Component(ChecklistDefaultProps, {
onChange: function (item) {
var _a = getValueFromProps(this, [
'multiple',
'options',
]), multiple = _a[0], options = _a[1];
var value;
value = item.value;
if (multiple) {
var currentValue_1 = this.getValue();
if (currentValue_1.indexOf(value) > -1) {
currentValue_1 = currentValue_1.filter(function (v) { return v !== value; });
}
else {
currentValue_1 = __spreadArray(__spreadArray([], currentValue_1, true), [value], false);
}
if (!this.isControlled()) {
this.update(currentValue_1);
}
triggerEventValues(this, 'change', [
currentValue_1,
options.filter(function (v) { return currentValue_1.indexOf(v.value) > -1; }),
]);
}
else {
if (!this.isControlled()) {
this.update(value);
}
triggerEventValues(this, 'change', [
value,
options.find(function (v) { return v.value === value; }),
]);
}
},
}, null, [
mixinValue({
transformValue: function (val) {
var value = val || [];
return {
needUpdate: true,
value: value,
};
},
}),
]);

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"ant-checklist-item": "./ChecklistItem/index",
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,15 @@
@import (reference) './variable.less';
@checklistPrefix: ant-checklist;
.@{checklistPrefix} {
&-body {
position: relative;
overflow: hidden;
}
&-item-check-icon {
font-size: @font-size-title;
color: @COLOR_BRAND1;
}
}

View File

@ -0,0 +1,9 @@
function getChecked(value, values, multiple) {
if (!multiple) {
return value === values;
}
return (values || []).indexOf(value) > -1;
}
export default {
getChecked: getChecked
};

View File

@ -0,0 +1,48 @@
import { IBaseProps } from '../_util/base';
/**
* @description 可勾选列表
*/
export interface ChecklistItem {
/**
* @description 可勾选项的描述文案
*/
description?: string;
/**
* @description 可勾选项的图片地址
*/
image?: string;
/**
* @description 可勾选项的标题文案
*/
title: string;
/**
* @description 可勾选项的值
*/
value: string | number;
disabled?: boolean;
readonly?: boolean;
}
export interface IChecklistProps extends IBaseProps {
/**
* @description 默认值
*/
value: Array<string | number> | string | number;
/**
* @description 默认值
*/
defaultValue: Array<string | number> | string | number;
/**
* @description 是否支持多选
* @default false
*/
multiple: boolean;
/**
* @description 可勾选列表数据配置选项内容
*/
options: Array<ChecklistItem>;
/**
* @description 可勾选列表值改变时触发
*/
onChange: (v: Array<string | number> | string | number, item: ChecklistItem | Array<ChecklistItem>, e: Record<string, any>) => void;
}
export declare const ChecklistDefaultProps: Partial<IChecklistProps>;

View File

@ -0,0 +1,6 @@
export var ChecklistDefaultProps = {
value: null,
defaultValue: null,
options: [],
multiple: false,
};

View File

@ -0,0 +1 @@
@import (reference) '../style/themes/index.less';

View File

@ -0,0 +1,78 @@
<import-sjs
from="./index.sjs"
name="utils"
></import-sjs>
<view
class="ant-collapse {{className ? className : ''}}"
style="{{style}}"
>
<block
a:for="{{items}}"
a:for-index="index"
a:for-item="item"
>
<view class="ant-collapse-item {{item.className || ''}} {{utils.isActive(mixin.value, index, item.disabled) ? 'ant-collapse-item-active' : ''}} {{item.disabled ? 'ant-collapse-item-disabled' : ''}}">
<view
class="ant-collapse-item-title"
data-active="{{utils.isActive(mixin.value, index, item.disabled)}}"
data-index="{{index}}"
data-id="{{$id}}"
onTap="onChange"
>
<view class="ant-collapse-item-line">
<view class="ant-collapse-item-title-node">
<slot
name="title"
value="{{item}}"
index="{{index}}"
current="{{mixin.value}}"
>
{{item.title}}
</slot>
</view>
<view class="ant-collapse-item-brief-container">
<view class="ant-collapse-item-brief-node">
<slot
name="brief"
value="{{item}}"
index="{{index}}"
current="{{mixin.value}}"
>
{{brief}}
</slot>
</view>
<view class="ant-collapse-item-title-arrow">
<slot
name="icon"
value="{{item}}"
index="{{index}}"
current="{{mixin.value}}"
>
<ant-icon type="{{utils.isActive(mixin.value, index, item.disabled) ? 'UpOutline' : 'DownOutline'}}"></ant-icon>
</slot>
</view>
</view>
</view>
</view>
<view
class="ant-collapse-item-content-wrap {{hasChange ? 'ant-collapse-item-content-wrap-transition' : ''}} ant-collapse-item-content-wrap{{$id ? '-' + $id : ''}}-{{index}}"
onTransitionEnd="resetContentHeight"
style="{{utils.getStyleHeight(index, contentHeight, item.disabled)}}"
data-index="{{index}}"
>
<view class="ant-collapse-item-content-container">
<view class="ant-collapse-item-content ant-collapse-item-content{{$id ? '-' + $id : ''}}-{{index}}">
<slot
name="content"
value="{{item}}"
index="{{index}}"
current="{{mixin.value}}"
>
{{item.content}}
</slot>
</view>
</view>
</view>
</view>
</block>
</view>

View File

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

View File

@ -0,0 +1,178 @@
import { __awaiter, __generator, __spreadArray } from "tslib";
import { Component, triggerEvent, getValueFromProps } from '../_util/simply';
import { CollapseDefaultProps } from './props';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
import createValue from '../mixins/value';
Component(CollapseDefaultProps, {
getInstance: function () {
if (this.$id) {
return my;
}
return this;
},
getBoundingClientRectWithBuilder: function (builder) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(this.getInstance(), builder(this.$id ? "-".concat(this.$id) : ''))];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
},
formatCurrent: function (val, props) {
var current = __spreadArray([], (val || []), true);
var items = props.items;
current = current.filter(function (item) {
if (!items[item] || items[item].disabled) {
return false;
}
return true;
});
if (props.accordion) {
current = current.length > 0 ? [current[0]] : [];
}
return __spreadArray([], current, true);
},
onChange: function (e) {
var itemIndex = parseInt(e.currentTarget.dataset.index, 10);
var _a = getValueFromProps(this, [
'items',
'accordion',
]), items = _a[0], accordion = _a[1];
if (items[itemIndex] && items[itemIndex].disabled) {
return;
}
var arr = this.getValue();
var current = __spreadArray([], arr, true);
var index = current.indexOf(itemIndex);
if (index >= 0) {
current.splice(index, 1);
}
else {
if (accordion) {
current = [itemIndex];
}
else {
current.push(itemIndex);
current.sort();
}
}
if (!this.isControlled()) {
this.update(current);
}
triggerEvent(this, 'change', current, e);
},
updateContentHeight: function (prevCurrent, nextCurrent) {
return __awaiter(this, void 0, void 0, function () {
var prevCurrentArray, nextCurrentArray, expandArray, closeArray, items, contentHeight;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
prevCurrentArray = prevCurrent;
nextCurrentArray = nextCurrent;
expandArray = [];
closeArray = [];
nextCurrentArray.forEach(function (item) {
if (prevCurrentArray.indexOf(item) < 0) {
expandArray.push(item);
}
});
prevCurrentArray.forEach(function (item) {
if (nextCurrentArray.indexOf(item) < 0) {
closeArray.push(item);
}
});
items = getValueFromProps(this, 'items');
return [4 /*yield*/, Promise.all(items.map(function (item, index) { return __awaiter(_this, void 0, void 0, function () {
var height;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(expandArray.indexOf(index) >= 0 ||
closeArray.indexOf(index) >= 0)) return [3 /*break*/, 2];
return [4 /*yield*/, this.getBoundingClientRectWithBuilder(function (id) { return ".ant-collapse-item-content".concat(id, "-").concat(index); })];
case 1:
height = (_a.sent()).height;
return [2 /*return*/, "".concat(height, "px")];
case 2: return [2 /*return*/, this.data.contentHeight[index]];
}
});
}); }))];
case 1:
contentHeight = _a.sent();
if (closeArray.length === 0) {
this.setData({
contentHeight: contentHeight,
});
}
else {
this.setData({
contentHeight: contentHeight,
});
setTimeout(function () {
contentHeight = contentHeight.map(function (item, index) {
if (closeArray.indexOf(index) >= 0) {
return '0px';
}
return item;
});
_this.setData({
contentHeight: contentHeight,
});
}, 10);
}
return [2 /*return*/];
}
});
});
},
resetContentHeight: function (e) {
var index = parseInt(e.currentTarget.dataset.index, 10);
if (this.getValue().indexOf(index) < 0) {
return;
}
var contentHeight = __spreadArray([], this.data.contentHeight, true);
contentHeight[index] = '';
this.setData({
contentHeight: contentHeight,
});
},
}, {
contentHeight: [],
hasChange: false,
}, [
createValue({
valueKey: 'current',
defaultValueKey: 'defaultCurrent',
transformValue: function (current, extra) {
var value = this.formatCurrent(current, extra ? extra.nextProps : getValueFromProps(this));
return {
needUpdate: true,
value: value,
};
},
}),
], {
didUpdate: function (prevProps, prevData) {
console.log(prevProps.items !== this.props.items, !this.isEqualValue(prevData));
if (prevProps.items !== this.props.items ||
!this.isEqualValue(prevData)) {
this.updateContentHeight(this.getValue(prevData), this.getValue());
}
},
didMount: function () {
var current = this.getValue();
var contentHeight = this.props.items.map(function (item, index) {
if (current.indexOf(index) >= 0) {
return '';
}
return '0px';
});
this.setData({
hasChange: true,
contentHeight: contentHeight,
});
},
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,136 @@
@import (reference) './variable.less';
@import '../style/mixins/hairline.less';
@collapsePrefix: ant-collapse-item;
.@{collapsePrefix} {
&-disabled {
.ant-collapse-item-title-node,
.ant-collapse-item-brief-container {
opacity: 0.4;
}
.@{collapsePrefix}-title:active {
background: @collapse-title-background-color;
transition: 0s;
}
}
&-line {
display: flex;
flex: 1;
border-bottom: 1px solid @COLOR_BORDER;
padding: 0 @collapse-title-padding @collapse-title-padding 0;
}
&-title {
position: relative;
display: flex;
text-align: justify;
align-items: center;
justify-content: space-between;
line-height: 48 * @rpx;
padding: @collapse-title-padding 0 0 @collapse-title-padding;
font-size: @collapse-title-size;
color: @collapse-title-color;
background-color: @collapse-title-background-color;
transition: all 300ms linear;
box-sizing: border-box;
&-node {
display: flex;
flex: 1;
max-width: 100%;
font-size: 34 * @rpx;
color: @COLOR_TEXT_PRIMARY;
}
&-arrow {
color: @COLOR_TEXT_WEAK;
}
&-icon {
width: 44 * @rpx;
height: 44 * @rpx;
overflow: hidden;
margin-right: 24 * @rpx;
.ant-icon {
font-size: 40 * @rpx;
}
& image {
width: 44 * @rpx;
height: 44 * @rpx;
}
}
&:active {
background-color: @COLOR_BORDER;
transition: 0s;
}
}
&-brief {
&-container {
display: flex;
.ant-icon {
font-size: 40 * @rpx;
}
}
&-node {
display: flex;
flex: 1;
font-size: 30 * @rpx;
color: @COLOR_TEXT_ASSIST;
margin-right: 8 * @rpx;
}
}
&-content {
color: @COLOR_TEXT_PRIMARY;
border-bottom: 1px solid @COLOR_BORDER;
padding: 24 * @rpx 24 * @rpx 24 * @rpx 0;
box-sizing: border-box;
&-container {
padding-left: 24 * @rpx;
background: @COLOR_WHITE_CHANGE;
}
&-wrap {
will-change: height;
overflow: hidden;
&-active {
animation: trigger1 0.2s;
}
&-non-active {
animation: trigger2 0.2s;
}
&-transition {
transition: height 0.2s ease-in-out;
}
&-first {
height: 0;
}
}
}
}
@keyframes trigger1 {
0% {
content: '';
}
100% {
content: '';
}
}
@keyframes trigger2 {
0% {
content: '';
}
100% {
content: '';
}
}

View File

@ -0,0 +1,23 @@
function isActive(current, index, disabled) {
if (disabled) {
return false;
}
return (current || []).indexOf(index) >= 0;
}
function getStyleHeight(index, contentHeight, disabled) {
if (disabled) {
return 'height: 0px';
}
var height = contentHeight[index];
if (height === '') {
return '';
}
if (height) {
return "height: ".concat(height);
}
return 'height: 0px';
}
export default {
isActive: isActive,
getStyleHeight: getStyleHeight
};

View File

@ -0,0 +1,35 @@
import { IBaseProps } from '../_util/base';
/**
* @description 手风琴
*/
export interface ICollapseProps extends IBaseProps {
/**
* @description 是否是手风琴模式,仅一个内容被展开
*/
/**
* @description 选中
*/
current?: number[];
/**
* @description 选中初始值
*/
defaultCurrent?: number[];
/**
* @description accordion模式
*/
accordion?: boolean;
/**
* @description 列表
*/
items?: {
title?: string;
content?: string;
disabled?: boolean;
className?: string;
}[];
/**
* @description collapse 切换时的回调
*/
onChange?: (current: number[] | undefined, e: Record<string, any>) => void;
}
export declare const CollapseDefaultProps: ICollapseProps;

View File

@ -0,0 +1,6 @@
export var CollapseDefaultProps = {
current: null,
defaultCurrent: [],
accordion: false,
items: [],
};

View File

@ -0,0 +1,16 @@
@import (reference) '../style/themes/index.less';
// 每一项的高度
@collapse-title-height: 96 * @rpx;
// 左右边距
@collapse-title-padding: @h-spacing-large;
// 背景色
@collapse-title-background-color: @COLOR_CARD;
// 字体颜色
@collapse-title-color: @COLOR_TEXT_PRIMARY;
// 字体大小
@collapse-title-size: @font-size-list;
// 箭头大小
@collapse-title-icon-size: 36 * @rpx;
// 内容背景色
@collapse-content-background-color: @COLOR_CARD;

View File

@ -0,0 +1,16 @@
<view
class="ant-container {{headerInBox ? 'ant-container-headerInBox' : 'ant-container-headerNotInBox'}} {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-container-header">
<view class="ant-container-header-title">
<slot name="title">{{title}}</slot>
</view>
<view class="ant-container-header-right">
<slot name="headerRight"></slot>
</view>
</view>
<view class="ant-container-content">
<slot></slot>
</view>
</view>

View File

@ -0,0 +1 @@
import '../_util/assert-component2';

View File

@ -0,0 +1,5 @@
import { ContainerDefaultProps } from './props';
import '../_util/assert-component2';
Component({
props: ContainerDefaultProps,
});

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,55 @@
@import (reference) './variable.less';
@import '../style/mixins/hairline.less';
@containerPrefix: ant-container;
.@{containerPrefix} {
border-radius: @container-radius;
margin-bottom: 24 * @rpx;
&-headerInBox {
background-color: @container-background-color;
.@{containerPrefix}-header {
padding: 0 @container-spacing;
.@{containerPrefix}-header-title,
.@{containerPrefix}-header-right {
position: relative;
.hairline('bottom');
}
}
}
&-content {
padding: @container-spacing;
background-color: @container-background-color;
border-radius: @container-radius;
}
&-header {
display: flex;
&-title {
font-size: @container-header-size;
font-weight: bold;
color: @container-header-color;
display: flex;
align-items: center;
height: 96 * @rpx;
flex: 1;
&:empty {
display: none;
}
}
&-right {
color: @COLOR_TEXT_ASSIST;
display: flex;
align-items: center;
height: 96 * @rpx;
justify-content: flex-end;
&:empty {
display: none;
}
}
.@{containerPrefix}-header-title:empty
+ .@{containerPrefix}-header-right:not(:empty) {
flex: 1;
}
}
}

View File

@ -0,0 +1,24 @@
import { IBaseProps } from '../_util/base';
/**
* @description 容器,依据最佳实践统一了元素的间距、圆角,并可根据具体情况选择使用 title 内容。
*/
export interface IContainerProps extends IBaseProps {
/**
* @description 标题
*/
title?: string;
/**
* @description 标题是否在容器内
* @default true
*/
headerInBox?: boolean;
/**
* @description 类名
*/
className?: string;
/**
* @description 样式
*/
style?: string;
}
export declare const ContainerDefaultProps: IContainerProps;

View File

@ -0,0 +1,3 @@
export var ContainerDefaultProps = {
headerInBox: true,
};

View File

@ -0,0 +1,12 @@
@import (reference) '../style/themes/index.less';
// 字体颜色
@container-header-color: @COLOR_TEXT_PRIMARY;
// 字体大小
@container-header-size: 32 * @rpx;
// 边距
@container-spacing: @h-spacing-large;
// 圆角
@container-radius: @corner-radius-lg;
// 背景
@container-background-color: @COLOR_CARD;

View File

@ -0,0 +1,80 @@
<template name="selector">
<view
class="ant-range-picker-selector-item {{active ? 'ant-range-picker-selector-item-active' : ''}}"
onTap="onChangeCurrentPickerType"
data-type="{{type}}"
>
<view
a:if="{{value}}"
class="ant-range-picker-selector-item-value"
>
{{value}}
</view>
<view
a:else
class="ant-range-picker-selector-item-placeholder"
>
{{placeholder}}
</view>
<icon
a:if="{{precision === 'year' || precision === 'month' || precision === 'day' || precision === 'hour'}}"
type="CalendarOutline"
className="ant-range-picker-selector-item-icon"
></icon>
</view>
</template>
<ant-picker
formattedValueText="{{formattedValueText}}"
className="ant-range-picker {{className || ''}}"
popClassName="{{!currentStartDate || !currentEndDate ? 'ant-range-picker-confirm-disabled' : ''}} {{popClassName || ''}}"
visible="{{visible}}"
style="{{style}}"
animationType="{{animationType}}"
options="{{columns}}"
value="{{currentValue}}"
disabled="{{disabled}}"
title="{{title}}"
placeholder="{{placeholder}}"
okText="{{okText}}"
cancelText="{{cancelText}}"
maskStyle="{{maskStyle}}"
maskClassName="{{maskClassName}}"
indicatorStyle="{{indicatorStyle}}"
indicatorClassName="{{indicatorClassName}}"
onChange="onChange"
onCancel="onCancel"
onOk="onOk"
onVisibleChange="onVisibleChange"
maskClosable="{{maskClosable}}"
>
<view
class="ant-range-picker-selector"
slot="content-header"
>
<template
is="selector"
data="{{ placeholder: startPlaceholder, active: pickerType === 'start', type: 'start', value: currentStartValueStr, precision: precision }}"
></template>
<view class="ant-range-picker-selector-split">{{splitCharacter}}</view>
<template
is="selector"
data="{{ placeholder: endPlaceholder, active: pickerType === 'end', type: 'end', value: currentEndValueStr, precision: precision }}"
></template>
</view>
<slot
name="content"
slot="content"
></slot>
<slot
name="title"
slot="title"
></slot>
<slot
name="prefix"
slot="prefix"
></slot>
<slot
name="suffix"
slot="suffix"
></slot>
</ant-picker>

View File

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

View File

@ -0,0 +1,310 @@
import { Component, triggerEvent, triggerEventValues, triggerEventOnly, getValueFromProps, } from '../../_util/simply';
import { resolveEventValue, resolveEventValues } from '../../_util/platform';
import { DateRangePickerDefaultProps } from './props';
import dayjs from 'dayjs';
import equal from 'fast-deep-equal';
import { getRangeData, getDateByValue, getValueByDate, getValidValue, } from '../util';
import computed from '../../mixins/computed';
import mixinValue from '../../mixins/value';
Component(DateRangePickerDefaultProps, {
// visible受控判断
isVisibleControlled: function () {
return 'visible' in getValueFromProps(this);
},
computed: function () {
var _a = this.data, currentStartDate = _a.currentStartDate, currentEndDate = _a.currentEndDate, pickerType = _a.pickerType;
var format = getValueFromProps(this, 'format');
if (pickerType)
return {
currentStartValueStr: currentStartDate
? dayjs(currentStartDate).format(format)
: '',
currentEndValueStr: currentEndDate
? dayjs(currentEndDate).format(format)
: '',
};
},
getMin: function (min) {
return min ? dayjs(min) : dayjs().subtract(10, 'year');
},
getMax: function (max) {
return max ? dayjs(max) : dayjs().add(10, 'year');
},
// didUpdate、弹窗打开、切换pickerType触发
setCurrentValue: function (currentProps) {
var _this = this;
var pickerVisible = this.pickerVisible; // 隐藏状态下从CValue触发展开状态使用当前数据
var precision = currentProps.precision;
var _a = this.data, pickerType = _a.pickerType, columns = _a.columns;
var realValue = this.getValue();
var _b = this.data, currentStartDate = _b.currentStartDate, currentEndDate = _b.currentEndDate;
var currentStartDateByCValue = (realValue === null || realValue === void 0 ? void 0 : realValue[0]) || null;
var currentEndDateByCValue = (realValue === null || realValue === void 0 ? void 0 : realValue[1]) || null;
// 展开状态说明在切换pickerType
if (pickerVisible) {
if (pickerType === 'start') {
if (!currentStartDate) {
currentStartDate = currentEndDate;
}
}
else {
// pickerType=end start已存在
// 结束时间默认选中开始
if (!currentEndDate) {
currentEndDate = currentStartDate;
}
}
}
else {
// 否则是在从cValue初始化
currentStartDate = currentStartDateByCValue;
currentEndDate = currentEndDateByCValue;
// 开始默认取优先取当前时间,不在时间范围内取开始时间
if (!currentStartDate) {
var min = this.getMin(currentProps.min).toDate();
var max = currentProps.max;
currentStartDate = new Date();
if ((min && dayjs(currentStartDate).isBefore(min, precision)) ||
(max && dayjs(currentStartDate).isAfter(max, precision)) ||
(currentEndDateByCValue &&
currentStartDate > currentEndDateByCValue)) {
currentStartDate = min;
}
}
}
var currentValue = getValueByDate(pickerType === 'start' ? currentStartDate : currentEndDate, precision);
var newColumns = this.generateData(currentValue, currentProps);
if (!equal(newColumns, columns)) {
this.setData({ columns: newColumns }, function () {
_this.setData({
currentStartDate: currentStartDate,
currentEndDate: currentEndDate,
currentValue: currentValue,
formattedValueText: _this.onFormat(),
});
});
}
else {
this.setData({
currentStartDate: currentStartDate,
currentEndDate: currentEndDate,
currentValue: currentValue,
formattedValueText: this.onFormat(),
});
}
},
/**
* 生成选项数据didmound、picker change、打开弹窗、切换picker type触发
*/
generateData: function (currentValue, currentProps) {
var precision = currentProps.precision, propsMin = currentProps.min, propsMax = currentProps.max;
var min = this.getMin(propsMin);
var max = this.getMax(propsMax);
if (max < min) {
return [];
}
var currentPickerDay = dayjs();
if (currentValue.length > 0) {
currentPickerDay = dayjs(getDateByValue(currentValue));
}
if (currentPickerDay < min || currentPickerDay > max) {
currentPickerDay = min;
}
var newColumns = getRangeData(precision, min, max, currentPickerDay, this.onFormatLabel.bind(this));
return newColumns;
},
onChange: function (selectedIdx) {
var _this = this;
var selectedIndex = resolveEventValues(getValidValue(selectedIdx))[0];
var _a = getValueFromProps(this, [
'format',
'precision',
'max',
'min',
]), format = _a[0], precision = _a[1], pmax = _a[2], pmin = _a[3];
var date = getDateByValue(selectedIndex);
var min = this.getMin(pmin);
var max = this.getMax(pmax);
if (dayjs(date).isBefore(min)) {
date = min.toDate();
selectedIndex = getValueByDate(date, precision);
}
if (dayjs(date).isAfter(max)) {
date = max.toDate();
selectedIndex = getValueByDate(date, precision);
}
var _b = this.data, pickerType = _b.pickerType, columns = _b.columns, currentEndDate = _b.currentEndDate, currentStartDate = _b.currentStartDate;
var newData = {
currentValue: selectedIndex,
formattedValueText: this.onFormat(),
};
if (pickerType === 'start') {
newData.currentStartDate = date;
if (currentEndDate && dayjs(date).isAfter(currentEndDate)) {
newData.currentEndDate = null;
}
}
else {
newData.currentEndDate = date;
if (currentStartDate && dayjs(date).isBefore(currentStartDate)) {
newData.currentStartDate = null;
}
}
var newColumns = this.generateData(selectedIndex, getValueFromProps(this));
if (!equal(newColumns, columns)) {
this.setData({
columns: newColumns,
}, function () {
_this.setData(newData);
triggerEventValues(_this, 'pickerChange', [
pickerType,
date,
dayjs(date).format(format),
]);
});
}
else {
this.setData(newData);
triggerEventValues(this, 'pickerChange', [
pickerType,
date,
dayjs(date).format(format),
]);
}
},
onCancel: function (e) {
triggerEventOnly(this, 'cancel', e);
},
onOk: function () {
var format = getValueFromProps(this, 'format');
var _a = this.data, currentStartDate = _a.currentStartDate, currentEndDate = _a.currentEndDate;
var realValue = [currentStartDate, currentEndDate];
if (!this.isControlled()) {
this.update(realValue);
}
triggerEventValues(this, 'ok', [
realValue,
realValue.map(function (v) { return dayjs(v).format(format); }),
]);
},
onFormatLabel: function (type, value) {
var onFormatLabel = getValueFromProps(this, 'onFormatLabel');
var formatValueByProps = onFormatLabel && onFormatLabel(type, value);
if (formatValueByProps !== undefined && formatValueByProps !== null) {
return String(formatValueByProps);
}
return this.defaultFormatLabel(type, value);
},
defaultFormatLabel: function (type, value) {
var suffixMap = {
year: '年',
month: '月',
day: '日',
hour: '时',
minute: '分',
second: '秒',
};
return "".concat(value).concat(suffixMap[type]);
},
defaultFormat: function (date, valueStrs) {
var _a = getValueFromProps(this, [
'format',
'splitCharacter',
]), format = _a[0], splitCharacter = _a[1];
if (format && valueStrs && valueStrs[0] && valueStrs[1]) {
return valueStrs.join("".concat(splitCharacter));
}
return '';
},
onFormat: function () {
var _a = getValueFromProps(this, [
'onFormat',
'format',
]), onFormat = _a[0], format = _a[1];
var realValue = this.getValue();
var formatValueByProps = onFormat &&
onFormat(realValue, realValue
? realValue.map(function (v) { return (v ? dayjs(v).format(format) : null); })
: null);
if (formatValueByProps !== undefined && formatValueByProps !== null) {
return formatValueByProps;
}
return this.defaultFormat(realValue, realValue
? realValue.map(function (v) { return (v ? dayjs(v).format(format) : null); })
: null);
},
/**
* 显示/隐藏切换
* @param visible
*/
onVisibleChange: function (visible) {
if (!this.isVisibleControlled() && visible) {
this.setData({ pickerType: 'start' });
this.setCurrentValue(getValueFromProps(this));
this.pickerVisible = visible;
}
triggerEvent(this, 'visibleChange', resolveEventValue(visible));
},
onChangeCurrentPickerType: function (e) {
var type = e.currentTarget.dataset.type;
var pickerType = this.data.pickerType;
if (type !== pickerType) {
this.setData({
pickerType: type,
});
this.setCurrentValue(getValueFromProps(this));
}
},
}, {
currentValue: [],
columns: [],
pickerType: 'start',
currentStartDate: null,
currentEndDate: null,
forceUpdate: 0,
formattedValueText: '',
}, [
mixinValue({
transformValue: function (value) {
return {
value: value && value[0] && value[1]
? [dayjs(value[0]).toDate(), dayjs(value[1]).toDate()]
: undefined,
needUpdate: true,
};
},
}),
computed(),
], {
pickerVisible: false,
didMount: function () {
this.pickerVisible = false;
var _a = getValueFromProps(this, [
'visible',
'defaultVisible',
]), visible = _a[0], defaultVisible = _a[1];
this.setData({
visible: this.isVisibleControlled() ? visible : defaultVisible,
formattedValueText: this.onFormat(),
});
},
didUpdate: function (prevProps, prevData) {
var currentProps = getValueFromProps(this);
var visible = getValueFromProps(this, 'visible');
if (this.isVisibleControlled() && !equal(prevProps.visible, visible)) {
this.setData({ visible: visible });
this.setCurrentValue(currentProps);
this.pickerVisible = visible;
}
if (!this.isEqualValue(prevData)) {
this.setData({
forceUpdate: this.data.forceUpdate + 1,
formattedValueText: this.onFormat(),
});
if (this.pickerVisible) {
// 展开状态才更新picker的数据否则下次triggerVisible触发
this.setCurrentValue(currentProps);
}
}
},
});

Some files were not shown because too many files have changed in this diff Show More