优化日历控件

This commit is contained in:
liaoxuezhi 2019-12-18 18:57:07 +08:00
parent 8f3d4148de
commit 8e327e6981
12 changed files with 788 additions and 858 deletions

View File

@ -35,17 +35,31 @@ $dark: $gray800 !default;
$remFactor: 16px !default;
// 字体相关
$fontFamilySansSerif: -apple-system, BlinkMacSystemFont, 'SF Pro SC',
'SF Pro Text', 'Helvetica Neue', Helvetica, 'PingFang SC', 'Segoe UI', Roboto,
'Hiragino Sans GB', 'Arial', 'microsoft yahei ui', 'Microsoft YaHei', SimSun,
sans-serif !default;
$fontFamilyMonospace: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
'Courier New', monospace !default;
$fontFamilySansSerif: -apple-system,
BlinkMacSystemFont,
'SF Pro SC',
'SF Pro Text',
'Helvetica Neue',
Helvetica,
'PingFang SC',
'Segoe UI',
Roboto,
'Hiragino Sans GB',
'Arial',
'microsoft yahei ui',
'Microsoft YaHei',
SimSun,
sans-serif !default;
$fontFamilyMonospace: SFMono-Regular,
Menlo,
Monaco,
Consolas,
'Liberation Mono',
'Courier New',
monospace !default;
$fontFamilyBase: $fontFamilySansSerif !default;
$fontSizeBase: px2rem(
14px
) !default; // Assumes the browser default, typically `16px`
$fontSizeBase: px2rem(14px) !default; // Assumes the browser default, typically `16px`
$fontSizeMd: px2rem(16px) !default;
$fontSizeLg: px2rem(20px) !default;
$fontSizeXl: px2rem(24px) !default;
@ -85,13 +99,11 @@ $boxShadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
$boxShadowLg: 0 1rem 3rem rgba($black, 0.175) !default;
// 窗口适配
$breakpoints: (
xs: 0,
$breakpoints: (xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
) !default;
xl: 1200px) !default;
// 段落间距
$paragraph-marginBottom: 1rem !default;
@ -147,14 +159,10 @@ $Layout-aside--md-width: px2rem(250px) !default;
$Layout-aside--lg-width: px2rem(300px) !default;
$Layout-aside--folded-width: px2rem(60px) !default;
$Layout-aside-bg: $dark !default;
$Layout-aside-onAcitve-bg: saturate(
darken($Layout-aside-bg, 5%),
2.5%
) !default;
$Layout-aside-subList-bg: saturate(
darken($Layout-aside-bg, 10%),
2.5%
) !default;
$Layout-aside-onAcitve-bg: saturate(darken($Layout-aside-bg, 5%),
2.5%) !default;
$Layout-aside-subList-bg: saturate(darken($Layout-aside-bg, 10%),
2.5%) !default;
$Layout-aside-onHover-bg: saturate(darken($Layout-aside-bg, 3%), 2.5%) !default;
$Layout-aside-color: desaturate(lighten($Layout-aside-bg, 40%), 10%) !default;
@ -175,16 +183,14 @@ $Layout-asideLink-arrowColor: $Layout-asideLink-color !default;
$Layout-asideLink-onActive-arrowColor: $Layout-asideLink-onActive-color !default;
$Layout-asideLabel-color: darken($Layout-aside-color, 10%) !default;
$Layout-brand-bg: $dark !default;
$Layout-brandBar-color: desaturate(
lighten($Layout-brand-bg, 40%),
10%
) !default;
$Layout-brandBar-color: desaturate(lighten($Layout-brand-bg, 40%),
10%) !default;
$Layout-brand-color: lighten($Layout-brandBar-color, 25%) !default;
$Layout-header-height: px2rem(50px) !default;
$Layout-headerBar-borderBottom: none !default;
$Layout-header-bg: $white !default;
$Layout-header-boxShadow: 0 px2rem(2px) px2rem(2px) rgba(0, 0, 0, 0.05),
0 1px 0 rgba(0, 0, 0, 0.05) !default;
0 1px 0 rgba(0, 0, 0, 0.05) !default;
$Layout-nav-height: px2rem(40px) !default;
$Layout-nav-lgHeight: px2rem(50px) !default;
$Layout-nav--folded-height: px2rem(50px) !default;
@ -217,9 +223,7 @@ $Modal-header-bg: darken($Modal-bg, 2.5%) !default;
$Modal-title-lineHeight: $lineHeightBase !default;
$Modal-title-fontSize: $fontSizeBase !default;
$Modal-title-color: $text--loud-color !default;
$Modal-header-paddingY: (
$Modal-header-height - $Modal-title-lineHeight * $Modal-title-fontSize
) / 2 !default;
$Modal-header-paddingY: ($Modal-header-height - $Modal-title-lineHeight * $Modal-title-fontSize) / 2 !default;
$Modal-header-paddingX: $gap-md !default;
$Modal-close-width: px2rem(12px) !default;
$Modal-close-color: $text--muted-color !default;
@ -227,10 +231,8 @@ $Model-close-onHover-color: $text-color !default;
$Modal-body-paddingX: $gap-md !default;
$Modal-body-paddingY: $gap-md !default;
$Modal-body--noHeader-paddingTop: $gap-base;
$Modal-body-borderTop: $Modal-content-borderWidth solid
lighten($Modal-content-borderColor, 5%) !default;
$Modal-body-borderBottom: $Modal-content-borderWidth solid
lighten($Modal-content-borderColor, 5%) !default;
$Modal-body-borderTop: $Modal-content-borderWidth solid lighten($Modal-content-borderColor, 5%) !default;
$Modal-body-borderBottom: $Modal-content-borderWidth solid lighten($Modal-content-borderColor, 5%) !default;
$Modal-footer-padding: $gap-sm !default;
$Modal-footer-marginY: 0 !default;
$Modal-footer-marginX: 0 !default;
@ -353,10 +355,8 @@ $Alert-marginBottom: $gap-md !default;
$Alert--danger-color: #a94442 !default;
$Alert--danger-bg: #f2dede !default;
$Alert--danger-borderColor: darken(
adjust-hue($Alert--danger-bg, -10),
5%
) !default;
$Alert--danger-borderColor: darken(adjust-hue($Alert--danger-bg, -10),
5%) !default;
$Alert--info-color: #31708f !default;
$Alert--info-bg: #d9edf7 !default;
@ -364,17 +364,13 @@ $Alert--info-borderColor: darken(adjust-hue($Alert--info-bg, -10), 5%) !default;
$Alert--success-color: #3c763d !default;
$Alert--success-bg: #dff0d8 !default;
$Alert--success-borderColor: darken(
adjust-hue($Alert--success-bg, -10),
5%
) !default;
$Alert--success-borderColor: darken(adjust-hue($Alert--success-bg, -10),
5%) !default;
$Alert--warning-color: #8a6d3b !default;
$Alert--warning-bg: #fcf8e3 !default;
$Alert--warning-borderColor: darken(
adjust-hue($Alert--warning-bg, -10),
5%
) !default;
$Alert--warning-borderColor: darken(adjust-hue($Alert--warning-bg, -10),
5%) !default;
// spinner
$Spinner-overlay-bg: rgba(255, 255, 255, 0.4) !default;
@ -462,8 +458,7 @@ $Table-tree-borderColor: $Table-borderColor !default;
$TableCell-height: px2rem(40px) !default;
$TableCell-paddingX: $gap-sm !default;
$TableCell--edge-paddingX: $gap-md !default;
$TableCell-paddingY: ($TableCell-height - $Table-fontSize * $Table-lineHeight) /
2;
$TableCell-paddingY: ($TableCell-height - $Table-fontSize * $Table-lineHeight) / 2;
$Table-placeholder-height: px2rem(100px) !default;
// $Table-checkCell-width: px2rem(50px) !default;
@ -637,15 +632,10 @@ $Form-input-placeholderColor: $text--muted-color !default;
$Form-input-lineHeight: 20/14 !default;
$Form-input-fontSize: $Form-fontSize !default;
$Form-input-boxShadow: none !default;
$Form-input-paddingY: (
$Form-input-height - $Form-input-lineHeight * $Form-input-fontSize -
px2rem(2px)
)/2 !default;
$Form-input-paddingY: ($Form-input-height - $Form-input-lineHeight * $Form-input-fontSize - px2rem(2px))/2 !default;
$Form-input-paddingX: px2rem(12px) !default;
$Form-input-marginBottom: px2rem(6px) !default;
$Form-label-paddingTop: (
$Form-input-height - $Form-input-lineHeight * $Form-input-fontSize
)/2 !default;
$Form-label-paddingTop: ($Form-input-height - $Form-input-lineHeight * $Form-input-fontSize)/2 !default;
$Form-input-addOnBg: #edf1f2 !default;
$Form-input-addOnColor: $text-color !default;
@ -687,14 +677,10 @@ $Form-select-onFocused-borderColor: $Form-input-onFocused-borderColor !default;
$Form-select-onError-borderColor: $Form-input-onError-borderColor !default;
$Form-selectOption-height: $Form-input-height !default;
$Form-selectValue-color: $info !default;
$Form-selectValue-bg: saturate(
lighten($Form-selectValue-color, 40%),
2.5%
) !default;
$Form-selectValue-borderColor: saturate(
lighten($Form-selectValue-color, 30%),
2.5%
) !default;
$Form-selectValue-bg: saturate(lighten($Form-selectValue-color, 40%),
2.5%) !default;
$Form-selectValue-borderColor: saturate(lighten($Form-selectValue-color, 30%),
2.5%) !default;
$Form-selectValue-fontSize: $fontSizeSm !default;
$Form-select-caret-vender: 'FontAwesome' !default;
$Form-select-caret-icon: '\f0d7' !default;
@ -723,10 +709,7 @@ $InputGroup-addOn-bg: $Form-input-addOnBg !default;
$InputGroup-addOn-borderWidth: $Form-input-borderWidth !default;
$InputGroup-addOn-borderColor: $Form-input-borderColor !default;
$InputGroup-addOn-borderRadius: $Form-input-borderRadius !default;
$InputGroup-paddingY: (
$InputGroup-height - $Form-input-lineHeight * $Form-input-fontSize -
px2rem(2px)
)/2 !default;
$InputGroup-paddingY: ($InputGroup-height - $Form-input-lineHeight * $Form-input-fontSize - px2rem(2px))/2 !default;
$InputGroup-paddingX: px2rem(10px) !default;
$InputGroup-addOn-onFocused-borderColor: $Form-input-onFocused-borderColor !default;
$InputGroup-select-borderWidth: $Form-select-borderWidth !default;
@ -752,10 +735,7 @@ $Button-height: $Form-input-height !default;
$Button-mimWidth: auto !default;
$Button-lineHeight: $Form-input-lineHeight !default;
$Button-paddingX: px2rem(12px) !default;
$Button-paddingY: (
$Button-height - $Button-borderWidth * 2 - $Button-lineHeight *
$Button-fontSize
)/2 !default;
$Button-paddingY: ($Button-height - $Button-borderWidth * 2 - $Button-lineHeight * $Button-fontSize)/2 !default;
$Button--iconOnly-minWidthRate: 4 / 3 !default;
@ -763,40 +743,28 @@ $Button--xs-fontSize: $fontSizeXs !default;
$Button--xs-height: px2rem(22px) !default;
$Button--xs-lineHeight: 18 / 11 !default;
$Button--xs-paddingX: px2rem(5px) !default;
$Button--xs-paddingY: (
$Button--xs-height - $Button-borderWidth * 2 - $Button--xs-lineHeight *
$Button--xs-fontSize
)/2 !default;
$Button--xs-paddingY: ($Button--xs-height - $Button-borderWidth * 2 - $Button--xs-lineHeight * $Button--xs-fontSize)/2 !default;
$Button--sm-fontSize: $fontSizeSm !default;
$Button--sm-height: px2rem(30px) !default;
$Button--sm-lineHeight: 18 / 12 !default;
$Button--sm-paddingX: px2rem(8px) !default;
$Button--sm-paddingY: (
$Button--sm-height - $Button-borderWidth * 2 - $Button--sm-lineHeight *
$Button--sm-fontSize
)/2 !default;
$Button--sm-paddingY: ($Button--sm-height - $Button-borderWidth * 2 - $Button--sm-lineHeight * $Button--sm-fontSize)/2 !default;
$Button--md-fontSize: $Button-fontSize !default;
$Button--md-height: $Button-height !default;
$Button--md-lineHeight: $Button-lineHeight !default;
$Button--md-paddingX: $Button-paddingX !default;
$Button--md-paddingY: (
$Button--md-height - $Button-borderWidth * 2 - $Button--md-lineHeight *
$Button--md-fontSize
)/2 !default;
$Button--md-paddingY: ($Button--md-height - $Button-borderWidth * 2 - $Button--md-lineHeight * $Button--md-fontSize)/2 !default;
$Button--lg-fontSize: $fontSizeLg !default;
$Button--lg-height: px2rem(46px) !default;
$Button--lg-lineHeight: 24 / 20 !default;
$Button--lg-paddingX: px2rem(16px) !default;
$Button--lg-paddingY: (
$Button--lg-height - $Button-borderWidth * 2 - $Button--lg-lineHeight *
$Button--lg-fontSize
)/2 !default;
$Button--lg-paddingY: ($Button--lg-height - $Button-borderWidth * 2 - $Button--lg-lineHeight * $Button--lg-fontSize)/2 !default;
$Button-boxShadow: inset 0 1px 0 rgba($white, 0.15),
0 1px 1px rgba($black, 0.075) !default;
0 1px 1px rgba($black, 0.075) !default;
$Button-onFocus-boxShadow: none !default;
$Button-onActive-boxShadow: inset 0 3px 5px rgba($black, 0.125) !default;
$Button-onDisabled-opacity: 0.65 !default;
@ -808,8 +776,10 @@ $Button-borderRadius: $borderRadius !default;
$Button--lg-borderRadius: $borderRadius !default;
$Button--sm-borderRadius: $borderRadius !default;
$Button-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !default;
$Button-transition: color 0.15s ease-in-out,
background-color 0.15s ease-in-out,
border-color 0.15s ease-in-out,
box-shadow 0.15s ease-in-out !default;
$Button--primary-bg: $primary !default;
$Button--primary-border: $Button--primary-bg !default;
@ -818,26 +788,20 @@ $Button--primary-onHover-bg: darken($Button--primary-bg, 7.5%) !default;
$Button--primary-onHover-border: darken($Button--primary-border, 10%) !default;
$Button--primary-onHover-color: $Button--primary-color !default;
$Button--primary-onActive-bg: darken($Button--primary-bg, 10%) !default;
$Button--primary-onActive-border: darken(
$Button--primary-border,
12.5%
) !default;
$Button--primary-onActive-border: darken($Button--primary-border,
12.5%) !default;
$Button--primary-onActive-color: $Button--primary-color !default;
$Button--secondary-bg: $secondary !default;
$Button--secondary-border: $Button--secondary-bg !default;
$Button--secondary-color: $white !default;
$Button--secondary-onHover-bg: darken($Button--secondary-bg, 7.5%) !default;
$Button--secondary-onHover-border: darken(
$Button--secondary-border,
10%
) !default;
$Button--secondary-onHover-border: darken($Button--secondary-border,
10%) !default;
$Button--secondary-onHover-color: $Button--secondary-color !default;
$Button--secondary-onActive-bg: darken($Button--secondary-bg, 10%) !default;
$Button--secondary-onActive-border: darken(
$Button--secondary-border,
12.5%
) !default;
$Button--secondary-onActive-border: darken($Button--secondary-border,
12.5%) !default;
$Button--secondary-onActive-color: $Button--secondary-color !default;
$Button--success-bg: $success !default;
@ -847,10 +811,8 @@ $Button--success-onHover-bg: darken($Button--success-bg, 7.5%) !default;
$Button--success-onHover-border: darken($Button--success-border, 10%) !default;
$Button--success-onHover-color: $Button--success-color !default;
$Button--success-onActive-bg: darken($Button--success-bg, 10%) !default;
$Button--success-onActive-border: darken(
$Button--success-border,
12.5%
) !default;
$Button--success-onActive-border: darken($Button--success-border,
12.5%) !default;
$Button--success-onActive-color: $Button--success-color !default;
$Button--info-bg: $info !default;
@ -870,10 +832,8 @@ $Button--warning-onHover-bg: darken($Button--warning-bg, 7.5%) !default;
$Button--warning-onHover-border: darken($Button--warning-border, 10%) !default;
$Button--warning-onHover-color: $Button--warning-color !default;
$Button--warning-onActive-bg: darken($Button--warning-bg, 10%) !default;
$Button--warning-onActive-border: darken(
$Button--warning-border,
12.5%
) !default;
$Button--warning-onActive-border: darken($Button--warning-border,
12.5%) !default;
$Button--warning-onActive-color: $Button--warning-color !default;
$Button--danger-bg: $danger !default;
@ -913,10 +873,8 @@ $Button--default-onHover-bg: darken($Button--default-bg, 7.5%) !default;
$Button--default-onHover-border: darken($Button--default-border, 10%) !default;
$Button--default-onHover-color: $Button--default-color !default;
$Button--default-onActive-bg: darken($Button--default-bg, 10%) !default;
$Button--default-onActive-border: darken(
$Button--default-border,
12.5%
) !default;
$Button--default-onActive-border: darken($Button--default-border,
12.5%) !default;
$Button--default-onActive-color: $Button--default-color !default;
$Button--link-color: $text-color !default;
@ -932,9 +890,7 @@ $DropDown-menu-height: px2rem(34px) !default;
$DropDown-menu-minWidth: px2rem(160px) !default;
$DropDown-menu-paddingY: $gap-xs !default;
$DropDown-menu-paddingX: 0 !default;
$DropDown-menuItem-paddingY: (
$DropDown-menu-height - $fontSizeBase * $lineHeightBase
) / 2 !default;
$DropDown-menuItem-paddingY: ($DropDown-menu-height - $fontSizeBase * $lineHeightBase) / 2 !default;
$DropDown-menuItem-paddingX: $gap-sm !default;
$DropDown-menuItem-onHover-color: inherit !default;
$DropDown-menuItem-onHover-bg: $Button--default-onHover-bg !default;
@ -989,9 +945,7 @@ $ColorPicker-height: $Form-input-height !default;
$ColorPicker-lineHeight: $Form-input-lineHeight !default;
$ColorPicker-fontSize: $Form-input-fontSize !default;
$ColorPicker-paddingX: px2rem(12px) !default;
$ColorPicker-paddingY: (
$ColorPicker-height - $ColorPicker-lineHeight * $ColorPicker-fontSize
)/2 - $ColorPicker-borderWidth !default;
$ColorPicker-paddingY: ($ColorPicker-height - $ColorPicker-lineHeight * $ColorPicker-fontSize)/2 - $ColorPicker-borderWidth !default;
$ColorPicker-placeholderColor: $Form-input-placeholderColor !default;
$ColorPicker-onFocused-borderColor: $Form-input-onFocused-borderColor !default;
$DatePicker-onHover-borderColor: $Form-input-borderColor !default;
@ -1007,9 +961,7 @@ $DatePicker-height: $Form-input-height !default;
$DatePicker-lineHeight: $Form-input-lineHeight !default;
$DatePicker-fontSize: $Form-input-fontSize !default;
$DatePicker-paddingX: px2rem(12px) !default;
$DatePicker-paddingY: (
$DatePicker-height - $DatePicker-lineHeight * $DatePicker-fontSize
)/2 - $DatePicker-borderWidth !default;
$DatePicker-paddingY: ($DatePicker-height - $DatePicker-lineHeight * $DatePicker-fontSize)/2 - $DatePicker-borderWidth !default;
$DatePicker-placeholderColor: $Form-input-placeholderColor !default;
$DatePicker-iconColor: $icon-color !default;
$DatePicker-onHover-iconColor: $icon-onHover-color !default;
@ -1035,18 +987,13 @@ $Calendar-input-borderRadius: $borderRadius !default;
$Calendar-input-height: px2rem(30px) !default;
$Calendar-input-lineHeight: $lineHeightBase;
$Calendar-input-paddingX: px2rem(10px) !default;
$Calendar-input-paddingY: (
$Calendar-input-height - $Calendar-input-lineHeight *
$Calendar-input-fontSize
) / 2;
$Calendar-input-paddingY: ($Calendar-input-height - $Calendar-input-lineHeight * $Calendar-input-fontSize) / 2;
$Calendar-btn-fontSize: $fontSizeSm !default;
$Calendar-btn-lineHeight: $lineHeightBase !default;
$Calendar-btn-height: px2rem(30px) !default;
$Calendar-btn-paddingX: px2rem(10px) !default;
$Calendar-btn-paddingY: (
$Calendar-btn-height - $Calendar-btn-lineHeight * $Calendar-btn-fontSize
)/2 !default;
$Calendar-btn-paddingY: ($Calendar-btn-height - $Calendar-btn-lineHeight * $Calendar-btn-fontSize)/2 !default;
$Calendar-btn-bg: $info !default;
$Calendar-btn-border: $Calendar-btn-bg !default;
@ -1064,16 +1011,12 @@ $Calendar-btnCancel-border: $Calendar-btnCancel-bg !default;
$Calendar-btnCancel-borderRadius: $Button-borderRadius !default;
$Calendar-btnCancel-color: $text-color !default;
$Calendar-btnCancel-onHover-bg: darken($Calendar-btnCancel-bg, 7.5%) !default;
$Calendar-btnCancel-onHover-border: darken(
$Calendar-btnCancel-border,
10%
) !default;
$Calendar-btnCancel-onHover-border: darken($Calendar-btnCancel-border,
10%) !default;
$Calendar-btnCancel-onHover-color: $Calendar-btnCancel-color !default;
$Calendar-btnCancel-onActive-bg: darken($Calendar-btnCancel-bg, 10%) !default;
$Calendar-btnCancel-onActive-border: darken(
$Calendar-btnCancel-border,
12.5%
) !default;
$Calendar-btnCancel-onActive-border: darken($Calendar-btnCancel-border,
12.5%) !default;
$Calendar-btnCancel-onActive-color: $Calendar-btnCancel-color !default;
$Calendar-color: $text-color !default;
@ -1081,8 +1024,18 @@ $Calendar-wLabel-color: #999 !default;
$Calendar-cell-bg: $white !default;
$Calendar-cell-onHover-bg: darken($Calendar-cell-bg, 7%) !default;
$Calendar-cell-onActive-bg: $info !default;
$Calendar-cell-onBetween-bg: rgba($info, 0.1) !default;
$Calendar-cell-onDisabled-bg: $light !default;
$Calendar-shortcuts-bg: transparent;
$Calendar-shortcuts-height: px2rem(30px);
$Calendar-shortcut-color: $info !default;
$Calendar-shortcut-decoration: none !default;
$Calendar-shortcut-onHover-color: darken($Calendar-shortcut-color,
15%) !default;
$Calendar-shortcut-onHover-decoration: none !default;
// List Control
$ListControl-fontSize: $Form-fontSize !default;
$ListControl-gutterWidth: px2rem(10px) !default;
@ -1096,18 +1049,14 @@ $ListControl-item-paddingX: px2rem(12px) !default;
$ListControl-item-paddingY: px2rem(6px) !default;
$ListControl-item-color: $text-color !default;
$ListControl-item-onHover-borderColor: darken(
$ListControl-item-borderColor,
10%
) !default;
$ListControl-item-onHover-borderColor: darken($ListControl-item-borderColor,
10%) !default;
$ListControl-item-onHover-bg: darken($ListControl-item-bg, 7.5%) !default;
$ListControl-item-onHover-color: $ListControl-item-color !default;
$ListControl-item-onActive-bg: $primary !default;
$ListControl-item-onActive-borderColor: darken(
$ListControl-item-onActive-bg,
10%
) !default;
$ListControl-item-onActive-borderColor: darken($ListControl-item-onActive-bg,
10%) !default;
$ListControl-item-onActive-color: $white !default;
$ListControl-item-onActive-before-bg: $white !default;
$ListControl-item-onActive-after-borderColor: $primary !default;
@ -1140,10 +1089,7 @@ $Combo-addBtn-borderRadius: $Button-borderRadius;
$Combo-addBtn-height: px2rem(26px) !default;
$Combo-addBtn-lineHeight: $Button--sm-lineHeight !default;
$Combo-addBtn-paddingX: $Button--sm-paddingX !default;
$Combo-addBtn-paddingY: (
$Combo-addBtn-height - $Button-borderWidth * 2 - $Combo-addBtn-lineHeight *
$Combo-addBtn-fontSize
)/2 !default;
$Combo-addBtn-paddingY: ($Combo-addBtn-height - $Button-borderWidth * 2 - $Combo-addBtn-lineHeight * $Combo-addBtn-fontSize)/2 !default;
$Combo--vertical-item-gap: px2rem(5px);
$Combo--vertical-item-borderColor: $borderColor !default;
@ -1158,10 +1104,8 @@ $Combo--vertical-itemToolbar-bg: $info !default;
$Combo--vertical-itemToolbar-color: darken($white, 5%) !default;
$Combo--vertical-itemToolbar-onHover-color: $white !default;
$Combo--vertical-itemToolbar-borderWidth: $borderWidth !default;
$Combo--vertical-itemToolbar-borderColor: darken(
$Combo--vertical-itemToolbar-bg,
5%
) !default;
$Combo--vertical-itemToolbar-borderColor: darken($Combo--vertical-itemToolbar-bg,
5%) !default;
$Combo--vertical-itemToolbar-borderRadius: px2rem(3px) !default;
$Combo--vertical-itemToolbar-transion: all 0.25s ease-in-out !default;
$Combo--vertical-itemToolbar-positionTop: -$Combo--vertical-itemToolbar-height !default;
@ -1177,10 +1121,8 @@ $SubForm--addBtn-onHover-bg: darken($SubForm--addBtn-bg, 7.5%) !default;
$SubForm--addBtn-onHover-border: darken($SubForm--addBtn-border, 10%) !default;
$SubForm--addBtn-onHover-color: $SubForm--addBtn-color !default;
$SubForm--addBtn-onActive-bg: darken($SubForm--addBtn-bg, 10%) !default;
$SubForm--addBtn-onActive-border: darken(
$SubForm--addBtn-border,
12.5%
) !default;
$SubForm--addBtn-onActive-border: darken($SubForm--addBtn-border,
12.5%) !default;
$SubForm--addBtn-onActive-color: $SubForm--addBtn-color !default;
$SubForm--addBtn-fontSize: $Button--sm-fontSize !default;
@ -1188,10 +1130,7 @@ $SubForm--addBtn-borderRadius: $Button-borderRadius;
$SubForm--addBtn-height: $Button--sm-height !default;
$SubForm--addBtn-lineHeight: $Button--sm-lineHeight !default;
$SubForm--addBtn-paddingX: $Button--sm-paddingX !default;
$SubForm--addBtn-paddingY: (
$SubForm--addBtn-height - $Button-borderWidth * 2 -
$SubForm--addBtn-lineHeight * $SubForm--addBtn-fontSize
)/2 !default;
$SubForm--addBtn-paddingY: ($SubForm--addBtn-height - $Button-borderWidth * 2 - $SubForm--addBtn-lineHeight * $SubForm--addBtn-fontSize)/2 !default;
// InputRange
$InputRange-fontFamily: $fontFamilyBase !default;
@ -1204,17 +1143,15 @@ $InputRange-onDisabled-color: #cccccc !default;
$InputRange-slider-bg: $InputRange-primaryColor !default;
$InputRange-slider-border: px2rem(1px) solid $InputRange-primaryColor !default;
$InputRange-slider-onFocus-borderRadius: $borderRadiusMd !default;
$InputRange-slider-onFocus-boxShadow: 0 0 0
$InputRange-slider-onFocus-borderRadius
transparentize($InputRange-slider-bg, 0.8) !default;
$InputRange-slider-onFocus-boxShadow: 0 0 0 $InputRange-slider-onFocus-borderRadius transparentize($InputRange-slider-bg, 0.8) !default;
$InputRange-slider-height: px2rem(24px) !default;
$InputRange-slider-width: px2rem(18px) !default;
$InputRange-slider-transition: transform 0.3s ease-out, box-shadow 0.3s ease-out !default;
$InputRange-slider-transition: transform 0.3s ease-out,
box-shadow 0.3s ease-out !default;
$InputRange-sliderContainer-transition: left 0.3s ease-out !default;
$InputRange-slider-onActive-transform: scale(1.3) !default;
$InputRange-slider-onDisabled-bg: $InputRange-onDisabled-color !default;
$InputRange-slider-onDisabled-border: px2rem(1px) solid
$InputRange-onDisabled-color !default;
$InputRange-slider-onDisabled-border: px2rem(1px) solid $InputRange-onDisabled-color !default;
// input-range-label
$InputRange-label-color: $InputRange-neutralColor !default;
@ -1226,7 +1163,8 @@ $InputRange-label--value-positionTop: px2rem(-40px) !default;
// input-range-track
$InputRange-track-bg: $InputRange-neutralLightColor !default;
$InputRange-track-height: px2rem(12px) !default;
$InputRange-track-transition: left 0.3s ease-out, width 0.3s ease-out !default;
$InputRange-track-transition: left 0.3s ease-out,
width 0.3s ease-out !default;
$InputRange-track-onActive-bg: $InputRange-primaryColor !default;
$InputRange-track-onDisabled-bg: $InputRange-neutralLightColor !default;
@ -1235,16 +1173,12 @@ $ImageControl-addBtn-bg: $Button--default-bg !default;
$ImageControl-addBtn-border: $Button--default-border !default;
$ImageControl-addBtn-color: $Button--default-color !default;
$ImageControl-addBtn-onHover-bg: darken($ImageControl-addBtn-bg, 7.5%) !default;
$ImageControl-addBtn-onHover-border: darken(
$ImageControl-addBtn-border,
10%
) !default;
$ImageControl-addBtn-onHover-border: darken($ImageControl-addBtn-border,
10%) !default;
$ImageControl-addBtn-onHover-color: $Button--default-color !default;
$ImageControl-addBtn-onActive-bg: darken($ImageControl-addBtn-bg, 10%) !default;
$ImageControl-addBtn-onActive-border: darken(
$ImageControl-addBtn-border,
12.5%
) !default;
$ImageControl-addBtn-onActive-border: darken($ImageControl-addBtn-border,
12.5%) !default;
$ImageControl-addBtn-onActive-color: $ImageControl-addBtn-color !default;
$ImageControl-addBtn-onDisabled-bg: $Form-input-onDisabled-bg !default;
$ImageControl-addBtn-onDisabled-border: $Form-input-onDisabled-borderColor !default;
@ -1257,16 +1191,12 @@ $TagControl-sugBtn-bg: $Button--default-bg !default;
$TagControl-sugBtn-border: $Button--default-border !default;
$TagControl-sugBtn-color: $Button--default-color !default;
$TagControl-sugBtn-onHover-bg: darken($TagControl-sugBtn-bg, 7.5%) !default;
$TagControl-sugBtn-onHover-border: darken(
$TagControl-sugBtn-border,
10%
) !default;
$TagControl-sugBtn-onHover-border: darken($TagControl-sugBtn-border,
10%) !default;
$TagControl-sugBtn-onHover-color: $Button--default-color !default;
$TagControl-sugBtn-onActive-bg: darken($TagControl-sugBtn-bg, 10%) !default;
$TagControl-sugBtn-onActive-border: darken(
$TagControl-sugBtn-border,
12.5%
) !default;
$TagControl-sugBtn-onActive-border: darken($TagControl-sugBtn-border,
12.5%) !default;
$TagControl-sugBtn-onActive-color: $TagControl-sugBtn-color !default;
$TagControl-sugBtn-borderWidth: $Button-borderWidth !default;
@ -1275,10 +1205,7 @@ $TagControl-sugBtn-borderRadius: $Button-borderRadius !default;
$TagControl-sugBtn-height: $Button--sm-height !default;
$TagControl-sugBtn-lineHeight: $Button--sm-lineHeight !default;
$TagControl-sugBtn-paddingX: $Button--sm-paddingX !default;
$TagControl-sugBtn-paddingY: (
$TagControl-sugBtn-height - $Button-borderWidth * 2 -
$TagControl-sugBtn-lineHeight * $TagControl-sugBtn-fontSize
)/2 !default;
$TagControl-sugBtn-paddingY: ($TagControl-sugBtn-height - $Button-borderWidth * 2 - $TagControl-sugBtn-lineHeight * $TagControl-sugBtn-fontSize)/2 !default;
// Wizard
$Wizard-steps-bg: $gray100 !default;
@ -1452,4 +1379,4 @@ $Picker-iconColor: $icon-color !default;
$Picker-onHover-iconColor: $icon-onHover-color !default;
$Picker-btn-vendor: 'FontAwesome' !default;
$Picker-btn-fontSize: $Form-fontSize !default;
$Picker-btn-icon: '\f2d2' !default;
$Picker-btn-icon: '\f2d2' !default;

View File

@ -33,7 +33,7 @@
&.is-disabled {
background: $gray200;
> &-input {
>&-input {
color: $text--muted-color;
}
}
@ -71,12 +71,13 @@
.#{$ns}DateRangePicker-wrap {
width: auto;
padding: $gap-md;
padding: $gap-sm;
}
.#{$ns}DateRangePicker-start,
.#{$ns}DateRangePicker-end {
display: inline-block;
vertical-align: top;
.rdtPicker {
padding: 0;
@ -109,10 +110,19 @@
margin-top: $gap-sm;
}
.#{$ns}DateRangeControl:not(.is-inline) > .#{$ns}DateRangePicker {
.#{$ns}DateRangeControl:not(.is-inline)>.#{$ns}DateRangePicker {
display: flex;
}
.#{$ns}DateRangePicker-popover {
margin: px2rem(2px) 0 0;
&.#{$ns}PopOver--leftTopLeftBottom,
&.#{$ns}PopOver--rightTopRightBottom {
margin: px2rem(-2px) 0 0;
}
}
@include media-breakpoint-up(sm) {
.#{$ns}DateRangePicker-wrap {
white-space: nowrap;
@ -120,6 +130,6 @@
.#{$ns}DateRangePicker-end {
margin-top: 0;
margin-left: 20px;
margin-left: $gap-sm;
}
}
}

View File

@ -33,7 +33,7 @@
&.is-disabled {
background: $gray200;
> &-input {
>&-input {
color: $text--muted-color;
}
}
@ -78,26 +78,44 @@
}
}
.#{$ns}DateControl:not(.is-inline) > .#{$ns}DatePicker {
.#{$ns}DateControl:not(.is-inline)>.#{$ns}DatePicker {
display: flex;
}
.#{$ns}DatePicker-shortcuts {
margin: $gap-sm $gap-md $gap-sm $gap-md;
padding: 0;
margin: 0;
background: $Calendar-shortcuts-bg;
padding: ($Calendar-shortcuts-height - $Calendar-fontSize * $lineHeightBase) / 2 $gap-sm;
list-style: none;
max-width: 206px;
& + .rdt .rdtPicker {
&+.rdt .rdtPicker {
padding-top: 0;
}
}
.#{$ns}DatePicker-shortcut {
display: inline-block;
margin-right: $gap-sm;
margin-right: $gap-md;
a {
font-size: $Calendar-fontSize;
cursor: pointer;
color: $Calendar-shortcut-color;
text-decoration: $Calendar-shortcut-decoration;
&:hover {
color: $Calendar-shortcut-onHover-color;
text-decoration: $Calendar-shortcut-onHover-decoration;
}
}
}
.#{$ns}DatePicker-popover {
margin: px2rem(2px) 0 0;
&.#{$ns}PopOver--leftTopLeftBottom,
&.#{$ns}PopOver--rightTopRightBottom {
margin: px2rem(-2px) 0 0;
}
}
@ -109,7 +127,7 @@
.rdtPicker {
margin-top: 0;
padding: $gap-md;
padding: $gap-sm;
background: transparent;
border: none;
@ -130,6 +148,10 @@
}
}
td.rdtBetween {
background: $Calendar-cell-onBetween-bg;
}
td.rdtToday:before {
border-bottom-color: $Calendar-cell-onActive-bg;
}
@ -143,6 +165,8 @@
background: $Calendar-cell-onActive-bg;
}
td.rdtDisabled,
td.rdtDisabled:hover {
background-color: $Calendar-cell-onDisabled-bg;
@ -151,8 +175,8 @@
thead tr:first-child th {
cursor: default;
text-align: left;
font-weight: normal;
border-bottom: none;
}
thead tr:first-child th:hover {
@ -237,8 +261,7 @@
font-size: $fontSizeSm;
}
@include button-variant(
$Calendar-btn-bg,
@include button-variant($Calendar-btn-bg,
$Calendar-btn-border,
$Calendar-btn-color,
$Calendar-btn-onHover-bg,
@ -246,18 +269,16 @@
$Calendar-btn-onHover-color,
$Calendar-btn-onActive-bg,
$Calendar-btn-onActive-border,
$Calendar-btn-onActive-color
);
$Calendar-btn-onActive-color);
border-radius: $Calendar-btn-borderRadius;
& + .rdtBtn {
&+.rdtBtn {
margin-left: $gap-xs;
}
&Cancel {
@include button-variant(
$Calendar-btnCancel-bg,
@include button-variant($Calendar-btnCancel-bg,
$Calendar-btnCancel-border,
$Calendar-btnCancel-color,
$Calendar-btnCancel-onHover-bg,
@ -265,8 +286,7 @@
$Calendar-btnCancel-onHover-color,
$Calendar-btnCancel-onActive-bg,
$Calendar-btnCancel-onActive-border,
$Calendar-btnCancel-onActive-color
);
$Calendar-btnCancel-onActive-color);
}
}
@ -290,26 +310,79 @@
content: $DatePicker-nextBtn-icon;
}
.rdtPrev,
.rdtNext {
cursor: pointer !important;
width: px2rem(20px);
padding: 0;
color: #999;
font-size: px2rem(20px);
text-decoration: none;
font-family: auto;
font-weight: normal;
&:hover {
text-decoration: none;
color: #000;
}
}
.rdtSwitch {
text-align: center;
color: #000;
cursor: pointer;
font-weight: normal;
&:hover {
color: $link-onHover-color;
text-decoration: none;
}
}
.rdtHeader {
display: table;
table-layout: fixed;
border-collapse: separate;
width: 100%;
// padding: 0 10px;
.rdtBtn {
>* {
display: table-cell;
width: px2rem(30px);
padding: 0;
vertical-align: middle;
text-align: center;
}
.rdtSelect {
display: table-cell;
width: 100%;
border-left: 1px solid $DatePicker-header-select-borderColor;
border-right: 1px solid $DatePicker-header-select-borderColor;
.#{$ns}Select {
display: flex;
}
.rdtSwitch+.rdtSwitch {
margin-left: $gap-xs;
}
}
td.rdtMonth,
td.rdtYear {
width: px2rem(50px);
height: px2rem(40px);
>span {
height: px2rem(24px);
display: block;
}
&:hover,
&.rdtActive {
background: transparent !important;
>span {
background: $info;
color: $white;
}
}
&.rdtDisabled {
background: transparent !important;
>span {
background: #edf1f2;
color: #999;
}
}
}

View File

@ -188,6 +188,8 @@ $DatePicker-nextBtn-fontSize: px2rem(14px);
$DatePicker-nextBtn-icon: '\e63b';
$Calendar-input-borderRadius: 0;
$Calendar-shortcuts-bg: #f5f5f5;
$Calendar-shortcuts-height: px2rem(30px);
// button
$Button-mimWidth: px2rem(68px);

View File

@ -8,602 +8,12 @@ import React from 'react';
import cx from 'classnames';
import moment from 'moment';
import 'moment/locale/zh-cn';
// hack 进去,让 days view 用 CustomDaysView 代替
import CalendarContainer from 'react-datetime/src/CalendarContainer';
import ReactDatePicker from 'react-datetime';
import Select from './Select';
import {Icon} from './icons';
import PopOver from './PopOver';
import Overlay from './Overlay';
import {classPrefix, classnames} from '../themes/default';
import {ClassNamesFn, themeable} from '../theme';
import {findDOMNode} from 'react-dom';
import find from 'lodash/find';
import {PlainObject} from '../types';
class HackedCalendarContainer extends CalendarContainer {
render() {
if (this.props.view === 'days') {
return <CustomDaysView {...this.props.viewProps} />;
}
return super.render();
}
}
// hack 后view 中可以调用 setDateTimeState
class BaseDatePicker extends ReactDatePicker {
__hacked: boolean;
render() {
if (!this.__hacked) {
this.__hacked = true;
const origin = (this as any).getComponentProps;
const setState = this.setState.bind(this);
(this as any).getComponentProps = function() {
const props = origin.apply(this);
props.setDateTimeState = setState;
[
'onChange',
'onClose',
'requiredConfirm',
'classPrefix',
'prevIcon',
'nextIcon',
'isEndDate'
].forEach(key => (props[key] = (this.props as any)[key]));
return props;
};
}
// TODO: Make a function or clean up this code,
// logic right now is really hard to follow
let className =
'rdt' +
(this.props.className
? Array.isArray(this.props.className)
? ' ' + this.props.className.join(' ')
: ' ' + this.props.className
: ''),
children: Array<any> = [];
if (this.props.input) {
var finalInputProps = {
type: 'text',
className: 'form-control',
onClick: this.openCalendar,
onFocus: this.openCalendar,
onChange: this.onInputChange,
onKeyDown: this.onInputKey,
value: this.state.inputValue,
...this.props.inputProps
};
if (this.props.renderInput) {
children = [
<div key="i">
{this.props.renderInput(
finalInputProps,
this.openCalendar,
this.closeCalendar
)}
</div>
];
} else {
children = [<input key="i" {...finalInputProps} />];
}
} else {
className += ' rdtStatic';
}
if (this.state.open) className += ' rdtOpen';
return (
<div className={className}>
{children.concat(
<div key="dt" className="rdtPicker">
<HackedCalendarContainer
view={this.state.currentView}
viewProps={this.getComponentProps()}
onClickOutside={this.handleClickOutside}
/>
</div>
)}
</div>
);
}
}
interface CustomDaysViewProps {
classPrefix?: string;
prevIcon?: string;
nextIcon?: string;
viewDate: moment.Moment;
selectedDate: moment.Moment;
timeFormat: string;
requiredConfirm?: boolean;
isEndDate?: boolean;
renderDay?: Function;
onClose?: () => void;
onChange: (value: moment.Moment) => void;
setDateTimeState: (state: any) => void;
setTime: (type: string, amount: number) => void;
subtractTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
addTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
isValidDate?: (
currentDate: moment.Moment,
selected?: moment.Moment
) => boolean;
showView: (view: string) => () => void;
updateSelectedDate: (event: React.MouseEvent<any>, close?: boolean) => void;
handleClickOutside: () => void;
}
class CustomDaysView extends React.Component<CustomDaysViewProps> {
static defaultProps = {
classPrefix: 'a-'
};
constructor(props: CustomDaysViewProps) {
super(props);
this.handleClickOutside = this.handleClickOutside.bind(this);
this.handleYearChange = this.handleYearChange.bind(this);
this.handleMonthChange = this.handleMonthChange.bind(this);
this.handleDayChange = this.handleDayChange.bind(this);
this.confirm = this.confirm.bind(this);
this.cancel = this.cancel.bind(this);
}
getDaysOfWeek(locale: moment.Locale) {
const days: Array<string> = locale.weekdaysMin();
const first = locale.firstDayOfWeek();
const dow: Array<string> = [];
let i = 0;
days.forEach(function(day) {
dow[(7 + i++ - first) % 7] = day;
});
return dow;
}
alwaysValidDate() {
return true;
}
handleDayChange(event: React.MouseEvent<any>) {
// need confirm
if (this.props.requiredConfirm) {
const viewDate = this.props.viewDate.clone();
const currentDate = this.props.selectedDate || viewDate;
const target = event.target as HTMLElement;
let modifier = 0;
if (~target.className.indexOf('rdtNew')) {
modifier = 1;
}
if (~target.className.indexOf('rdtOld')) {
modifier = -1;
}
viewDate
.month(viewDate.month() + modifier)
.date(parseInt(target.getAttribute('data-value') as string, 10))
.hours(currentDate.hours())
.minutes(currentDate.minutes())
.seconds(currentDate.seconds())
.milliseconds(currentDate.milliseconds());
this.props.setDateTimeState({
viewDate,
selectedDate: viewDate.clone()
});
return;
}
this.props.updateSelectedDate(event, true);
}
handleMonthChange(option: any) {
// const div = document.createElement('div');
// div.innerHTML = `<span class="rdtMonth" data-value="${option.value}"></span>`;
// const fakeEvent = {
// target: div.firstChild
// };
// this.props.updateSelectedDate(fakeEvent as any);
const viewDate = this.props.viewDate;
this.props.setDateTimeState({
viewDate: viewDate
.clone()
.month(option.value)
.startOf('month')
});
}
handleYearChange(option: any) {
// const div = document.createElement('div');
// div.innerHTML = `<span class="rdtYear" data-value="${option.value}"></span>`;
// const fakeEvent = {
// target: div.firstChild
// };
// this.props.updateSelectedDate(fakeEvent as any);
const viewDate = this.props.viewDate;
const newDate = viewDate.clone().year(option.value);
this.props.setDateTimeState({
viewDate: newDate[newDate.isBefore(viewDate) ? 'endOf' : 'startOf'](
'year'
)
});
}
setTime(
type: 'hours' | 'minutes' | 'seconds' | 'milliseconds',
value: number
) {
const date = (this.props.selectedDate || this.props.viewDate).clone();
date[type](value);
this.props.setDateTimeState({
viewDate: date.clone(),
selectedDate: date.clone()
});
if (!this.props.requiredConfirm) {
this.props.onChange(date);
}
}
confirm() {
const date = this.props.viewDate.clone();
this.props.setDateTimeState({
selectedDate: date
});
this.props.onChange(date);
this.props.onClose && this.props.onClose();
}
cancel() {
this.props.onClose && this.props.onClose();
}
handleClickOutside() {
this.props.handleClickOutside();
}
renderYearsSelect() {
const classPrefix = this.props.classPrefix;
const date = this.props.viewDate;
const years: Array<number> = [];
const isValid = this.props.isValidDate || this.alwaysValidDate;
const irrelevantMonth = 0;
const irrelevantDate = 1;
let year = date.year();
let count = 0;
years.push(year);
while (count < 20) {
year++;
let currentYear = date.clone().set({
year: year,
month: irrelevantMonth,
date: irrelevantDate
});
const noOfDaysInYear = parseInt(
currentYear.endOf('year').format('DDD'),
10
);
const daysInYear = Array.from(
{
length: noOfDaysInYear
},
(e, i) => i + 1
);
const validDay = daysInYear.find(d =>
isValid(currentYear.clone().dayOfYear(d))
);
if (!validDay) {
break;
}
years.push(year);
count++;
}
count = 0;
year = date.year();
while (count < 20) {
year--;
let currentYear = date.clone().set({
year: year,
month: irrelevantMonth,
date: irrelevantDate
});
const noOfDaysInYear = parseInt(
currentYear.endOf('year').format('DDD'),
10
);
const daysInYear = Array.from(
{
length: noOfDaysInYear
},
(e, i) => i + 1
);
const validDay = daysInYear.find(d =>
isValid(currentYear.clone().dayOfYear(d))
);
if (!validDay) {
break;
}
years.unshift(year);
count++;
}
return (
<Select
value={date.year()}
options={years.map(year => ({
label: `${year}`,
value: year
}))}
onChange={this.handleYearChange}
clearable={false}
searchable={false}
/>
);
}
renderMonthsSelect() {
const classPrefix = this.props.classPrefix;
const date = this.props.viewDate;
const year = this.props.viewDate.year();
const isValid = this.props.isValidDate || this.alwaysValidDate;
let i = 0;
const days = [];
while (i < 12) {
const currentMonth = date.clone().set({
year,
month: i,
date: 1
});
const noOfDaysInMonth = parseInt(
currentMonth.endOf('month').format('D'),
10
);
const daysInMonth = Array.from({length: noOfDaysInMonth}, function(e, i) {
return i + 1;
});
const validDay = daysInMonth.find(d =>
isValid(currentMonth.clone().set('date', d))
);
if (validDay) {
days.push(i);
}
i++;
}
return (
<Select
classPrefix={classPrefix}
value={date.month()}
options={days.map(day => ({
label: `${day + 1}`,
value: day
}))}
onChange={this.handleMonthChange}
clearable={false}
searchable={false}
/>
);
}
renderDay(props: any, currentDate: moment.Moment) {
return <td {...props}>{currentDate.date()}</td>;
}
renderTimes() {
const {timeFormat, selectedDate, viewDate, isEndDate} = this.props;
const date = selectedDate || (isEndDate ? viewDate.endOf('day') : viewDate);
const inputs: Array<React.ReactNode> = [];
timeFormat.split(':').forEach((format, i) => {
const type = /h/i.test(format)
? 'hours'
: /m/i.test(format)
? 'minutes'
: 'seconds';
const min = 0;
const max = type === 'hours' ? 23 : 59;
inputs.push(
<input
key={i + 'input'}
type="text"
value={date.format(format)}
min={min}
max={max}
onChange={e =>
this.setTime(
type,
Math.max(
min,
Math.min(
parseInt(e.currentTarget.value.replace(/\D/g, ''), 10) || 0,
max
)
)
)
}
/>
);
inputs.push(<span key={i + 'divider'}>:</span>);
});
inputs.length && inputs.pop();
return <div>{inputs}</div>;
}
renderFooter() {
if (!this.props.timeFormat && !this.props.requiredConfirm) {
return null;
}
return (
<tfoot key="tf">
<tr>
<td colSpan={7}>
{this.props.timeFormat ? this.renderTimes() : null}
{this.props.requiredConfirm ? (
<div key="button" className="rdtActions">
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>
</a>
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>
</a>
</div>
) : null}
</td>
</tr>
</tfoot>
);
}
renderDays() {
const date = this.props.viewDate;
const selected = this.props.selectedDate && this.props.selectedDate.clone();
const prevMonth = date.clone().subtract(1, 'months');
const currentYear = date.year();
const currentMonth = date.month();
const weeks = [];
let days = [];
const renderer = this.props.renderDay || this.renderDay;
const isValid = this.props.isValidDate || this.alwaysValidDate;
let classes, isDisabled, dayProps: any, currentDate;
// Go to the last week of the previous month
prevMonth.date(prevMonth.daysInMonth()).startOf('week');
var lastDay = prevMonth.clone().add(42, 'd');
while (prevMonth.isBefore(lastDay)) {
classes = 'rdtDay';
currentDate = prevMonth.clone();
if (
(prevMonth.year() === currentYear &&
prevMonth.month() < currentMonth) ||
prevMonth.year() < currentYear
)
classes += ' rdtOld';
else if (
(prevMonth.year() === currentYear &&
prevMonth.month() > currentMonth) ||
prevMonth.year() > currentYear
)
classes += ' rdtNew';
if (selected && prevMonth.isSame(selected, 'day'))
classes += ' rdtActive';
if (prevMonth.isSame(moment(), 'day')) classes += ' rdtToday';
isDisabled = !isValid(currentDate, selected);
if (isDisabled) classes += ' rdtDisabled';
dayProps = {
'key': prevMonth.format('M_D'),
'data-value': prevMonth.date(),
'className': classes
};
if (!isDisabled) dayProps.onClick = this.handleDayChange;
days.push(renderer(dayProps, currentDate, selected));
if (days.length === 7) {
weeks.push(<tr key={prevMonth.format('M_D')}>{days}</tr>);
days = [];
}
prevMonth.add(1, 'd');
}
return weeks;
}
render() {
const footer = this.renderFooter();
const date = this.props.viewDate;
const locale = date.localeData();
const tableChildren = [
<thead key="th">
<tr>
<th colSpan={7}>
<div className="rdtHeader">
<a
className="rdtBtn"
onClick={this.props.subtractTime(1, 'months')}
>
<i className="rdtBtnPrev" />
</a>
<div className="rdtSelect">{this.renderYearsSelect()}</div>
<div className="rdtSelect">{this.renderMonthsSelect()}</div>
<a className="rdtBtn" onClick={this.props.addTime(1, 'months')}>
<i className="rdtBtnNext" />
</a>
</div>
</th>
</tr>
<tr>
{this.getDaysOfWeek(locale).map((day, index) => (
<th key={day + index} className="dow">
{day}
</th>
))}
</tr>
</thead>,
<tbody key="tb">{this.renderDays()}</tbody>
];
footer && tableChildren.push(footer);
return (
<div className="rdtDays">
<table>{tableChildren}</table>
</div>
);
}
}
import Calendar from './calendar/Calendar';
const availableShortcuts: {[propName: string]: any} = {
today: {
@ -768,20 +178,24 @@ const advancedShortcuts = [
}
];
export type ShortCutDate = {
label: string;
date: moment.Moment;
};
export type ShortCutDateRange = {
label: string;
startDate?: moment.Moment;
endDate?: moment.Moment;
};
export type ShortCuts =
| {
label: string;
value: string;
}
| {
label: string;
date: moment.Moment;
}
| {
label: string;
startDate?: moment.Moment;
endDate?: moment.Moment;
};
| ShortCutDate
| ShortCutDateRange;
export interface DateProps {
viewMode: 'years' | 'months' | 'days' | 'time';
@ -1016,10 +430,10 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
if (typeof item === 'string') {
shortcut = this.getAvailableShortcuts(item);
shortcut.key = item;
} else if (item.date) {
} else if ((item as ShortCutDate).date) {
shortcut = {
...item,
date: () => item.date
date: () => (item as ShortCutDate).date
};
}
return (
@ -1043,7 +457,6 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
value,
placeholder,
disabled,
format,
inputFormat,
dateFormat,
timeFormat,
@ -1093,7 +506,6 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
{isOpened ? (
<Overlay
placement="left-bottom-left-top right-bottom-right-top"
target={this.getTarget}
container={popOverContainer || this.getParent}
rootClose={false}
@ -1108,12 +520,10 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
>
{this.renderShortCuts(shortcuts)}
<BaseDatePicker
<Calendar
value={date}
onChange={this.handleChange}
classPrefix={ns}
classnames={cx}
requiredConfirm={dateFormat && timeFormat}
requiredConfirm={!!(dateFormat && timeFormat)}
dateFormat={dateFormat}
timeFormat={timeFormat}
isValidDate={this.checkIsValidDate}
@ -1132,5 +542,3 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
}
export default themeable(DatePicker);
export {BaseDatePicker};

View File

@ -10,10 +10,12 @@ import {findDOMNode} from 'react-dom';
import cx from 'classnames';
import {Icon} from './icons';
import Overlay from './Overlay';
import {BaseDatePicker, ShortCuts} from './DatePicker';
import {ShortCuts, ShortCutDateRange} from './DatePicker';
import Calendar from './calendar/Calendar';
import PopOver from './PopOver';
import {ClassNamesFn, themeable} from '../theme';
import {PlainObject} from '../types';
import {noop} from '../utils/helper';
export interface DateRangePickerProps {
className?: string;
@ -34,6 +36,7 @@ export interface DateRangePickerProps {
onChange: (value: any) => void;
data?: any;
disabled?: boolean;
closeOnSelect?: boolean;
[propName: string]: any;
}
@ -78,20 +81,20 @@ const availableRanges: {[propName: string]: any} = {
'7daysago': {
label: '最近7天',
startDate: (now: moment.Moment) => {
return now.add(-7, 'days');
return now.add(-7, 'days').startOf('day');
},
endDate: (now: moment.Moment) => {
return now;
return now.add(-1, 'days').endOf('day');
}
},
'90daysago': {
label: '最近90天',
startDate: (now: moment.Moment) => {
return now.add(-90, 'days');
return now.add(-90, 'days').startOf('day');
},
endDate: (now: moment.Moment) => {
return now;
return now.add(-1, 'days').endOf('day');
}
},
@ -168,7 +171,8 @@ export class DateRangePicker extends React.Component<
delimiter: ',',
ranges: 'yesterday,7daysago,prevweek,thismonth,prevmonth,prevquarter',
iconClassName: 'fa fa-calendar',
resetValue: ''
resetValue: '',
closeOnSelect: false
};
innerDom: any;
@ -217,6 +221,7 @@ export class DateRangePicker extends React.Component<
}
dom: React.RefObject<HTMLDivElement>;
nextMonth = moment().add(1, 'months');
constructor(props: DateRangePickerProps) {
super(props);
@ -235,6 +240,7 @@ export class DateRangePicker extends React.Component<
this.handleClick = this.handleClick.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handlePopOverClick = this.handlePopOverClick.bind(this);
this.renderDay = this.renderDay.bind(this);
const {format, joinValues, delimiter, value} = this.props;
this.state = {
@ -338,28 +344,53 @@ export class DateRangePicker extends React.Component<
this.close();
}
handleStartChange(newValue: any) {
handleStartChange(newValue: moment.Moment) {
if (
this.state.startDate &&
!this.state.endDate &&
newValue.isAfter(this.state.startDate)
) {
return this.setState({
endDate: newValue.clone()
});
}
this.setState({
startDate: newValue.clone()
});
}
handleEndChange(newValue: any) {
handleEndChange(newValue: moment.Moment) {
newValue =
!this.state.endDate && !this.props.timeFormat
? newValue.endOf('day')
: newValue;
if (
this.state.endDate &&
!this.state.startDate &&
newValue.isBefore(this.state.endDate)
) {
return this.setState({
startDate: newValue.clone()
});
}
this.setState({
endDate: newValue.clone()
});
}
selectRannge(range: PlainObject) {
const {closeOnSelect} = this.props;
const now = moment();
this.setState({
startDate: range.startDate(now.clone()),
endDate: range.endDate(now.clone())
});
this.setState(
{
startDate: range.startDate(now.clone()),
endDate: range.endDate(now.clone())
},
closeOnSelect ? this.close : noop
);
}
renderRanges(ranges: string | Array<ShortCuts> | undefined) {
@ -383,11 +414,14 @@ export class DateRangePicker extends React.Component<
if (typeof item === 'string') {
range = availableRanges[item];
range.key = item;
} else if (item.startDate && item.endDate) {
} else if (
(item as ShortCutDateRange).startDate &&
(item as ShortCutDateRange).endDate
) {
range = {
...item,
startDate: () => item.startDate,
endDate: () => item.endDate
startDate: () => (item as ShortCutDateRange).startDate,
endDate: () => (item as ShortCutDateRange).endDate
};
}
return (
@ -454,6 +488,20 @@ export class DateRangePicker extends React.Component<
return true;
}
renderDay(props: any, currentDate: moment.Moment) {
let {startDate, endDate} = this.state;
if (
startDate &&
endDate &&
currentDate.isBetween(startDate, endDate, 'day', '[]')
) {
props.className += ' rdtBetween';
}
return <td {...props}>{currentDate.date()}</td>;
}
render() {
const {
className,
@ -529,7 +577,6 @@ export class DateRangePicker extends React.Component<
{isOpened ? (
<Overlay
placement="left-bottom-left-top right-bottom-right-top left-bottom-left-top"
target={() => this.dom.current}
onHide={this.close}
container={popOverContainer || (() => findDOMNode(this))}
@ -546,9 +593,7 @@ export class DateRangePicker extends React.Component<
<div className={`${ns}DateRangePicker-wrap`}>
{this.renderRanges(ranges)}
<BaseDatePicker
classPrefix={ns}
classnames={cx}
<Calendar
className={`${ns}DateRangePicker-start`}
value={startDate}
onChange={this.handleStartChange}
@ -559,22 +604,23 @@ export class DateRangePicker extends React.Component<
viewMode="days"
input={false}
onClose={this.close}
renderDay={this.renderDay}
/>
<BaseDatePicker
classPrefix={ns}
classnames={cx}
<Calendar
className={`${ns}DateRangePicker-end`}
value={endDate}
onChange={this.handleEndChange}
requiredConfirm={false}
dateFormat={format}
timeFormat={timeFormat}
isEndDate={true}
viewDate={this.nextMonth}
isEndDate
isValidDate={this.checkEndIsValidDate}
viewMode="days"
input={false}
onClose={this.close}
renderDay={this.renderDay}
/>
<div key="button" className={`${ns}DateRangePicker-actions`}>

View File

@ -0,0 +1,81 @@
/**
* @file react-datetime
*/
import ReactDatePicker from 'react-datetime';
import React from 'react';
import CustomCalendarContainer from './CalendarContainer';
import cx from 'classnames';
import moment from 'moment';
interface BaseDatePickerProps extends ReactDatePicker.DatetimepickerProps {
onViewModeChange?: (type: string) => void;
requiredConfirm?: boolean;
onClose?: () => void;
isEndDate?: boolean;
renderDay?: (
props: any,
currentDate: moment.Moment,
selectedDate: moment.Moment
) => JSX.Element;
}
class BaseDatePicker extends ReactDatePicker {
state: any;
props: BaseDatePickerProps;
setState: (state: any) => void;
getComponentProps = ((origin: Function) => {
return () => {
const props = origin.call(this);
props.setDateTimeState = this.setState.bind(this);
[
'onChange',
'onClose',
'requiredConfirm',
'classPrefix',
'prevIcon',
'nextIcon',
'isEndDate'
].forEach(key => (props[key] = (this.props as any)[key]));
return props;
};
})((this as any).getComponentProps);
setDate = (type: 'month' | 'year') => {
const nextViews = {
month: 'days',
year: 'days'
};
return (e: any) => {
this.setState({
viewDate: this.state.viewDate
.clone()
[type](
parseInt(e.target.closest('td').getAttribute('data-value'), 10)
)
.startOf(type),
currentView: nextViews[type]
});
this.props.onViewModeChange!(nextViews[type]);
};
};
render() {
const Component = CustomCalendarContainer as any;
return (
<div className={cx('rdt rdtStatic rdtOpen', this.props.className)}>
<div key="dt" className="rdtPicker">
<Component
view={this.state.currentView}
viewProps={this.getComponentProps()}
/>
</div>
</div>
);
}
}
const Calendar: any = BaseDatePicker;
export default Calendar as React.ComponentType<BaseDatePickerProps>;

View File

@ -0,0 +1,15 @@
// @ts-ignore
import CalendarContainer from 'react-datetime/src/CalendarContainer';
import CustomDaysView from './DaysView';
import CustomYearsView from './YearsView';
import CustomMonthsView from './MonthsView';
export default class CustomCalendarContainer extends CalendarContainer {
viewComponents: any = {
...(this as any).viewComponents,
days: CustomDaysView,
years: CustomYearsView,
months: CustomMonthsView
};
}

View File

@ -0,0 +1,248 @@
import moment from 'moment';
// @ts-ignore
import DaysView from 'react-datetime/src/DaysView';
import React from 'react';
interface CustomDaysViewProps {
classPrefix?: string;
prevIcon?: string;
nextIcon?: string;
viewDate: moment.Moment;
selectedDate: moment.Moment;
timeFormat: string;
requiredConfirm?: boolean;
isEndDate?: boolean;
renderDay?: Function;
onClose?: () => void;
onChange: (value: moment.Moment) => void;
setDateTimeState: (state: any) => void;
setTime: (type: string, amount: number) => void;
subtractTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
addTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
isValidDate?: (
currentDate: moment.Moment,
selected?: moment.Moment
) => boolean;
showView: (view: string) => () => void;
updateSelectedDate: (event: React.MouseEvent<any>, close?: boolean) => void;
handleClickOutside: () => void;
}
export default class CustomDaysView extends DaysView {
props: CustomDaysViewProps;
getDaysOfWeek: (locale: any) => any;
renderDays: () => JSX.Element;
updateSelectedDate = (event: React.MouseEvent<any>) => {
// need confirm
if (this.props.requiredConfirm) {
const viewDate = this.props.viewDate.clone();
const currentDate = this.props.selectedDate || viewDate;
const target = event.target as HTMLElement;
let modifier = 0;
if (~target.className.indexOf('rdtNew')) {
modifier = 1;
}
if (~target.className.indexOf('rdtOld')) {
modifier = -1;
}
viewDate
.month(viewDate.month() + modifier)
.date(parseInt(target.getAttribute('data-value') as string, 10))
.hours(currentDate.hours())
.minutes(currentDate.minutes())
.seconds(currentDate.seconds())
.milliseconds(currentDate.milliseconds());
this.props.setDateTimeState({
viewDate,
selectedDate: viewDate.clone()
});
return;
}
this.props.updateSelectedDate(event, true);
};
setTime = (
type: 'hours' | 'minutes' | 'seconds' | 'milliseconds',
value: number
) => {
const date = (this.props.selectedDate || this.props.viewDate).clone();
date[type](value);
this.props.setDateTimeState({
viewDate: date.clone(),
selectedDate: date.clone()
});
if (!this.props.requiredConfirm) {
this.props.onChange(date);
}
};
confirm = () => {
const date = this.props.viewDate.clone();
this.props.setDateTimeState({
selectedDate: date
});
this.props.onChange(date);
this.props.onClose && this.props.onClose();
};
cancel = () => {
this.props.onClose && this.props.onClose();
};
renderDay = (props: any, currentDate: moment.Moment) => {
return <td {...props}>{currentDate.date()}</td>;
};
renderTimes = () => {
const {timeFormat, selectedDate, viewDate, isEndDate} = this.props;
const date = selectedDate || (isEndDate ? viewDate.endOf('day') : viewDate);
const inputs: Array<React.ReactNode> = [];
timeFormat.split(':').forEach((format, i) => {
const type = /h/i.test(format)
? 'hours'
: /m/i.test(format)
? 'minutes'
: 'seconds';
const min = 0;
const max = type === 'hours' ? 23 : 59;
inputs.push(
<input
key={i + 'input'}
type="text"
value={date.format(format)}
min={min}
max={max}
onChange={e =>
this.setTime(
type,
Math.max(
min,
Math.min(
parseInt(e.currentTarget.value.replace(/\D/g, ''), 10) || 0,
max
)
)
)
}
/>
);
inputs.push(<span key={i + 'divider'}>:</span>);
});
inputs.length && inputs.pop();
return <div>{inputs}</div>;
};
renderFooter = () => {
if (!this.props.timeFormat && !this.props.requiredConfirm) {
return null;
}
return (
<tfoot key="tf">
<tr>
<td colSpan={7}>
{this.props.timeFormat ? this.renderTimes() : null}
{this.props.requiredConfirm ? (
<div key="button" className="rdtActions">
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>
</a>
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>
</a>
</div>
) : null}
</td>
</tr>
</tfoot>
);
};
render() {
const footer = this.renderFooter();
const date = this.props.viewDate;
const locale = date.localeData();
const tableChildren = [
<thead key="th">
<tr>
<th colSpan={7}>
<div className="rdtHeader">
<a
className="rdtPrev"
onClick={this.props.subtractTime(1, 'years')}
>
«
</a>
<a
className="rdtPrev"
onClick={this.props.subtractTime(1, 'months')}
>
</a>
<div className="rdtCenter">
<a className="rdtSwitch" onClick={this.props.showView('years')}>
{date.format('YYYY年')}
</a>
<a
className="rdtSwitch"
onClick={this.props.showView('months')}
>
{date.format('MM月')}
</a>
</div>
<a className="rdtNext" onClick={this.props.addTime(1, 'months')}>
</a>
<a className="rdtNext" onClick={this.props.addTime(1, 'years')}>
»
</a>
</div>
</th>
</tr>
<tr>
{this.getDaysOfWeek(locale).map((day: number, index: number) => (
<th key={day + index} className="dow">
{day}
</th>
))}
</tr>
</thead>,
<tbody key="tb">{this.renderDays()}</tbody>
];
footer && tableChildren.push(footer);
return (
<div className="rdtDays">
<table>{tableChildren}</table>
</div>
);
}
}

View File

@ -0,0 +1,61 @@
// @ts-ignore
import MonthsView from 'react-datetime/src/MonthsView';
import moment from 'moment';
import React from 'react';
export default class CustomMonthsView extends MonthsView {
props: {
viewDate: moment.Moment;
subtractTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
addTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
};
renderMonths: () => JSX.Element;
renderMonth = (props: any, month: number) => {
var localMoment = this.props.viewDate;
var monthStr = localMoment
.localeData()
.monthsShort(localMoment.month(month));
var strLength = 3;
// Because some months are up to 5 characters long, we want to
// use a fixed string length for consistency
var monthStrFixedLength = monthStr.substring(0, strLength);
return (
<td {...props}>
<span>{monthStrFixedLength}</span>
</td>
);
};
render() {
return (
<div className="rdtMonths">
<table>
<thead>
<tr>
<th
className="rdtPrev"
onClick={this.props.subtractTime(1, 'years')}
>
«
</th>
<th className="rdtSwitch">{this.props.viewDate.year()}</th>
<th className="rdtNext" onClick={this.props.addTime(1, 'years')}>
»
</th>
</tr>
</thead>
</table>
<table>
<tbody>{this.renderMonths()}</tbody>
</table>
</div>
);
}
}

View File

@ -0,0 +1,59 @@
// @ts-ignore
import YearsView from 'react-datetime/src/YearsView';
import moment from 'moment';
import React from 'react';
export default class CustomYearsView extends YearsView {
props: {
viewDate: moment.Moment;
subtractTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
addTime: (
amount: number,
type: string,
toSelected?: moment.Moment
) => () => void;
showView: (view: string) => () => void;
};
renderYears: (year: number) => JSX.Element;
renderYear = (props: any, year: number) => {
return (
<td {...props}>
<span>{year}</span>
</td>
);
};
render() {
let year = this.props.viewDate.year();
year = year - (year % 10);
return (
<div className="rdtYears">
<table>
<thead>
<tr>
<th
className="rdtPrev"
onClick={this.props.subtractTime(10, 'years')}
>
«
</th>
<th className="rdtSwitch">
{year}-{year + 9}
</th>
<th className="rdtNext" onClick={this.props.addTime(10, 'years')}>
»
</th>
</tr>
</thead>
</table>
<table>
<tbody>{this.renderYears(year)}</tbody>
</table>
</div>
);
}
}

View File

@ -13,7 +13,7 @@ export interface DateProps extends FormControlProps {
format?: string;
timeConstrainst?: object;
closeOnSelect?: boolean;
disabled?: boolean;
disabled: boolean;
iconClassName?: string;
}