From 742567b033a6c55ac00f486f716f6d697f8e3f92 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Fri, 9 Apr 2021 12:43:05 +0800 Subject: [PATCH] wip(calendar) --- demo/routes/routes.js | 8 + demo/store/menu-options.js | 6 + src/_styles/common/light.ts | 2 +- src/calendar/demos/enUS/basic.demo.md | 5 + src/calendar/demos/enUS/index.demo-entry.md | 9 + src/calendar/demos/zhCN/basic.demo.md | 5 + src/calendar/demos/zhCN/index.demo-entry.md | 9 + src/calendar/index.ts | 1 + src/calendar/src/Calendar.tsx | 186 ++++++++++++++++++ src/calendar/src/styles/index.cssr.ts | 131 ++++++++++++ src/calendar/styles/_common.ts | 3 + src/calendar/styles/dark.ts | 41 ++++ src/calendar/styles/index.ts | 3 + src/calendar/styles/light.ts | 47 +++++ src/components.ts | 1 + src/config-provider/src/internal-interface.ts | 2 + src/date-picker/src/utils.ts | 6 +- src/themes/dark.ts | 2 + src/themes/light.ts | 2 + 19 files changed, 466 insertions(+), 3 deletions(-) create mode 100644 src/calendar/demos/enUS/basic.demo.md create mode 100644 src/calendar/demos/enUS/index.demo-entry.md create mode 100644 src/calendar/demos/zhCN/basic.demo.md create mode 100644 src/calendar/demos/zhCN/index.demo-entry.md create mode 100644 src/calendar/index.ts create mode 100644 src/calendar/src/Calendar.tsx create mode 100644 src/calendar/src/styles/index.cssr.ts create mode 100644 src/calendar/styles/_common.ts create mode 100644 src/calendar/styles/dark.ts create mode 100644 src/calendar/styles/index.ts create mode 100644 src/calendar/styles/light.ts diff --git a/demo/routes/routes.js b/demo/routes/routes.js index 5407eff96..cdae0118c 100644 --- a/demo/routes/routes.js +++ b/demo/routes/routes.js @@ -397,6 +397,10 @@ export const enComponentRoutes = [ path: 'n-skeleton', component: () => import('../../src/skeleton/demos/enUS/index.demo-entry.md') }, + { + path: 'n-calendar', + component: () => import('../../src/calendar/demos/enUS/index.demo-entry.md') + }, // deprecated { path: 'n-nimbus-service-layout', @@ -726,6 +730,10 @@ export const zhComponentRoutes = [ path: 'n-skeleton', component: () => import('../../src/skeleton/demos/zhCN/index.demo-entry.md') }, + { + path: 'n-calendar', + component: () => import('../../src/calendar/demos/zhCN/index.demo-entry.md') + }, // deprecated { path: 'n-nimbus-service-layout', diff --git a/demo/store/menu-options.js b/demo/store/menu-options.js index 3b77a0908..12fd43926 100644 --- a/demo/store/menu-options.js +++ b/demo/store/menu-options.js @@ -320,6 +320,12 @@ export function createComponentMenuOptions ({ lang, theme, mode }) { en: 'Data Display Components', type: 'group', children: [ + { + en: 'Calendar', + zh: '日历', + enSuffix: true, + path: '/n-calendar' + }, { en: 'Code', zh: '代码', diff --git a/src/_styles/common/light.ts b/src/_styles/common/light.ts index eef1fcc7c..dbc2475e2 100644 --- a/src/_styles/common/light.ts +++ b/src/_styles/common/light.ts @@ -173,7 +173,7 @@ const derived = { actionColor: 'rgb(250, 250, 252)', tableHeaderColor: 'rgb(250, 250, 252)', - hoverColor: 'rgb(246, 246, 250)', + hoverColor: 'rgb(246, 246, 248)', tableColorHover: overlay(base.alphaTablePending), activeColor: overlay(base.alphaActive), diff --git a/src/calendar/demos/enUS/basic.demo.md b/src/calendar/demos/enUS/basic.demo.md new file mode 100644 index 000000000..a9558215e --- /dev/null +++ b/src/calendar/demos/enUS/basic.demo.md @@ -0,0 +1,5 @@ +# Basic + +```html + +``` diff --git a/src/calendar/demos/enUS/index.demo-entry.md b/src/calendar/demos/enUS/index.demo-entry.md new file mode 100644 index 000000000..cbd564e4e --- /dev/null +++ b/src/calendar/demos/enUS/index.demo-entry.md @@ -0,0 +1,9 @@ + + +# Calendar + +## Demos + +```demo +basic +``` diff --git a/src/calendar/demos/zhCN/basic.demo.md b/src/calendar/demos/zhCN/basic.demo.md new file mode 100644 index 000000000..a9558215e --- /dev/null +++ b/src/calendar/demos/zhCN/basic.demo.md @@ -0,0 +1,5 @@ +# Basic + +```html + +``` diff --git a/src/calendar/demos/zhCN/index.demo-entry.md b/src/calendar/demos/zhCN/index.demo-entry.md new file mode 100644 index 000000000..cbd564e4e --- /dev/null +++ b/src/calendar/demos/zhCN/index.demo-entry.md @@ -0,0 +1,9 @@ + + +# Calendar + +## Demos + +```demo +basic +``` diff --git a/src/calendar/index.ts b/src/calendar/index.ts new file mode 100644 index 000000000..a6a7d33f0 --- /dev/null +++ b/src/calendar/index.ts @@ -0,0 +1 @@ +export { default as NCalendar } from './src/Calendar' diff --git a/src/calendar/src/Calendar.tsx b/src/calendar/src/Calendar.tsx new file mode 100644 index 000000000..7395329ea --- /dev/null +++ b/src/calendar/src/Calendar.tsx @@ -0,0 +1,186 @@ +import { + computed, + defineComponent, + ExtractPropTypes, + h, + ref, + PropType, + CSSProperties +} from 'vue' +import { + getDate, + format, + getYear, + addMonths, + startOfDay, + startOfMonth +} from 'date-fns' +import { dateArray } from '../../date-picker/src/utils' +import style from './styles/index.cssr' +import { useLocale, useTheme } from '../../_mixins' +import type { ThemeProps } from '../../_mixins' +import { calendarLight } from '../styles' +import type { CalendarTheme } from '../styles' +import { ChevronLeftIcon, ChevronRightIcon } from '../../_internal/icons' +import { NBaseIcon } from '../../_internal' + +const calendarProps = { + ...(useTheme.props as ThemeProps), + isDateDisabled: Function as PropType<(date: number) => boolean | undefined> +} as const + +export type CalendarProps = Partial> + +export default defineComponent({ + name: 'Calendar', + props: calendarProps, + setup (props) { + const themeRef = useTheme( + 'Calendar', + 'Calendar', + style, + calendarLight, + props + ) + const { locale: localeRef, dateLocale: dateLocaleRef } = useLocale( + 'DatePicker' + ) + const now = Date.now() + // ts => timestamp + const monthTsRef = ref(startOfMonth(now).valueOf()) + const valueRef = ref(null) + function handlePrevClick (): void { + monthTsRef.value = addMonths(monthTsRef.value, -1).valueOf() + } + function handleNextClick (): void { + monthTsRef.value = addMonths(monthTsRef.value, 1).valueOf() + } + return { + locale: localeRef, + dateLocale: dateLocaleRef, + now, + value: ref(null), + monthTs: monthTsRef, + dateItems: computed(() => { + return dateArray( + monthTsRef.value, + valueRef.value, + now, + localeRef.value.firstDayOfWeek, + true + ) + }), + handlePrevClick, + handleNextClick, + cssVars: computed(() => { + const { + common: { cubicBezierEaseInOut }, + self: { + borderColor, + borderRadius, + titleFontSize, + textColor, + titleFontWeight, + titleTextColor, + dayTextColor, + fontSize, + lineHeight, + dateColorCurrent, + dateTextColorCurrent, + cellColorHover, + cellColorActive + } + } = themeRef.value + return { + '--bezier': cubicBezierEaseInOut, + '--border-color': borderColor, + '--border-radius': borderRadius, + '--text-color': textColor, + '--title-font-weight': titleFontWeight, + '--title-font-size': titleFontSize, + '--title-text-color': titleTextColor, + '--day-text-color': dayTextColor, + '--font-size': fontSize, + '--line-height': lineHeight, + '--date-color-current': dateColorCurrent, + '--date-text-color-current': dateTextColorCurrent, + '--cell-color-hover': cellColorHover, + '--cell-color-active': cellColorActive + } + }) + } + }, + render () { + const { + isDateDisabled, + monthTs, + cssVars, + value, + dateLocale: { locale }, + handlePrevClick, + handleNextClick + } = this + const normalizedValue = value && startOfDay(value).valueOf() + return ( +
+
+ + {{ default: () => }} + + + {{ default: () => }} + + {getYear(monthTs)} {format(monthTs, 'MMMM', { locale })} +
+
+ {this.dateItems.map( + ({ ts, inCurrentMonth, isCurrentDate }, index) => { + const disabled = !inCurrentMonth || isDateDisabled?.(ts) === true + return ( +
{ + this.value = ts + this.monthTs = startOfMonth(ts).valueOf() + }} + > +
+ {disabled ? ( +
+ {getDate(ts)} +
+ ) : ( +
+ {getDate(ts)} +
+ )} + {index < 7 && ( +
+ {format(ts, 'EEE', { + locale + })} +
+ )} +
+
+ ) + } + )} +
+
+ ) + } +}) diff --git a/src/calendar/src/styles/index.cssr.ts b/src/calendar/src/styles/index.cssr.ts new file mode 100644 index 000000000..c0e6f49b3 --- /dev/null +++ b/src/calendar/src/styles/index.cssr.ts @@ -0,0 +1,131 @@ +import { cB, cE, cM, c } from '../../../_utils/cssr' + +// vars: +// --bezier +// --border-color +// --border-radius +// --text-color +// --title-font-weight +// --title-font-size +// --title-text-color +// --day-text-color +// --font-size +// --line-height +// --date-color-current +// --cell-color-hover +// --cell-color-active +export default cB('calendar', ` + line-height: var(--line-height); + font-size: var(--font-size); + color: var(--text-color); + height: 720px; + display: flex; + flex-direction: column; +`, [ + cB('calendar-prev-btn', ` + margin-right: 6px; + cursor: pointer; + `), + cB('calendar-next-btn', ` + margin-right: 12px; + cursor: pointer; + `), + cB('calendar-header', ` + display: flex; + align-items: center; + line-height: 1; + font-size: var(--title-font-size); + color: var(--title-text-color); + font-weight: var(--title-font-weight); + padding: 8px 0 18px 0; + transition: color .3s var(--bezier); + `), + cB('calendar-dates', ` + border-radius: var(--border-radius); + flex: 1; + border-top: 1px solid; + border-left: 1px solid; + border-color: var(--border-color); + transition: border-color .3s var(--bezier); + `), + cB('calendar-cell', ` + box-sizing: border-box; + padding: 12px; + border-right: 1px solid; + border-bottom: 1px solid; + border-color: var(--border-color); + cursor: pointer; + background-clip: padding-box; + transition: + color .3s var(--bezier), + border-color .3s var(--bezier), + background-color .3s var(--bezier); + `, [ + c('&:nth-child(7)', ` + border-top-right-radius: var(--border-radius); + `), + c('&:nth-last-child(7)', ` + border-bottom-left-radius: var(--border-radius); + `), + c('&:last-child', ` + border-bottom-right-radius: var(--border-radius); + `), + c('&:hover', ` + background-color: var(--cell-color-hover); + `), + cM('selected', ` + background-color: var(--cell-color-active); + `), + cB('calendar-date', ` + transition: + color .3s var(--bezier), + border-color .3s var(--bezier), + background-color .3s var(--bezier); + color: var(--text-color); + `, [ + cE('date', ` + color: var(--text-color); + `) + ]), + cM('disabled', [ + cB('calendar-date', [ + cE('date', ` + color: var(--day-text-color); + `) + ]) + ]), + cM('current', [ + cB('calendar-date', [ + cE('date', ` + color: var(--date-text-color-current); + background-color: var(--date-color-current); + `) + ]) + ]), + cB('calendar-date', ` + position: relative; + line-height: 1; + display: flex; + align-items: center; + height: 1em; + justify-content: space-between; + `, [ + cE('date', ` + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-left: -0.5em; + width: 2em; + height: 2em; + transition: + color .3s var(--bezier), + background-color .3s var(--bezier); + `), + cE('day', ` + color: var(--day-text-color); + transition: color .3s var(--bezier); + `) + ]) + ]) +]) diff --git a/src/calendar/styles/_common.ts b/src/calendar/styles/_common.ts new file mode 100644 index 000000000..da09b6a57 --- /dev/null +++ b/src/calendar/styles/_common.ts @@ -0,0 +1,3 @@ +export default { + titleFontSize: '22px' +} diff --git a/src/calendar/styles/dark.ts b/src/calendar/styles/dark.ts new file mode 100644 index 000000000..df1544d56 --- /dev/null +++ b/src/calendar/styles/dark.ts @@ -0,0 +1,41 @@ +import { commonDark } from '../../_styles/common' +import commonVariables from './_common' +import type { CalendarTheme } from './light' +import { changeColor } from 'seemly' + +const calendarDark: CalendarTheme = { + name: 'Calendar', + common: commonDark, + self (vars) { + const { + borderRadius, + fontSize, + lineHeight, + textColor2, + textColor1, + textColorDisabled, + dividerColor, + fontWeightStrong, + primaryColor, + baseColor, + hoverColor + } = vars + return { + ...commonVariables, + borderRadius, + borderColor: dividerColor, + textColor: textColor2, + titleTextColor: textColor1, + titleFontWeight: fontWeightStrong, + dayTextColor: textColorDisabled, + fontSize, + lineHeight, + dateColorCurrent: primaryColor, + dateTextColorCurrent: baseColor, + cellColorHover: hoverColor, + cellColorActive: changeColor(primaryColor, { alpha: 0.12 }) + } + } +} + +export default calendarDark diff --git a/src/calendar/styles/index.ts b/src/calendar/styles/index.ts new file mode 100644 index 000000000..5b431d591 --- /dev/null +++ b/src/calendar/styles/index.ts @@ -0,0 +1,3 @@ +export { default as calendarDark } from './dark' +export { default as calendarLight } from './light' +export type { CalendarTheme, CalendarThemeVars } from './light' diff --git a/src/calendar/styles/light.ts b/src/calendar/styles/light.ts new file mode 100644 index 000000000..caf179366 --- /dev/null +++ b/src/calendar/styles/light.ts @@ -0,0 +1,47 @@ +import { commonLight } from '../../_styles/common' +import type { ThemeCommonVars } from '../../_styles/common' +import commonVariables from './_common' +import { Theme } from '../../_mixins' +import { changeColor } from 'seemly' + +const self = (vars: ThemeCommonVars) => { + const { + borderRadius, + fontSize, + lineHeight, + textColor2, + textColor1, + textColorDisabled, + dividerColor, + fontWeightStrong, + primaryColor, + baseColor, + hoverColor + } = vars + return { + ...commonVariables, + borderRadius, + borderColor: dividerColor, + textColor: textColor2, + titleFontWeight: fontWeightStrong, + titleTextColor: textColor1, + dayTextColor: textColorDisabled, + fontSize, + lineHeight, + dateColorCurrent: primaryColor, + dateTextColorCurrent: baseColor, + cellColorHover: hoverColor, + cellColorActive: changeColor(primaryColor, { alpha: 0.12 }) + } +} + +export type CalendarThemeVars = ReturnType + +const calendarLight: Theme<'Calendar', CalendarThemeVars> = { + name: 'Calendar', + common: commonLight, + self +} + +export default calendarLight +export type CalendarTheme = typeof calendarLight diff --git a/src/components.ts b/src/components.ts index 404840073..197cbfa66 100644 --- a/src/components.ts +++ b/src/components.ts @@ -7,6 +7,7 @@ export * from './back-top' export * from './badge' export * from './breadcrumb' export * from './button' +export * from './calendar' export * from './card' export * from './cascader' export * from './checkbox' diff --git a/src/config-provider/src/internal-interface.ts b/src/config-provider/src/internal-interface.ts index f27e61097..fd2bea3bd 100644 --- a/src/config-provider/src/internal-interface.ts +++ b/src/config-provider/src/internal-interface.ts @@ -7,6 +7,7 @@ import type { BackTopTheme } from '../../back-top/styles' import type { BadgeTheme } from '../../badge/styles' import type { BreadcrumbTheme } from '../../breadcrumb/styles' import type { ButtonTheme } from '../../button/styles' +import type { CalendarTheme } from '../../calendar/styles' import type { CardTheme } from '../../card/styles' import type { CascaderTheme } from '../../cascader/styles' import type { CheckboxTheme } from '../../checkbox/styles' @@ -89,6 +90,7 @@ export interface GlobalThemeWithoutCommon { Badge?: BadgeTheme Breadcrumb?: BreadcrumbTheme Button?: ButtonTheme + Calendar?: CalendarTheme Card?: CardTheme Cascader?: CascaderTheme Checkbox?: CheckboxTheme diff --git a/src/date-picker/src/utils.ts b/src/date-picker/src/utils.ts index 3e57fddc7..d7a70b640 100644 --- a/src/date-picker/src/utils.ts +++ b/src/date-picker/src/utils.ts @@ -99,7 +99,8 @@ function dateArray ( monthTs: number, valueTs: number | [number, number] | null, currentTs: number, - startDay: 0 | 1 | 2 | 3 | 4 | 5 | 6 + startDay: 0 | 1 | 2 | 3 | 4 | 5 | 6, + stripTail: boolean = false ): DateItem[] { const displayMonth = getMonth(monthTs) // First day of current month @@ -124,7 +125,8 @@ function dateArray ( ) displayMonthIterator = getTime(addDays(displayMonthIterator, 1)) } - while (calendarDays.length < 42) { + const endIndex = calendarDays.length <= 35 && stripTail ? 35 : 42 + while (calendarDays.length < endIndex) { calendarDays.push( dateItem(displayMonthIterator, monthTs, valueTs, currentTs) ) diff --git a/src/themes/dark.ts b/src/themes/dark.ts index fc3d0a5b9..fe80fcae9 100644 --- a/src/themes/dark.ts +++ b/src/themes/dark.ts @@ -7,6 +7,7 @@ import { backTopDark } from '../back-top/styles' import { badgeDark } from '../badge/styles' import { breadcrumbDark } from '../breadcrumb/styles' import { buttonDark } from '../button/styles' +import { calendarDark } from '../calendar/styles' import { cardDark } from '../card/styles' import { cascaderDark } from '../cascader/styles' import { checkboxDark } from '../checkbox/styles' @@ -80,6 +81,7 @@ export const darkTheme: BuiltInGlobalTheme = { Badge: badgeDark, Breadcrumb: breadcrumbDark, Button: buttonDark, + Calendar: calendarDark, Card: cardDark, Cascader: cascaderDark, Checkbox: checkboxDark, diff --git a/src/themes/light.ts b/src/themes/light.ts index 9aff8b9ae..2986d2566 100644 --- a/src/themes/light.ts +++ b/src/themes/light.ts @@ -9,6 +9,7 @@ import { backTopLight } from '../back-top/styles' import { badgeLight } from '../badge/styles' import { breadcrumbLight } from '../breadcrumb/styles' import { buttonLight } from '../button/styles' +import { calendarLight } from '../calendar/styles' import { cardLight } from '../card/styles' import { cascaderLight } from '../cascader/styles' import { checkboxLight } from '../checkbox/styles' @@ -82,6 +83,7 @@ export const lightTheme: BuiltInGlobalTheme = { Badge: badgeLight, Breadcrumb: breadcrumbLight, Button: buttonLight, + Calendar: calendarLight, Card: cardLight, Cascader: cascaderLight, Checkbox: checkboxLight,