From 3ca0ba5e9d3d3d9486199afe5ade924dce0c82ef Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Mon, 5 Jun 2023 16:46:26 +0100 Subject: [PATCH 01/25] feat: add calendar --- packages/calendar/.npmignore | 2 + packages/calendar/README.md | 28 + packages/calendar/exports.json | 4 + packages/calendar/package.json | 74 ++ packages/calendar/sp-calendar.ts | 20 + packages/calendar/src/Calendar.ts | 886 ++++++++++++++++++ packages/calendar/src/calendar.css | 13 + packages/calendar/src/index.ts | 12 + packages/calendar/src/spectrum-calendar.css | 750 +++++++++++++++ packages/calendar/src/spectrum-config.js | 35 + packages/calendar/stories/calendar.stories.ts | 31 + .../calendar/test/benchmark/basic-test.ts | 18 + packages/calendar/test/calendar.test.ts | 38 + packages/calendar/tsconfig.json | 10 + tools/bundle/elements.ts | 1 + tools/bundle/package.json | 1 + tools/bundle/src/index.ts | 1 + tsconfig-all.json | 1 + yarn.lock | 90 ++ 19 files changed, 2015 insertions(+) create mode 100644 packages/calendar/.npmignore create mode 100644 packages/calendar/README.md create mode 100644 packages/calendar/exports.json create mode 100644 packages/calendar/package.json create mode 100644 packages/calendar/sp-calendar.ts create mode 100644 packages/calendar/src/Calendar.ts create mode 100644 packages/calendar/src/calendar.css create mode 100644 packages/calendar/src/index.ts create mode 100644 packages/calendar/src/spectrum-calendar.css create mode 100644 packages/calendar/src/spectrum-config.js create mode 100644 packages/calendar/stories/calendar.stories.ts create mode 100644 packages/calendar/test/benchmark/basic-test.ts create mode 100644 packages/calendar/test/calendar.test.ts create mode 100644 packages/calendar/tsconfig.json diff --git a/packages/calendar/.npmignore b/packages/calendar/.npmignore new file mode 100644 index 00000000000..c50cbe188c0 --- /dev/null +++ b/packages/calendar/.npmignore @@ -0,0 +1,2 @@ +stories +test \ No newline at end of file diff --git a/packages/calendar/README.md b/packages/calendar/README.md new file mode 100644 index 00000000000..c2d406a9d4d --- /dev/null +++ b/packages/calendar/README.md @@ -0,0 +1,28 @@ +## Description + +### Usage + +[![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/calendar?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/calendar) +[![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/calendar?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/calendar) + +``` +yarn add @spectrum-web-components/calendar +``` + +Import the side effectful registration of `` via: + +``` +import '@spectrum-web-components/calendar/sp-calendar.js'; +``` + +When looking to leverage the `Calendar` base class as a type and/or for extension purposes, do so via: + +``` +import { Calendar } from '@spectrum-web-components/calendar'; +``` + +## Example + +```html + +``` diff --git a/packages/calendar/exports.json b/packages/calendar/exports.json new file mode 100644 index 00000000000..5aa8b7b31c6 --- /dev/null +++ b/packages/calendar/exports.json @@ -0,0 +1,4 @@ +{ + "./src/*": "./src/*.js", + "./sp-calendar.js": "./sp-calendar.js" +} diff --git a/packages/calendar/package.json b/packages/calendar/package.json new file mode 100644 index 00000000000..ad8edec960f --- /dev/null +++ b/packages/calendar/package.json @@ -0,0 +1,74 @@ +{ + "name": "@spectrum-web-components/calendar", + "version": "0.0.1", + "publishConfig": { + "access": "public" + }, + "description": "Web component implementation of a Spectrum design Calendar", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/adobe/spectrum-web-components.git", + "directory": "packages/calendar" + }, + "author": "", + "homepage": "https://adobe.github.io/spectrum-web-components/components/calendar", + "bugs": { + "url": "https://github.com/adobe/spectrum-web-components/issues" + }, + "main": "src/index.js", + "module": "src/index.js", + "type": "module", + "exports": { + ".": { + "development": "./src/index.dev.js", + "default": "./src/index.js" + }, + "./package.json": "./package.json", + "./src/Calendar.js": { + "development": "./src/Calendar.dev.js", + "default": "./src/Calendar.js" + }, + "./src/calendar.css.js": "./src/calendar.css.js", + "./src/index.js": { + "development": "./src/index.dev.js", + "default": "./src/index.js" + }, + "./sp-calendar.js": { + "development": "./sp-calendar.dev.js", + "default": "./sp-calendar.js" + } + }, + "scripts": { + "test": "echo \"Error: run tests from mono-repo root.\" && exit 1" + }, + "files": [ + "**/*.d.ts", + "**/*.js", + "**/*.js.map", + "custom-elements.json", + "!stories/", + "!test/" + ], + "keywords": [ + "spectrum css", + "web components", + "lit-element", + "lit-html" + ], + "dependencies": { + "@spectrum-web-components/action-button": "^0.32.0", + "@spectrum-web-components/base": "^0.32.0", + "@spectrum-web-components/icons-workflow": "^0.32.0" + }, + "devDependencies": { + "@spectrum-css/calendar": "^3.1.23" + }, + "types": "./src/index.d.ts", + "customElements": "custom-elements.json", + "sideEffects": [ + "./sp-*.js", + "./**/*.dev.js", + "./**/*.dev.js" + ] +} diff --git a/packages/calendar/sp-calendar.ts b/packages/calendar/sp-calendar.ts new file mode 100644 index 00000000000..79df5db0aa4 --- /dev/null +++ b/packages/calendar/sp-calendar.ts @@ -0,0 +1,20 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { Calendar } from './src/Calendar.js'; + +customElements.define('sp-calendar', Calendar); + +declare global { + interface HTMLElementTagNameMap { + 'sp-calendar': Calendar; + } +} diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts new file mode 100644 index 00000000000..d39191c2e35 --- /dev/null +++ b/packages/calendar/src/Calendar.ts @@ -0,0 +1,886 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { + CSSResultArray, + html, + SpectrumElement, + TemplateResult, +} from '@spectrum-web-components/base'; + +import styles from './calendar.css.js'; +import { property } from 'lit/decorators.js'; + +import '@spectrum-web-components/action-button/sp-action-button.js'; +import '@spectrum-web-components/icons-workflow/icons/sp-icon-chevron-left.js'; +import '@spectrum-web-components/icons-workflow/icons/sp-icon-chevron-right.js'; + +/** + * @element sp-calendar + */ +export class Calendar extends SpectrumElement { + public static override get styles(): CSSResultArray { + return [styles]; + } + + @property({ type: Boolean, reflect: true }) + padded = false; + + protected override render(): TemplateResult { + return html` +
+
August 2017
+ + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ `; + } +} diff --git a/packages/calendar/src/calendar.css b/packages/calendar/src/calendar.css new file mode 100644 index 00000000000..8bfbb5a10a5 --- /dev/null +++ b/packages/calendar/src/calendar.css @@ -0,0 +1,13 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +@import './spectrum-calendar.css'; diff --git a/packages/calendar/src/index.ts b/packages/calendar/src/index.ts new file mode 100644 index 00000000000..c1532216a3a --- /dev/null +++ b/packages/calendar/src/index.ts @@ -0,0 +1,12 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +export * from './Calendar.js'; diff --git a/packages/calendar/src/spectrum-calendar.css b/packages/calendar/src/spectrum-calendar.css new file mode 100644 index 00000000000..eb03f0451f4 --- /dev/null +++ b/packages/calendar/src/spectrum-calendar.css @@ -0,0 +1,750 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +/* THIS FILE IS MACHINE GENERATED. DO NOT EDIT */ +:host { + --spectrum-calendar-border-radius-reset: 0; + --spectrum-calendar-border-width-reset: 0; + --spectrum-calendar-margin-y: 24px; + --spectrum-calendar-margin-x: 32px; + --spectrum-calendar-width: calc( + ( + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) + + var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ) * 2 + ) * 7 + ); + --spectrum-calendar-button-gap: var(--spectrum-global-dimension-size-40); + --spectrum-calendar-title-text-letter-spacing: var( + --spectrum-detail-m-text-letter-spacing, + var(--spectrum-global-font-letter-spacing-medium) + ); +} +:host { + display: inline-block; + width: var(--spectrum-calendar-width, 250px); +} +:host([padded]) { + margin: var(--spectrum-calendar-margin-x) var(--spectrum-calendar-margin-y); +} +.spectrum-Calendar-header { + align-items: center; + display: flex; + width: 100%; +} +.spectrum-Calendar-title { + flex-grow: 1; + font-size: var( + --spectrum-calendar-title-text-size, + var(--spectrum-global-dimension-font-size-300) + ); + font-weight: 700; + line-height: var( + --spectrum-calendar-title-height, + var(--spectrum-global-dimension-static-size-400) + ); + margin: 0; + order: 1; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; +} +:host([dir='ltr']) .spectrum-Calendar-nextMonth, +:host([dir='ltr']) .spectrum-Calendar-prevMonth, +:host([dir='rtl']) .spectrum-Calendar-nextMonth, +:host([dir='rtl']) .spectrum-Calendar-prevMonth { + margin: 0 var(--spectrum-calendar-button-gap); +} +:host([dir='rtl']) .spectrum-Calendar-nextMonth, +:host([dir='rtl']) .spectrum-Calendar-prevMonth { + transform: matrix(-1, 0, 0, 1, 0, 0); +} +.spectrum-Calendar-prevMonth { + order: 0; +} +.spectrum-Calendar-nextMonth { + order: 2; +} +.spectrum-Calendar-dayOfWeek { + border-bottom: none !important; + cursor: default; + display: flex; + flex-direction: column; + font-size: var( + --spectrum-calendar-day-title-text-size, + var(--spectrum-global-dimension-font-size-50) + ); + font-weight: var( + --spectrum-calendar-day-title-text-font-weight, + var(--spectrum-alias-detail-text-font-weight-regular) + ); + height: 100%; + justify-content: flex-end; + -webkit-text-decoration: none !important; + text-decoration: none !important; + text-transform: uppercase; + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([title]) .spectrum-Calendar-dayOfWeek { + border-bottom: none; + letter-spacing: var(--spectrum-calendar-title-text-letter-spacing); + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} +.spectrum-Calendar-body { + outline: none; +} +.spectrum-Calendar-table { + border-collapse: collapse; + border-spacing: 0; + table-layout: fixed; + -webkit-user-select: none; + user-select: none; +} +.spectrum-Calendar-tableCell { + box-sizing: content-box; + height: var( + --spectrum-calendar-day-height, + var(--spectrum-global-dimension-size-400) + ); + padding: 0; + padding: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); + position: relative; + text-align: center; + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +.spectrum-Calendar-tableCell:focus { + outline: 0; +} +:host([dir='ltr']) .spectrum-Calendar-date { + left: 0; +} +:host([dir='rtl']) .spectrum-Calendar-date { + right: 0; +} +.spectrum-Calendar-date { + border: var( + --spectrum-calendar-day-border-size, + var(--spectrum-alias-border-size-thick) + ) + solid transparent; + border-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); + box-sizing: border-box; + cursor: pointer; + display: block; + font-size: var( + --spectrum-calendar-day-text-size, + var(--spectrum-alias-font-size-default) + ); + height: var( + --spectrum-calendar-day-height, + var(--spectrum-global-dimension-size-400) + ); + line-height: calc( + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) - + var( + --spectrum-calendar-day-border-size, + var(--spectrum-alias-border-size-thick) + ) * 2 + ); + margin: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); + position: absolute; + top: 0; + white-space: nowrap; + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +.spectrum-Calendar-date:lang(ja), +.spectrum-Calendar-date:lang(ko), +.spectrum-Calendar-date:lang(zh) { + font-size: var( + --spectrum-calendar-day-text-size-han, + var(--spectrum-global-dimension-font-size-50) + ); +} +.spectrum-Calendar-date.is-disabled { + cursor: default; + pointer-events: none; +} +.spectrum-Calendar-date.is-outsideMonth { + visibility: hidden; +} +:host([dir='ltr']) .spectrum-Calendar-date:before { + left: calc( + 50% - + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) / 2 + ); +} +:host([dir='rtl']) .spectrum-Calendar-date:before { + right: calc( + 50% - + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) / 2 + ); +} +.spectrum-Calendar-date:before { + border: var( + --spectrum-calendar-day-border-size, + var(--spectrum-alias-border-size-thick) + ) + solid transparent; + border-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); + box-sizing: border-box; + content: ''; + height: var( + --spectrum-calendar-day-height, + var(--spectrum-global-dimension-size-400) + ); + position: absolute; + top: calc( + 50% - + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) / 2 + ); + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +.spectrum-Calendar-date.is-selected:not(.is-range-selection) { + font-weight: var( + --spectrum-calendar-day-text-font-weight-selected, + var(--spectrum-global-font-weight-bold) + ); +} +.spectrum-Calendar-date.is-selected:not(.is-range-selection):before { + display: none; +} +.spectrum-Calendar-date.is-today { + font-weight: var( + --spectrum-calendar-day-today-text-font-weight, + var(--spectrum-global-font-weight-bold) + ); +} +.spectrum-Calendar-date.is-range-selection { + border-radius: var(--spectrum-calendar-border-radius-reset); + border-width: var(--spectrum-calendar-border-width-reset); + line-height: var( + --spectrum-calendar-day-height, + var(--spectrum-global-dimension-size-400) + ); + margin: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ) + 0; + width: calc( + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) + + var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ) * 2 + ); +} +.spectrum-Calendar-date.is-range-selection.is-range-end, +.spectrum-Calendar-date.is-range-selection.is-range-start, +.spectrum-Calendar-date.is-range-selection.is-selection-end, +.spectrum-Calendar-date.is-range-selection.is-selection-start { + width: calc( + var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ) + + var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ) + ); +} +.spectrum-Calendar-date.is-range-selection.is-selection-end, +.spectrum-Calendar-date.is-range-selection.is-selection-start { + font-weight: var( + --spectrum-calendar-day-text-font-weight-cap-selected, + var(--spectrum-global-font-weight-bold) + ); +} +.spectrum-Calendar-date.is-range-selection.is-selection-end:after, +.spectrum-Calendar-date.is-range-selection.is-selection-start:after { + border-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); + content: ''; + display: block; + height: var( + --spectrum-calendar-day-height, + var(--spectrum-global-dimension-size-400) + ); + position: absolute; + top: 0; + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + padding-right: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + padding-left: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + margin-left: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + margin-right: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + border-top-left-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + border-top-right-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + border-bottom-left-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-start, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start { + border-bottom-right-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-start:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-start:before, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-start:before { + left: 0; +} +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-start:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-start:before, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-start:before { + right: 0; +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + padding-left: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + padding-right: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + margin-right: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + margin-left: var( + --spectrum-calendar-day-padding, + var(--spectrum-global-dimension-static-size-50) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + border-top-right-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + border-top-left-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='ltr']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + border-bottom-right-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-range-end, +:host([dir='rtl']) .spectrum-Calendar-date.is-range-selection.is-selection-end { + border-bottom-left-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-end:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-end:before, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:before { + left: auto; +} +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-end:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-end:before, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:before { + right: auto; +} +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-end:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-range-end:before, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:after, +:host([dir='ltr']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:before { + right: 0; +} +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-end:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-range-end:before, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:after, +:host([dir='rtl']) + .spectrum-Calendar-date.is-range-selection.is-selection-end:before { + left: 0; +} +.spectrum-Calendar-date.is-range-selection.is-range-start.is-range-end, +.spectrum-Calendar-date.is-range-selection.is-selection-end.is-range-start, +.spectrum-Calendar-date.is-range-selection.is-selection-start.is-range-end, +.spectrum-Calendar-date.is-range-selection.is-selection-start.is-selection-end { + border-radius: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); + width: var( + --spectrum-calendar-day-width, + var(--spectrum-global-dimension-size-400) + ); +} +.spectrum-Calendar-nextMonth, +.spectrum-Calendar-prevMonth { + color: var( + --spectrum-calendar-button-icon-color, + var(--spectrum-global-color-gray-700) + ); +} +.spectrum-Calendar-dayOfWeek { + color: var( + --spectrum-calendar-day-title-text-color, + var(--spectrum-global-color-gray-700) + ); +} +.spectrum-Calendar-date:hover { + color: var( + --spectrum-calendar-day-text-color-hover, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date:hover:not(.is-selection-end):not(.is-selection-start):before { + background: var( + --spectrum-calendar-day-background-color-hover, + var(--spectrum-alias-highlight-hover) + ); +} +.spectrum-Calendar-date:hover.is-selected { + color: var( + --spectrum-calendar-day-text-color-selected-hover, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date:hover.is-selected:not(.is-selection-end):not(.is-selection-start):before { + background: var( + --spectrum-calendar-day-background-color-selected-hover, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date:hover.is-range-selection:before { + background: var( + --spectrum-calendar-day-background-color-selected-hover, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date:active { + background-color: var( + --spectrum-calendar-day-background-color-down, + var(--spectrum-alias-highlight-down) + ); +} +.spectrum-Calendar-date.is-selected { + background: var( + --spectrum-calendar-day-background-color-selected, + var(--spectrum-alias-highlight-selected) + ); + color: var( + --spectrum-calendar-day-text-color-selected, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date.is-selected:not(.is-range-selection) { + background: var( + --spectrum-calendar-day-background-color-cap-selected, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date.is-today { + border-color: var( + --spectrum-calendar-day-today-border-color, + var(--spectrum-global-color-gray-800) + ); + color: var( + --spectrum-calendar-day-today-text-color, + var(--spectrum-alias-text-color) + ); +} +.spectrum-Calendar-date.is-today:before { + border-color: var( + --spectrum-calendar-day-today-border-color, + var(--spectrum-global-color-gray-800) + ); +} +.spectrum-Calendar-date.is-today:hover.is-selected:not(.is-range-selection):before { + background: var( + --spectrum-calendar-day-today-background-color-selected-hover, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date.is-today.is-disabled { + border-color: var( + --spectrum-calendar-day-today-border-color-disabled, + var(--spectrum-global-color-gray-400) + ); + color: var( + --spectrum-calendar-day-today-text-color-disabled, + var(--spectrum-alias-text-color-disabled) + ); +} +.spectrum-Calendar-date.is-today.is-disabled:before { + border-color: var( + --spectrum-calendar-day-today-border-color-disabled, + var(--spectrum-global-color-gray-400) + ); +} +.spectrum-Calendar-date.is-focused:not(.is-range-selection) { + background: var( + --spectrum-calendar-day-background-color-key-focus, + var(--spectrum-alias-highlight-hover) + ); + border-color: var( + --spectrum-calendar-day-border-color-key-focus, + var(--spectrum-alias-focus-color) + ); + color: var( + --spectrum-calendar-day-text-color-key-focus, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date.is-focused:not(.is-range-selection).is-today { + border-color: var( + --spectrum-calendar-day-border-color-key-focus, + var(--spectrum-alias-focus-color) + ); +} +.spectrum-Calendar-date.is-focused:not(.is-range-selection).is-selected, +.spectrum-Calendar-date.is-focused:not(.is-range-selection):active { + background: var( + --spectrum-calendar-day-background-color-cap-selected, + var(--spectrum-alias-highlight-selected-hover) + ); + border-color: var( + --spectrum-calendar-day-border-color-key-focus, + var(--spectrum-alias-focus-color) + ); + color: var( + --spectrum-calendar-day-text-color-selected, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date.is-focused.is-selected:before { + background: var( + --spectrum-calendar-day-background-color-selected-hover, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date.is-focused.is-range-selection:before { + background: var( + --spectrum-calendar-day-background-color-selected-hover, + var(--spectrum-alias-highlight-selected-hover) + ); +} +.spectrum-Calendar-date.is-focused:before { + border-color: var( + --spectrum-calendar-day-border-color-key-focus, + var(--spectrum-alias-focus-color) + ); +} +.spectrum-Calendar-date.is-disabled { + color: var( + --spectrum-calendar-day-text-color-disabled, + var(--spectrum-alias-text-color-disabled) + ); +} +.spectrum-Calendar-date.is-selection-end, +.spectrum-Calendar-date.is-selection-start { + color: var( + --spectrum-calendar-day-text-color-cap-selected, + var(--spectrum-alias-text-color-hover) + ); +} +.spectrum-Calendar-date.is-selection-end:after, +.spectrum-Calendar-date.is-selection-start:after { + background-color: var( + --spectrum-calendar-day-background-color-selected, + var(--spectrum-alias-highlight-selected) + ); +} +.spectrum-Calendar-date.is-selection-end.is-disabled, +.spectrum-Calendar-date.is-selection-start.is-disabled { + color: var( + --spectrum-calendar-day-text-color-disabled, + var(--spectrum-alias-text-color-disabled) + ); +} +@media (forced-colors: active) { + .spectrum-Calendar-date { + --spectrum-calendar-button-icon-color: ButtonText; + --spectrum-calendar-day-background-color-cap-selected: Highlight; + --spectrum-calendar-day-background-color-down: ButtonFace; + --spectrum-calendar-day-background-color-hover: transparent; + --spectrum-calendar-day-background-color-key-focus: ButtonFace; + --spectrum-calendar-day-background-color-selected-hover: transparent; + --spectrum-calendar-day-background-color-selected: Highlight; + --spectrum-calendar-day-border-color-key-focus: ButtonText; + --spectrum-calendar-day-text-color-cap-selected: HighlightText; + --spectrum-calendar-day-text-color-disabled: GrayText; + --spectrum-calendar-day-text-color-hover: ButtonText; + --spectrum-calendar-day-text-color-key-focus: ButtonText; + --spectrum-calendar-day-text-color-selected-hover: HighlightText; + --spectrum-calendar-day-text-color-selected: HighlightText; + --spectrum-calendar-day-title-text-color: CanvasText; + --spectrum-calendar-day-today-background-color-selected-hover: Highlight; + --spectrum-calendar-day-today-border-color-disabled: GrayText; + --spectrum-calendar-day-today-border-color: ButtonText; + --spectrum-calendar-day-today-text-color-disabled: GrayText; + --spectrum-calendar-day-today-text-color: ButtonText; + color: CanvasText; + forced-color-adjust: none; + } + .spectrum-Calendar-date.is-range-selection { + color: HighlightText; + } + .spectrum-Calendar-date.is-range-selection.is-selection-end:after, + .spectrum-Calendar-date.is-range-selection.is-selection-start:after { + content: none; + } + .spectrum-Calendar-date.is-disabled.is-range-selection, + .spectrum-Calendar-date.is-disabled.is-selected { + background: Highlight; + color: HighlightText; + } + .spectrum-Calendar-date:hover.is-today { + color: ButtonText; + } +} diff --git a/packages/calendar/src/spectrum-config.js b/packages/calendar/src/spectrum-config.js new file mode 100644 index 00000000000..c83b888d563 --- /dev/null +++ b/packages/calendar/src/spectrum-config.js @@ -0,0 +1,35 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +// @ts-check + +import { converterFor } from '../../../tasks/process-spectrum-utils.js'; + +const converter = converterFor('spectrum-Calendar'); + +/** + * @type { import('../../../tasks/spectrum-css-converter').SpectrumCSSConverter } + */ +const config = { + conversions: [ + { + inPackage: '@spectrum-css/calendar', + outPackage: 'calendar', + fileName: 'calendar', + components: [ + converter.classToHost(), + converter.classToAttribute('spectrum-Calendar--padded'), + ], + }, + ], +}; + +export default config; diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts new file mode 100644 index 00000000000..cad15f9295d --- /dev/null +++ b/packages/calendar/stories/calendar.stories.ts @@ -0,0 +1,31 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { html, TemplateResult } from '@spectrum-web-components/base'; + +import '../sp-calendar.js'; + +export default { + title: 'Calendar', + component: 'sp-calendar', +}; + +export const Default = (): TemplateResult => { + return html` + + `; +}; + +export const paddedCalendar = (): TemplateResult => { + return html` + + `; +}; diff --git a/packages/calendar/test/benchmark/basic-test.ts b/packages/calendar/test/benchmark/basic-test.ts new file mode 100644 index 00000000000..5ae4a925f61 --- /dev/null +++ b/packages/calendar/test/benchmark/basic-test.ts @@ -0,0 +1,18 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import '@spectrum-web-components/calendar/sp-calendar.js'; +import { html } from '@spectrum-web-components/base'; +import { measureFixtureCreation } from '../../../../test/benchmark/helpers.js'; + +measureFixtureCreation(html` + +`); diff --git a/packages/calendar/test/calendar.test.ts b/packages/calendar/test/calendar.test.ts new file mode 100644 index 00000000000..9bc72ba3af8 --- /dev/null +++ b/packages/calendar/test/calendar.test.ts @@ -0,0 +1,38 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { elementUpdated, expect, fixture, html } from '@open-wc/testing'; + +import '../sp-calendar.js'; +import { Calendar } from '..'; +import { testForLitDevWarnings } from '../../../test/testing-helpers.js'; + +describe('Calendar', () => { + testForLitDevWarnings( + async () => + await fixture( + html` + + ` + ) + ); + it('loads default calendar accessibly', async () => { + const el = await fixture( + html` + + ` + ); + + await elementUpdated(el); + + await expect(el).to.be.accessible(); + }); +}); diff --git a/packages/calendar/tsconfig.json b/packages/calendar/tsconfig.json new file mode 100644 index 00000000000..c90873db4cf --- /dev/null +++ b/packages/calendar/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "composite": true, + "rootDir": "./" + }, + "include": ["*.ts", "src/*.ts"], + "exclude": ["test/*.ts", "stories/*.ts"], + "references": [{ "path": "../../tools/base" }] +} diff --git a/tools/bundle/elements.ts b/tools/bundle/elements.ts index 12e537eec70..af94b1b3ff1 100644 --- a/tools/bundle/elements.ts +++ b/tools/bundle/elements.ts @@ -22,6 +22,7 @@ import '@spectrum-web-components/banner/sp-banner.js'; import '@spectrum-web-components/button/sp-button.js'; import '@spectrum-web-components/button/sp-clear-button.js'; import '@spectrum-web-components/button-group/sp-button-group.js'; +import '@spectrum-web-components/calendar/sp-calendar.js'; import '@spectrum-web-components/card/sp-card.js'; import '@spectrum-web-components/checkbox/sp-checkbox.js'; import '@spectrum-web-components/coachmark/sp-coachmark.js'; diff --git a/tools/bundle/package.json b/tools/bundle/package.json index e32e397f9b6..cbf5716100d 100644 --- a/tools/bundle/package.json +++ b/tools/bundle/package.json @@ -72,6 +72,7 @@ "@spectrum-web-components/base": "^0.34.0", "@spectrum-web-components/button": "^0.34.0", "@spectrum-web-components/button-group": "^0.34.0", + "@spectrum-web-components/calendar": "^0.0.1", "@spectrum-web-components/card": "^0.34.0", "@spectrum-web-components/checkbox": "^0.34.0", "@spectrum-web-components/clear-button": "^0.34.0", diff --git a/tools/bundle/src/index.ts b/tools/bundle/src/index.ts index bc86cabd7e4..3d7a937e503 100644 --- a/tools/bundle/src/index.ts +++ b/tools/bundle/src/index.ts @@ -20,6 +20,7 @@ export * from '@spectrum-web-components/badge'; export * from '@spectrum-web-components/banner'; export * from '@spectrum-web-components/button'; export * from '@spectrum-web-components/button-group'; +export * from '@spectrum-web-components/calendar'; export * from '@spectrum-web-components/card'; export * from '@spectrum-web-components/checkbox'; export * from '@spectrum-web-components/coachmark'; diff --git a/tsconfig-all.json b/tsconfig-all.json index 7ef6eb33807..a3ad7b0c079 100644 --- a/tsconfig-all.json +++ b/tsconfig-all.json @@ -27,6 +27,7 @@ { "path": "packages/badge" }, { "path": "packages/button" }, { "path": "packages/button-group" }, + { "path": "packages/calendar" }, { "path": "packages/card" }, { "path": "packages/checkbox" }, { "path": "packages/clear-button" }, diff --git a/yarn.lock b/yarn.lock index 5b8fc212b22..bc6cb0b7a15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5339,6 +5339,11 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-6.0.57.tgz#e393ecef4c352e56c289fa660005db294be9d506" integrity sha512-pVdfGIcZdPeWv0Ha0BKICrQx7YiENwKlnT9mZXy3Dw8EAxWbR45zsb1xpsMOLFQ/UZtNn5njKD5FcC3gD2ZVRw== +"@spectrum-css/calendar@^3.1.23": + version "3.1.23" + resolved "https://registry.yarnpkg.com/@spectrum-css/calendar/-/calendar-3.1.23.tgz#ad24d53d3a454dc8b0bd1c67f1a4baffdfb6b4e4" + integrity sha512-TpOcf9IT8zR38WILdDaruLBTjnBIVl7Ix0Xv9StuuzAmzjeRMLK8jmd6hDTcWzcZcXP3c8+0oQ5XFRinWzYfSg== + "@spectrum-css/card@^6.0.4": version "6.0.4" resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-6.0.4.tgz#0dc81c5753c3c1540939061778576336852af135" @@ -5604,9 +5609,94 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-9.0.8.tgz#6af3bcdace903b8461f5fcd4c9aa23e70128a456" integrity sha512-rGfd7jqXOdR69bEjrRP58ynuIeJU0czPfwQvzhtCzg7jKVukV+efNHqrs086sC6xutB3W4TF71K/dZMr3oyTyg== +"@spectrum-web-components/action-button@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/action-button/-/action-button-0.32.0.tgz#84a923ce75961e847c5d787b896c2cae489bc2d8" + integrity sha512-DDSH+mkatskddifqUpdR3fgTa1HYIFvd/3N90zxZQAeJnpQECDNViB2Ybt7SRk1ZhHjTodzgwckOLV1HHDZKEg== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/button" "^0.32.0" + "@spectrum-web-components/icon" "^0.32.0" + "@spectrum-web-components/icons-ui" "^0.32.0" + "@spectrum-web-components/shared" "^0.32.0" + +"@spectrum-web-components/base@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/base/-/base-0.32.0.tgz#a9e10acb2e5c7dbd7bc38a4b5402991e8b49cea2" + integrity sha512-AkkWeRM5aAhXRmeAOIgSgLpPdQ2VjoGqNUmMFpmhRvRcrhnR0AqFcjmqNaEE6Zwkw7F2xyry3s3LC3yB+RWnaA== + dependencies: + lit "^2.5.0" + +"@spectrum-web-components/button@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/button/-/button-0.32.0.tgz#eb1f95daae50ccce5a1669289588788a16fae691" + integrity sha512-8lRqT8V4CU+MicJak2/frJZtZSbU6xFHxt7muK/mNv6dfQwuL2fUyadGowTLG6K/TyQi/faGiJZcc78jUspTsw== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/clear-button" "^0.32.0" + "@spectrum-web-components/close-button" "^0.32.0" + "@spectrum-web-components/icon" "^0.32.0" + "@spectrum-web-components/icons-ui" "^0.32.0" + "@spectrum-web-components/shared" "^0.32.0" + +"@spectrum-web-components/clear-button@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/clear-button/-/clear-button-0.32.0.tgz#6bcc0691be6f9d64359d678b009ac7ea31ae7cc4" + integrity sha512-OMnNfJN/V8fFXV0C1fAM0fHZwZQSC2BJbNLECBEUa7YxE8CjN7ENlgBWHk2aMGmpCTvCYXr7MS4yH3P834BzZA== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + +"@spectrum-web-components/close-button@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/close-button/-/close-button-0.32.0.tgz#536f558c0c827c344ccab519646c4868af93d9ec" + integrity sha512-8z7COXCj2+Bf1IpnNB8gojRWf6SJxXlK6d0IndVOO/xtkCOByqUXYPNwJ9s7dxrBZ9HHw0QNT758qkmpmn6icg== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/eslint-plugin@file:./linters/eslint": version "1.1.1" +"@spectrum-web-components/icon@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/icon/-/icon-0.32.0.tgz#6626c662393b3598ad58fb7ca729142f0442a909" + integrity sha512-ZyjVHy72xcE45QrfS+yRA44A6xK9vUCyUc2PqoPONtoJCv3O4aq9nqjwAWa4WLloN8G7yBoCthZHkg+oI5blgA== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/iconset" "^0.32.0" + +"@spectrum-web-components/icons-ui@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/icons-ui/-/icons-ui-0.32.0.tgz#adb828d65eaaa075a0abde8f746dcbc64c17b35f" + integrity sha512-AWPdnJg9QziqC+rViTrknS8r9BEv+6mf+xHB+nmmhKT/oXWKZJ03AltyGotyITOJk9w3UlLCHhAe7JL1xLV0rA== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/icon" "^0.32.0" + "@spectrum-web-components/iconset" "^0.32.0" + +"@spectrum-web-components/icons-workflow@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/icons-workflow/-/icons-workflow-0.32.0.tgz#8e9a2ef67736e57a74e7b47afb71fee504356902" + integrity sha512-aQTCQJDkeC6448MAgrL04GR60dU4y4Z8IQ6hy93HymL3WII7wVmOhNG8ibfznkv8se8Owt9Jb2EC2PvUM//SAg== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + "@spectrum-web-components/icon" "^0.32.0" + +"@spectrum-web-components/iconset@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/iconset/-/iconset-0.32.0.tgz#4a7679ba30609574b78504c1869e6a2abbbc58b2" + integrity sha512-pvauqxLX1ctj8iRRIMR/GnyUzmXsMdc4rL2/njyjwnTg9CTPbHo60m2Xa4l2EdW3R03/Ooz2vSs/e46bRZa6Xw== + dependencies: + "@spectrum-web-components/base" "^0.32.0" + +"@spectrum-web-components/shared@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@spectrum-web-components/shared/-/shared-0.32.0.tgz#e4e65c35e601320df65ded77404e84a193189e78" + integrity sha512-iPB/ZvYWyfV7ZpgyHwQ0VcB0ukt29iUploLZV9AgwF4YhLwg3GLkWJ2PABbLeQnfUy4uQvGnyUTc0HFW4R36HA== + dependencies: + "@lit-labs/observers" "^2.0.0" + "@spectrum-web-components/base" "^0.32.0" + focus-visible "^5.1.0" + "@storybook/csf-tools@^6.4.9": version "6.4.19" resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-6.4.19.tgz#28bdea11da17501a8bc4e761b821d7721880eaf6" From f8e27debfe34fc6eb98d482ef6d8ffad31cc2278 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Tue, 13 Jun 2023 15:12:08 +0100 Subject: [PATCH 02/25] feat: use first day of the week according to the locale --- packages/calendar/package.json | 8 +- packages/calendar/src/Calendar.ts | 1067 ++++------------- packages/calendar/src/types.ts | 17 + packages/calendar/stories/calendar.stories.ts | 106 +- yarn.lock | 7 + 5 files changed, 378 insertions(+), 827 deletions(-) create mode 100644 packages/calendar/src/types.ts diff --git a/packages/calendar/package.json b/packages/calendar/package.json index ad8edec960f..69f181f1bf9 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -34,6 +34,10 @@ "development": "./src/index.dev.js", "default": "./src/index.js" }, + "./src/types.js": { + "development": "./src/types.dev.js", + "default": "./src/types.js" + }, "./sp-calendar.js": { "development": "./sp-calendar.dev.js", "default": "./sp-calendar.js" @@ -57,9 +61,11 @@ "lit-html" ], "dependencies": { + "@internationalized/date": "^3.2.0", "@spectrum-web-components/action-button": "^0.32.0", "@spectrum-web-components/base": "^0.32.0", - "@spectrum-web-components/icons-workflow": "^0.32.0" + "@spectrum-web-components/icons-workflow": "^0.32.0", + "@spectrum-web-components/reactive-controllers": "^0.32.0" }, "devDependencies": { "@spectrum-css/calendar": "^3.1.23" diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index d39191c2e35..0099514b149 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -9,15 +9,31 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +import { + CalendarDate, + getLocalTimeZone, + getWeeksInMonth, + isSameDay, + startOfMonth, + startOfWeek, + today, +} from '@internationalized/date'; import { CSSResultArray, html, + PropertyValueMap, SpectrumElement, TemplateResult, } from '@spectrum-web-components/base'; +import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; -import styles from './calendar.css.js'; import { property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { when } from 'lit/directives/when.js'; + +import { CalendarWeekday, daysInWeek } from './types.js'; +import styles from './calendar.css.js'; import '@spectrum-web-components/action-button/sp-action-button.js'; import '@spectrum-web-components/icons-workflow/icons/sp-icon-chevron-left.js'; @@ -34,11 +50,80 @@ export class Calendar extends SpectrumElement { @property({ type: Boolean, reflect: true }) padded = false; + @property({ reflect: true }) + selectedDate!: Date | undefined; + + private _languageResolver = new LanguageResolutionController(this); + private _locale!: string; + private _timeZone: string = getLocalTimeZone(); + private _currentDate!: CalendarDate; + + public get today(): CalendarDate { + return today(this._timeZone); + } + + protected override willUpdate( + changedProperties: PropertyValueMap + ): void { + this._setLocale(); + this._setDefaultCalendarDate(); + + if (changedProperties.has('selectedDate')) { + if (this.selectedDate) { + this.selectedDate = new Date(this.selectedDate); + + if (isNaN(this.selectedDate.getTime())) { + this.selectedDate = undefined; + } else { + this.selectedDate.setHours(0, 0, 0, 0); + this._currentDate = this._toCalendarDate(this.selectedDate); + } + } + } + + super.updated(changedProperties); + } + protected override render(): TemplateResult { + return when( + this._currentDate, + () => html` + ${this.renderCalendarHeader()} + +
+ + + ${this.renderWeekDays()} + + + + ${this.renderWeekRows()} + + +
+ ` + ); + } + + public renderCalendarHeader(): TemplateResult { + const monthAndYear = this._capitalFirstLetter( + this._formatDate(this._currentDate, { + month: 'long', + year: 'numeric', + }) + ); + return html`
-
August 2017
+
${monthAndYear}
+ +
+ `; + } + + public renderWeekDays(): TemplateResult[] { + return this._getWeekdays().map( + (weekDay) => html` + + + ${weekDay.narrow} + + + ` + ); + } + + public renderWeekRows(): TemplateResult[] { + return [...new Array(this._getWeeksInCurrentMonth()).keys()].map( + (weekIndex) => html` + + ${this._getDatesInWeek(weekIndex).map((calendarDate) => + this.renderDay(calendarDate) + )} + + ` + ); + } + + public renderDay(calendarDate: CalendarDate): TemplateResult { + const isOutsideMonth = calendarDate.month !== this._currentDate.month; -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + ${calendarDate.day} + + `; } + + private _getWeeksInCurrentMonth(): number { + return getWeeksInMonth(this._currentDate, this._locale); + } + + private _getWeekdays(): CalendarWeekday[] { + const weekStart = startOfWeek(this._currentDate, this._locale); + + return [...new Array(daysInWeek).keys()].map((index) => { + const date = weekStart.add({ days: index }); + + return { + narrow: this._formatDate(date, { weekday: 'narrow' }), + long: this._capitalFirstLetter( + this._formatDate(date, { weekday: 'long' }) + ), + }; + }); + } + + private _formatDate( + calendarDate: CalendarDate, + options: Intl.DateTimeFormatOptions + ): string { + const date = calendarDate.toDate(this._timeZone); + + return new Intl.DateTimeFormat(this._locale, options).format(date); + } + + private _capitalFirstLetter(string: string): string { + return `${string.charAt(0).toUpperCase()}${string.substring(1)}`; + } + + private _setLocale(): void { + this._locale = this._languageResolver.language; + } + + private _setDefaultCalendarDate(): void { + this._currentDate = this.today; + } + + private _getDatesInWeek(weekIndex: number): CalendarDate[] { + const dates: CalendarDate[] = []; + + let date = startOfMonth(this._currentDate).add({ + weeks: weekIndex, + }); + + date = startOfWeek(date, this._locale); + + while (dates.length < daysInWeek) { + dates.push(date); + + const nextDate = date.add({ days: 1 }); + + // If the next day is the same, we have hit the end of the calendar system + if (isSameDay(date, nextDate)) { + break; + } + + date = nextDate; + } + + return dates; + } + + /** + * Converts a `Date` object to a `CalendarDate` + * + * @param date - `Date` object + */ + private _toCalendarDate(date: Date): CalendarDate { + return new CalendarDate( + date.getFullYear(), + date.getMonth() + 1, // The month to create a new `CalendarDate` cannot be a zero-based index, unlike `Date` + date.getDate() + ); + } } diff --git a/packages/calendar/src/types.ts b/packages/calendar/src/types.ts new file mode 100644 index 00000000000..659c5e03606 --- /dev/null +++ b/packages/calendar/src/types.ts @@ -0,0 +1,17 @@ +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +export const daysInWeek = 7; + +export interface CalendarWeekday { + narrow: string; + long: string; +} diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index cad15f9295d..b32c7406ef0 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -12,20 +12,118 @@ governing permissions and limitations under the License. import { html, TemplateResult } from '@spectrum-web-components/base'; import '../sp-calendar.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; + +const locales = [ + 'cs-CZ', + 'cy-GB', + 'da-DK', + 'de-DE', + 'en-GB', + 'en-US', + 'es-ES', + 'fi-FI', + 'fr-FR', + 'hu-HU', + 'it-IT', + 'ja-JP', + 'ko-KR', + 'nb-NO', + 'nl-NL', + 'pl-PL', + 'pt-BR', + 'ru-RU', + 'sv-SE', + 'tr-TR', + 'uk-UA', + 'zh-Hans-CN', + 'zh-Hant-TW', + 'zz-ZY', + 'zz-ZZ', +] as const; +type Locale = typeof locales; + +// Don't render private properties and getters in Storybook UI +const hiddenProperty = { + table: { + disable: true, + }, +}; export default { title: 'Calendar', component: 'sp-calendar', + + argTypes: { + padded: { + control: 'boolean', + }, + + _languageResolver: { ...hiddenProperty }, + _locale: { ...hiddenProperty }, + _timeZone: { ...hiddenProperty }, + _currentDate: { ...hiddenProperty }, + today: { ...hiddenProperty }, + + shadowRoot: { ...hiddenProperty }, + _dirParent: { ...hiddenProperty }, + dir: { ...hiddenProperty }, + isLTR: { ...hiddenProperty }, + }, + + args: { + padded: true, + }, + + // Hide "This story is not configured to handle controls" warning + parameters: { + controls: { hideNoControlsWarning: true }, + }, }; -export const Default = (): TemplateResult => { +interface StoryArgs { + padded?: boolean; + locale?: Locale; +} + +export const Default = (args: StoryArgs): TemplateResult => { + return html` + + `; +}; + +export const withDate = (args: StoryArgs): TemplateResult => { return html` - + `; }; -export const paddedCalendar = (): TemplateResult => { +export const otherLocales = (args: StoryArgs): TemplateResult => { return html` - + + + `; }; + +otherLocales.args = { + locale: 'en-US', +}; +otherLocales.argTypes = { + locale: { + name: 'locale', + description: 'Locale', + type: { name: 'string', required: true }, + control: { + type: 'select', + options: locales, + }, + }, +}; diff --git a/yarn.lock b/yarn.lock index bc6cb0b7a15..cc8501cd11d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2499,6 +2499,13 @@ resolved "https://registry.yarnpkg.com/@import-maps/resolve/-/resolve-1.0.1.tgz#1e9fcadcf23aa0822256a329aabca241879d37c9" integrity sha512-tWZNBIS1CoekcwlMuyG2mr0a1Wo5lb5lEHwwWvZo+5GLgr3e9LLDTtmgtCWEwBpXMkxn9D+2W9j2FY6eZQq0tA== +"@internationalized/date@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.2.0.tgz#1d266e5e5543a059cf8cca9b954fa033c3e58a75" + integrity sha512-VDMHN1m33L4eqPs5BaihzgQJXyaORbMoHOtrapFxx179J8ucY5CRIHYsq5RRLKPHZWgjNfa5v6amWWDkkMFywA== + dependencies: + "@swc/helpers" "^0.4.14" + "@internationalized/number@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.1.2.tgz#4482a6ac573acfb18efd354a42008af20da6c89c" From 304e0c94d84cb6c4d67b3646385acd61a8f99c9f Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Tue, 13 Jun 2023 16:53:44 +0100 Subject: [PATCH 03/25] feat: add "disabled" property --- packages/calendar/package.json | 2 +- packages/calendar/src/Calendar.ts | 28 +++++++++++++++---- packages/calendar/stories/calendar.stories.ts | 28 +++++++++++-------- yarn.lock | 8 +++--- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 69f181f1bf9..eb6e62511ad 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -68,7 +68,7 @@ "@spectrum-web-components/reactive-controllers": "^0.32.0" }, "devDependencies": { - "@spectrum-css/calendar": "^3.1.23" + "@spectrum-css/calendar": "^3.1.24" }, "types": "./src/index.d.ts", "customElements": "custom-elements.json", diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 0099514b149..17789d48afd 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -50,6 +50,9 @@ export class Calendar extends SpectrumElement { @property({ type: Boolean, reflect: true }) padded = false; + @property({ type: Boolean, reflect: true }) + disabled = false; + @property({ reflect: true }) selectedDate!: Date | undefined; @@ -95,7 +98,7 @@ export class Calendar extends SpectrumElement { role="grid" tabindex="0" aria-readonly="true" - aria-disabled="false" + aria-disabled=${this.disabled} > @@ -121,7 +124,17 @@ export class Calendar extends SpectrumElement { return html`
-
${monthAndYear}
+ + +
+ ${monthAndYear} +
+ + @@ -140,7 +154,8 @@ export class Calendar extends SpectrumElement { size="s" aria-label="Next" title="Next" - class="spectrum-Calendar-nextMonth" + class="spectrum-ActionButton spectrum-Calendar-nextMonth" + ?disabled=${this.disabled} > @@ -193,6 +208,7 @@ export class Calendar extends SpectrumElement { 'is-outsideMonth': isOutsideMonth, 'is-selected': isSelected, 'is-today': isToday, + 'is-disabled': this.disabled, }; const currentDayTitle = this._formatDate(calendarDate, { @@ -216,8 +232,8 @@ export class Calendar extends SpectrumElement { class="spectrum-Calendar-tableCell" title=${title} tabindex=${ifDefined(!isOutsideMonth ? '-1' : undefined)} - aria-disabled=${ifDefined(isOutsideMonth ? 'true' : undefined)} - aria-selected=${ifDefined(isSelected ? 'true' : undefined)} + aria-disabled=${isOutsideMonth || this.disabled} + aria-selected=${isSelected} > { +export const Default = (args: StoryArgs = {}): TemplateResult => { return html` - + `; }; -export const withDate = (args: StoryArgs): TemplateResult => { +export const withSelectedDate = (args: StoryArgs = {}): TemplateResult => { return html` `; }; -export const otherLocales = (args: StoryArgs): TemplateResult => { +export const otherLocales = (args: StoryArgs = {}): TemplateResult => { return html` - + `; }; diff --git a/yarn.lock b/yarn.lock index cc8501cd11d..0b507fc1659 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5346,10 +5346,10 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-6.0.57.tgz#e393ecef4c352e56c289fa660005db294be9d506" integrity sha512-pVdfGIcZdPeWv0Ha0BKICrQx7YiENwKlnT9mZXy3Dw8EAxWbR45zsb1xpsMOLFQ/UZtNn5njKD5FcC3gD2ZVRw== -"@spectrum-css/calendar@^3.1.23": - version "3.1.23" - resolved "https://registry.yarnpkg.com/@spectrum-css/calendar/-/calendar-3.1.23.tgz#ad24d53d3a454dc8b0bd1c67f1a4baffdfb6b4e4" - integrity sha512-TpOcf9IT8zR38WILdDaruLBTjnBIVl7Ix0Xv9StuuzAmzjeRMLK8jmd6hDTcWzcZcXP3c8+0oQ5XFRinWzYfSg== +"@spectrum-css/calendar@^3.1.24": + version "3.1.24" + resolved "https://registry.yarnpkg.com/@spectrum-css/calendar/-/calendar-3.1.24.tgz#64001a1ec91c4b0516043d82ea2bd4992557a3a2" + integrity sha512-zwtfw7Dx60/2IqpL7w0stHpCSaKoCYFpW2cxSSw+ETppAOLiP1Fi94xkd1wzWxx7bsD/7y33585XyseDhFYOZQ== "@spectrum-css/card@^6.0.4": version "6.0.4" From fdd06602f8b42e93a43403be0bc772ae1c658bc4 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 14 Jun 2023 11:43:23 +0100 Subject: [PATCH 04/25] feat: handle "Previous" and "Next" month buttons --- packages/calendar/src/Calendar.ts | 37 ++++++++++++++----- packages/calendar/stories/calendar.stories.ts | 30 ++++++++++++--- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 17789d48afd..7924cf2ec5f 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -27,7 +27,7 @@ import { } from '@spectrum-web-components/base'; import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; -import { property } from 'lit/decorators.js'; +import { property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { when } from 'lit/directives/when.js'; @@ -56,20 +56,28 @@ export class Calendar extends SpectrumElement { @property({ reflect: true }) selectedDate!: Date | undefined; + @state() + private _currentDate!: CalendarDate; + private _languageResolver = new LanguageResolutionController(this); private _locale!: string; private _timeZone: string = getLocalTimeZone(); - private _currentDate!: CalendarDate; public get today(): CalendarDate { return today(this._timeZone); } + constructor() { + super(); + + this._setLocale(); + this._setDefaultCalendarDate(); + } + protected override willUpdate( changedProperties: PropertyValueMap ): void { this._setLocale(); - this._setDefaultCalendarDate(); if (changedProperties.has('selectedDate')) { if (this.selectedDate) { @@ -83,8 +91,6 @@ export class Calendar extends SpectrumElement { } } } - - super.updated(changedProperties); } protected override render(): TemplateResult { @@ -144,6 +150,7 @@ export class Calendar extends SpectrumElement { title="Previous" class="spectrum-ActionButton spectrum-Calendar-prevMonth" ?disabled=${this.disabled} + @click=${this.handlePreviousMonth} > @@ -156,6 +163,7 @@ export class Calendar extends SpectrumElement { title="Next" class="spectrum-ActionButton spectrum-Calendar-nextMonth" ?disabled=${this.disabled} + @click=${this.handleNextMonth} > @@ -245,6 +253,16 @@ export class Calendar extends SpectrumElement { `; } + public handlePreviousMonth(): void { + this._currentDate = startOfMonth(this._currentDate).subtract({ + months: 1, + }); + } + + public handleNextMonth(): void { + this._currentDate = startOfMonth(this._currentDate).add({ months: 1 }); + } + private _getWeeksInCurrentMonth(): number { return getWeeksInMonth(this._currentDate, this._locale); } @@ -288,11 +306,10 @@ export class Calendar extends SpectrumElement { private _getDatesInWeek(weekIndex: number): CalendarDate[] { const dates: CalendarDate[] = []; - let date = startOfMonth(this._currentDate).add({ - weeks: weekIndex, - }); - - date = startOfWeek(date, this._locale); + let date = startOfWeek( + startOfMonth(this._currentDate).add({ weeks: weekIndex }), + this._locale + ); while (dates.length < daysInWeek) { dates.push(date); diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 88b3aa140ff..ff139056c62 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -42,8 +42,11 @@ const locales = [ 'zz-ZY', 'zz-ZZ', ] as const; + type Locale = typeof locales; +const defaultLocale = 'en-US'; + // Don't render private properties and getters in Storybook UI const hiddenProperty = { table: { @@ -82,7 +85,9 @@ export default { // Hide "This story is not configured to handle controls" warning parameters: { - controls: { hideNoControlsWarning: true }, + controls: { + hideNoControlsWarning: true, + }, }, }; @@ -101,10 +106,19 @@ export const Default = (args: StoryArgs = {}): TemplateResult => { }; export const withSelectedDate = (args: StoryArgs = {}): TemplateResult => { + const selectedDate = new Date(2019, 0, 30); + const formattedDate = Intl.DateTimeFormat(defaultLocale, { + day: 'numeric', + month: 'long', + year: 'numeric', + }).format(selectedDate); + return html` +

Selected Date: ${formattedDate}

+ `; }; @@ -112,22 +126,28 @@ export const withSelectedDate = (args: StoryArgs = {}): TemplateResult => { export const otherLocales = (args: StoryArgs = {}): TemplateResult => { return html` +

Locale: ${args.locale}

+
`; }; otherLocales.args = { - locale: 'en-US', + locale: defaultLocale, }; otherLocales.argTypes = { locale: { name: 'locale', description: 'Locale', - type: { name: 'string', required: true }, + options: locales, control: { type: 'select', - options: locales, + }, + table: { + defaultValue: { + summary: defaultLocale, + }, }, }, }; From 07fdf78397a89bb70dac5cc4ee258bfb0190832d Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 14 Jun 2023 12:41:04 +0100 Subject: [PATCH 05/25] feat: add locale for all stories --- packages/calendar/stories/calendar.stories.ts | 107 +++++++++++------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index ff139056c62..65c629d2bd1 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -47,7 +47,6 @@ type Locale = typeof locales; const defaultLocale = 'en-US'; -// Don't render private properties and getters in Storybook UI const hiddenProperty = { table: { disable: true, @@ -59,13 +58,19 @@ export default { component: 'sp-calendar', argTypes: { - padded: { - control: 'boolean', - }, - disabled: { - control: 'boolean', + locale: { + options: locales, + control: { + type: 'select', + }, + table: { + defaultValue: { + summary: defaultLocale, + }, + }, }, + // Don't render private properties and getters in Storybook UI _languageResolver: { ...hiddenProperty }, _locale: { ...hiddenProperty }, _timeZone: { ...hiddenProperty }, @@ -79,8 +84,7 @@ export default { }, args: { - padded: false, - disabled: false, + locale: defaultLocale, }, // Hide "This story is not configured to handle controls" warning @@ -99,55 +103,76 @@ interface StoryArgs { [prop: string]: unknown; } -export const Default = (args: StoryArgs = {}): TemplateResult => { +const renderCalendar = ( + title: string, + args: StoryArgs = {} +): TemplateResult => { return html` - + +

${title}

+

+ Locale: + ${args.locale} +

+ +
+ + +
`; }; -export const withSelectedDate = (args: StoryArgs = {}): TemplateResult => { - const selectedDate = new Date(2019, 0, 30); - const formattedDate = Intl.DateTimeFormat(defaultLocale, { +export const Default = (args: StoryArgs = {}): TemplateResult => { + return renderCalendar('Default', args); +}; + +export const padded = (args: StoryArgs = {}): TemplateResult => { + return renderCalendar(`Padded? ${args.padded}`, args); +}; + +padded.argTypes = { + padded: { + control: 'boolean', + table: { + defaultValue: { + summary: true, + }, + }, + }, +}; + +padded.args = { + padded: true, +}; + +export const selectedDate = (args: StoryArgs = {}): TemplateResult => { + const date = new Date(2019, 0, 30); + const formatted = Intl.DateTimeFormat(defaultLocale, { day: 'numeric', month: 'long', year: 'numeric', - }).format(selectedDate); + }).format(date); - return html` -

Selected Date: ${formattedDate}

+ args = { ...args, selectedDate: date }; - - `; + return renderCalendar(`Selected Date: ${formatted}`, args); }; -export const otherLocales = (args: StoryArgs = {}): TemplateResult => { - return html` - -

Locale: ${args.locale}

- - -
- `; +export const disabled = (args: StoryArgs = {}): TemplateResult => { + return renderCalendar(`Disabled? ${args.disabled}`, args); }; -otherLocales.args = { - locale: defaultLocale, -}; -otherLocales.argTypes = { - locale: { - name: 'locale', - description: 'Locale', - options: locales, - control: { - type: 'select', - }, +disabled.argTypes = { + disabled: { + control: 'boolean', table: { defaultValue: { - summary: defaultLocale, + summary: true, }, }, }, }; + +disabled.args = { + disabled: true, +}; From b61eea7ec529daec17dfd19cdf42cad09e7d729b Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 14 Jun 2023 15:46:56 +0100 Subject: [PATCH 06/25] feat: add "min" and "max" date --- packages/calendar/src/Calendar.ts | 101 ++++++++++++++---- packages/calendar/stories/calendar.stories.ts | 81 ++++++++++---- 2 files changed, 143 insertions(+), 39 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 7924cf2ec5f..f718f574669 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -56,9 +56,21 @@ export class Calendar extends SpectrumElement { @property({ reflect: true }) selectedDate!: Date | undefined; + @property({ reflect: true }) + min!: Date | undefined; + + @property({ reflect: true }) + max!: Date | undefined; + @state() private _currentDate!: CalendarDate; + @state() + private _minDate!: CalendarDate; + + @state() + private _maxDate!: CalendarDate; + private _languageResolver = new LanguageResolutionController(this); private _locale!: string; private _timeZone: string = getLocalTimeZone(); @@ -80,16 +92,15 @@ export class Calendar extends SpectrumElement { this._setLocale(); if (changedProperties.has('selectedDate')) { - if (this.selectedDate) { - this.selectedDate = new Date(this.selectedDate); - - if (isNaN(this.selectedDate.getTime())) { - this.selectedDate = undefined; - } else { - this.selectedDate.setHours(0, 0, 0, 0); - this._currentDate = this._toCalendarDate(this.selectedDate); - } - } + this._setCurrentCalendarDate(); + } + + if (changedProperties.has('min')) { + this._setMinCalendarDate(); + } + + if (changedProperties.has('max')) { + this._setMaxCalendarDate(); } } @@ -102,7 +113,7 @@ export class Calendar extends SpectrumElement {
@@ -212,11 +223,17 @@ export class Calendar extends SpectrumElement { const isToday = Boolean(isSameDay(calendarDate, this.today)); + const isDisabled = Boolean( + this.disabled || + (this._minDate && calendarDate.compare(this._minDate) < 0) || + (this._maxDate && calendarDate.compare(this._maxDate) > 0) + ); + const dayClasses = { 'is-outsideMonth': isOutsideMonth, 'is-selected': isSelected, 'is-today': isToday, - 'is-disabled': this.disabled, + 'is-disabled': isDisabled, }; const currentDayTitle = this._formatDate(calendarDate, { @@ -267,6 +284,10 @@ export class Calendar extends SpectrumElement { return getWeeksInMonth(this._currentDate, this._locale); } + /** + * Returns data for the days of the week, starting with the first day of the week according to the defined locale + * (Sunday, Monday, etc.) + */ private _getWeekdays(): CalendarWeekday[] { const weekStart = startOfWeek(this._currentDate, this._locale); @@ -286,9 +307,9 @@ export class Calendar extends SpectrumElement { calendarDate: CalendarDate, options: Intl.DateTimeFormatOptions ): string { - const date = calendarDate.toDate(this._timeZone); - - return new Intl.DateTimeFormat(this._locale, options).format(date); + return new Intl.DateTimeFormat(this._locale, options).format( + calendarDate.toDate(this._timeZone) + ); } private _capitalFirstLetter(string: string): string { @@ -303,6 +324,42 @@ export class Calendar extends SpectrumElement { this._currentDate = this.today; } + private _setCurrentCalendarDate(): void { + if (this.selectedDate) { + this.selectedDate = new Date(this.selectedDate); + + if (!this._isValidDate(this.selectedDate)) { + this.selectedDate = undefined; + } else { + this._currentDate = this._toCalendarDate(this.selectedDate); + } + } + } + + private _setMinCalendarDate(): void { + if (this.min) { + this.min = new Date(this.min); + + if (!this._isValidDate(this.min)) { + this.min = undefined; + } else { + this._minDate = this._toCalendarDate(this.min); + } + } + } + + private _setMaxCalendarDate(): void { + if (this.max) { + this.max = new Date(this.max); + + if (!this._isValidDate(this.max)) { + this.max = undefined; + } else { + this._maxDate = this._toCalendarDate(this.max); + } + } + } + private _getDatesInWeek(weekIndex: number): CalendarDate[] { const dates: CalendarDate[] = []; @@ -327,11 +384,6 @@ export class Calendar extends SpectrumElement { return dates; } - /** - * Converts a `Date` object to a `CalendarDate` - * - * @param date - `Date` object - */ private _toCalendarDate(date: Date): CalendarDate { return new CalendarDate( date.getFullYear(), @@ -339,4 +391,13 @@ export class Calendar extends SpectrumElement { date.getDate() ); } + + /** + * Checks if the date is valid by parsing the time. Invalid dates return `NaN` for times of invalid dates + * + * @param date - `Date` object to validate + */ + private _isValidDate(date: Date): boolean { + return !isNaN(date.getTime()); + } } diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 65c629d2bd1..842f6dd5514 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -43,8 +43,6 @@ const locales = [ 'zz-ZZ', ] as const; -type Locale = typeof locales; - const defaultLocale = 'en-US'; const hiddenProperty = { @@ -75,6 +73,8 @@ export default { _locale: { ...hiddenProperty }, _timeZone: { ...hiddenProperty }, _currentDate: { ...hiddenProperty }, + _minDate: { ...hiddenProperty }, + _maxDate: { ...hiddenProperty }, today: { ...hiddenProperty }, shadowRoot: { ...hiddenProperty }, @@ -96,10 +96,6 @@ export default { }; interface StoryArgs { - padded?: boolean; - disabled?: boolean; - locale?: Locale; - [prop: string]: unknown; } @@ -145,19 +141,6 @@ padded.args = { padded: true, }; -export const selectedDate = (args: StoryArgs = {}): TemplateResult => { - const date = new Date(2019, 0, 30); - const formatted = Intl.DateTimeFormat(defaultLocale, { - day: 'numeric', - month: 'long', - year: 'numeric', - }).format(date); - - args = { ...args, selectedDate: date }; - - return renderCalendar(`Selected Date: ${formatted}`, args); -}; - export const disabled = (args: StoryArgs = {}): TemplateResult => { return renderCalendar(`Disabled? ${args.disabled}`, args); }; @@ -176,3 +159,63 @@ disabled.argTypes = { disabled.args = { disabled: true, }; + +export const selectedDate = (args: StoryArgs = {}): TemplateResult => { + const date = new Date(2019, 0, 30); + const formatted = Intl.DateTimeFormat(defaultLocale, { + day: 'numeric', + month: 'long', + year: 'numeric', + }).format(date); + + args = { + ...args, + selectedDate: date, + }; + + return renderCalendar(`Selected Date: ${formatted}`, args); +}; + +export const minimumDate = (args: StoryArgs = {}): TemplateResult => { + const today = new Date(); + const lastMonth = new Date( + today.getFullYear(), + today.getMonth() - 1, + today.getDate() + ); + + const formatted = Intl.DateTimeFormat(defaultLocale, { + day: 'numeric', + month: 'long', + year: 'numeric', + }).format(lastMonth); + + args = { + ...args, + min: lastMonth, + }; + + return renderCalendar(`Minimum Date: ${formatted}`, args); +}; + +export const maximumDate = (args: StoryArgs = {}): TemplateResult => { + const today = new Date(); + const nextMonth = new Date( + today.getFullYear(), + today.getMonth() + 1, + today.getDate() + ); + + const formatted = Intl.DateTimeFormat(defaultLocale, { + day: 'numeric', + month: 'long', + year: 'numeric', + }).format(nextMonth); + + args = { + ...args, + max: nextMonth, + }; + + return renderCalendar(`Maximum Date: ${formatted}`, args); +}; From 619be78b9ae1af33df984448aed3ddb4cc818c72 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 14 Jun 2023 17:08:54 +0100 Subject: [PATCH 07/25] refactor: add new render methods --- packages/calendar/src/Calendar.ts | 102 +++++++++++++++++------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index f718f574669..7ad52ad5024 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -108,25 +108,7 @@ export class Calendar extends SpectrumElement { return when( this._currentDate, () => html` - ${this.renderCalendarHeader()} - -
-
- - ${this.renderWeekDays()} - - - - ${this.renderWeekRows()} - - - + ${this.renderCalendarHeader()}${this.renderCalendarGrid()} ` ); } @@ -182,38 +164,70 @@ export class Calendar extends SpectrumElement { `; } - public renderWeekDays(): TemplateResult[] { - return this._getWeekdays().map( - (weekDay) => html` - - - ${weekDay.narrow} - - - ` - ); + public renderCalendarGrid(): TemplateResult { + return html` +
+ + ${this.renderCalendarTableHead()} + ${this.renderCalendarTableBody()} + +
+ `; } - public renderWeekRows(): TemplateResult[] { - return [...new Array(this._getWeeksInCurrentMonth()).keys()].map( - (weekIndex) => html` + public renderCalendarTableHead(): TemplateResult { + return html` + - ${this._getDatesInWeek(weekIndex).map((calendarDate) => - this.renderDay(calendarDate) + ${this._getWeekdays().map((weekday) => + this.renderWeekdayColumn(weekday) )} - ` - ); + + `; + } + + public renderWeekdayColumn(weekday: CalendarWeekday): TemplateResult { + return html` + + + ${weekday.narrow} + + + `; + } + + public renderCalendarTableBody(): TemplateResult { + return html` + + ${[...new Array(this._getWeeksInCurrentMonth()).keys()].map( + (weekIndex) => this.renderCalendarTableRow(weekIndex) + )} + + `; + } + + public renderCalendarTableRow(weekIndex: number): TemplateResult { + return html` + + ${this._getDatesInWeek(weekIndex).map((calendarDate) => + this.renderCalendarTableCell(calendarDate) + )} + + `; } - public renderDay(calendarDate: CalendarDate): TemplateResult { + public renderCalendarTableCell(calendarDate: CalendarDate): TemplateResult { const isOutsideMonth = calendarDate.month !== this._currentDate.month; const isSelected = Boolean( From 6336db2a85e275fcbda35e5696e62b3fd33e5fe8 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Thu, 15 Jun 2023 15:40:37 +0100 Subject: [PATCH 08/25] feat: format day using Intl.NumberFormat --- packages/calendar/src/Calendar.ts | 43 ++++++++++--------- packages/calendar/stories/calendar.stories.ts | 1 + 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 7ad52ad5024..65934030c98 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -83,7 +83,7 @@ export class Calendar extends SpectrumElement { super(); this._setLocale(); - this._setDefaultCalendarDate(); + this._setInitialCalendarDate(); } protected override willUpdate( @@ -278,7 +278,7 @@ export class Calendar extends SpectrumElement { role="presentation" class="spectrum-Calendar-date ${classMap(dayClasses)}" > - ${calendarDate.day} + ${this._formatNumber(calendarDate.day)} `; @@ -303,10 +303,9 @@ export class Calendar extends SpectrumElement { * (Sunday, Monday, etc.) */ private _getWeekdays(): CalendarWeekday[] { - const weekStart = startOfWeek(this._currentDate, this._locale); - - return [...new Array(daysInWeek).keys()].map((index) => { - const date = weekStart.add({ days: index }); + return [...new Array(daysInWeek).keys()].map((dayIndex) => { + const weekStart = startOfWeek(this._currentDate, this._locale); + const date = weekStart.add({ days: dayIndex }); return { narrow: this._formatDate(date, { weekday: 'narrow' }), @@ -317,24 +316,11 @@ export class Calendar extends SpectrumElement { }); } - private _formatDate( - calendarDate: CalendarDate, - options: Intl.DateTimeFormatOptions - ): string { - return new Intl.DateTimeFormat(this._locale, options).format( - calendarDate.toDate(this._timeZone) - ); - } - - private _capitalFirstLetter(string: string): string { - return `${string.charAt(0).toUpperCase()}${string.substring(1)}`; - } - private _setLocale(): void { this._locale = this._languageResolver.language; } - private _setDefaultCalendarDate(): void { + private _setInitialCalendarDate(): void { this._currentDate = this.today; } @@ -414,4 +400,21 @@ export class Calendar extends SpectrumElement { private _isValidDate(date: Date): boolean { return !isNaN(date.getTime()); } + + private _formatDate( + calendarDate: CalendarDate, + options: Intl.DateTimeFormatOptions + ): string { + return new Intl.DateTimeFormat(this._locale, options).format( + calendarDate.toDate(this._timeZone) + ); + } + + private _formatNumber(number: number): string { + return new Intl.NumberFormat(this._locale).format(number); + } + + private _capitalFirstLetter(string: string): string { + return `${string.charAt(0).toUpperCase()}${string.substring(1)}`; + } } diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 842f6dd5514..34be0c1fc5f 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -38,6 +38,7 @@ const locales = [ 'tr-TR', 'uk-UA', 'zh-Hans-CN', + 'zh-Hans-CN-u-nu-hanidec', 'zh-Hant-TW', 'zz-ZY', 'zz-ZZ', From 2ac6dd3ebaa52211d282fb4e6452e777cbfa2a87 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Mon, 19 Jun 2023 15:20:46 +0100 Subject: [PATCH 09/25] fix: lit-plugin "no-incompatible-property-type" * The built in converter doesn't handle the property type Date | undefined --- packages/calendar/src/Calendar.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 65934030c98..fc202f985ed 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -53,13 +53,13 @@ export class Calendar extends SpectrumElement { @property({ type: Boolean, reflect: true }) disabled = false; - @property({ reflect: true }) + @property({ reflect: true, attribute: false }) selectedDate!: Date | undefined; - @property({ reflect: true }) + @property({ reflect: true, attribute: false }) min!: Date | undefined; - @property({ reflect: true }) + @property({ reflect: true, attribute: false }) max!: Date | undefined; @state() From d218c5efb6a5a2a4f3b139f42234d950141b29ee Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Tue, 20 Jun 2023 15:36:18 +0100 Subject: [PATCH 10/25] fix: packages version + property type error --- packages/calendar/package.json | 8 ++++---- packages/calendar/stories/calendar.stories.ts | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/calendar/package.json b/packages/calendar/package.json index eb6e62511ad..8b329754cf8 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -62,10 +62,10 @@ ], "dependencies": { "@internationalized/date": "^3.2.0", - "@spectrum-web-components/action-button": "^0.32.0", - "@spectrum-web-components/base": "^0.32.0", - "@spectrum-web-components/icons-workflow": "^0.32.0", - "@spectrum-web-components/reactive-controllers": "^0.32.0" + "@spectrum-web-components/action-button": "^0.33.2", + "@spectrum-web-components/base": "^0.33.2", + "@spectrum-web-components/icons-workflow": "^0.33.2", + "@spectrum-web-components/reactive-controllers": "^0.33.2" }, "devDependencies": { "@spectrum-css/calendar": "^3.1.24" diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 34be0c1fc5f..aba6a8d9dca 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -11,6 +11,8 @@ governing permissions and limitations under the License. */ import { html, TemplateResult } from '@spectrum-web-components/base'; +import { ifDefined } from 'lit/directives/if-defined.js'; + import { spreadProps } from '../../../test/lit-helpers.js'; import '../sp-calendar.js'; @@ -97,6 +99,12 @@ export default { }; interface StoryArgs { + locale?: string; + padded?: boolean; + disabled?: boolean; + selectedDate?: Date; + min?: Date; + max?: Date; [prop: string]: unknown; } @@ -105,7 +113,7 @@ const renderCalendar = ( args: StoryArgs = {} ): TemplateResult => { return html` - +

${title}

Locale: From db4d3fb791feac4ac5fecfd4435c7ae402311959 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 21 Jun 2023 14:50:21 +0100 Subject: [PATCH 11/25] refactor: add to-do list to README --- packages/calendar/README.md | 7 +++++++ packages/calendar/src/Calendar.ts | 15 ++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/calendar/README.md b/packages/calendar/README.md index c2d406a9d4d..daff7fb3a4e 100644 --- a/packages/calendar/README.md +++ b/packages/calendar/README.md @@ -26,3 +26,10 @@ import { Calendar } from '@spectrum-web-components/calendar'; ```html ``` + +## To-do list + +- Attribute `role="heading"` removed from `.spectrum-Calendar-title`, due to error _'The "heading" role requires the attribute "aria-level"'_ +- Translate _"Previous"_ and _"Next"_ used in the `title` and `aria-label` of buttons displayed in the header of the calendar +- Translate _"Today"_ and _"selected"_ used in the `title` of the day when it is today +- Implement keyboard navigation diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index fc202f985ed..6f35db20985 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -54,13 +54,13 @@ export class Calendar extends SpectrumElement { disabled = false; @property({ reflect: true, attribute: false }) - selectedDate!: Date | undefined; + selectedDate?: Date; @property({ reflect: true, attribute: false }) - min!: Date | undefined; + min?: Date; @property({ reflect: true, attribute: false }) - max!: Date | undefined; + max?: Date; @state() private _currentDate!: CalendarDate; @@ -123,8 +123,10 @@ export class Calendar extends SpectrumElement { return html`
- - +
- -
Date: Fri, 23 Jun 2023 15:54:56 +0100 Subject: [PATCH 12/25] feat: add event handlers and slots for icons --- packages/calendar/src/Calendar.ts | 32 +++++++++++++++++-- packages/calendar/stories/calendar.stories.ts | 22 ++++++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 6f35db20985..43e4bf67ecb 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -41,6 +41,11 @@ import '@spectrum-web-components/icons-workflow/icons/sp-icon-chevron-right.js'; /** * @element sp-calendar + * + * @slot prev-icon - The icon used in the _"Previous Month"_ button + * @slot next-icon - The icon used in the _"Next Month"_ button + * + * @event change - Announces when a day is selected by emitting a `Date` object */ export class Calendar extends SpectrumElement { public static override get styles(): CSSResultArray { @@ -145,7 +150,11 @@ export class Calendar extends SpectrumElement { ?disabled=${this.disabled} @click=${this.handlePreviousMonth} > - +
+ + + +
@@ -158,7 +167,11 @@ export class Calendar extends SpectrumElement { ?disabled=${this.disabled} @click=${this.handleNextMonth} > - +
+ + + +
`; @@ -278,6 +291,7 @@ export class Calendar extends SpectrumElement { this.handleDayClick(calendarDate)} > ${this._formatNumber(calendarDate.day)} @@ -295,6 +309,20 @@ export class Calendar extends SpectrumElement { this._currentDate = startOfMonth(this._currentDate).add({ months: 1 }); } + public handleDayClick(calendarDate: CalendarDate): void { + this.selectedDate = calendarDate.toDate(this._timeZone); + this._setCurrentCalendarDate(); + + this.dispatchEvent( + new CustomEvent('change', { + bubbles: true, + cancelable: true, + composed: true, + detail: this.selectedDate, + }) + ); + } + private _getWeeksInCurrentMonth(): number { return getWeeksInMonth(this._currentDate, this._locale); } diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index aba6a8d9dca..65e562fd523 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -17,6 +17,9 @@ import { spreadProps } from '../../../test/lit-helpers.js'; import '../sp-calendar.js'; +import '@spectrum-web-components/calendar/sp-calendar.js'; +import '@spectrum-web-components/theme/sp-theme.js'; + const locales = [ 'cs-CZ', 'cy-GB', @@ -71,7 +74,7 @@ export default { }, }, - // Don't render private properties and getters in Storybook UI + // Don't render private properties and getters in the Storybook UI _languageResolver: { ...hiddenProperty }, _locale: { ...hiddenProperty }, _timeZone: { ...hiddenProperty }, @@ -80,8 +83,9 @@ export default { _maxDate: { ...hiddenProperty }, today: { ...hiddenProperty }, - shadowRoot: { ...hiddenProperty }, + // Inherited _dirParent: { ...hiddenProperty }, + shadowRoot: { ...hiddenProperty }, dir: { ...hiddenProperty }, isLTR: { ...hiddenProperty }, }, @@ -90,21 +94,28 @@ export default { locale: defaultLocale, }, - // Hide "This story is not configured to handle controls" warning parameters: { controls: { + // Hide "This story is not configured to handle controls" warning hideNoControlsWarning: true, }, + actions: { + handles: ['onChange'], + }, }, }; interface StoryArgs { locale?: string; + padded?: boolean; disabled?: boolean; selectedDate?: Date; min?: Date; max?: Date; + + onChange?: (date: Date) => void; + [prop: string]: unknown; } @@ -122,7 +133,10 @@ const renderCalendar = (
- + `; }; From c18991c6c69344dc38132db2b5ee18399ad30b65 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Tue, 18 Jul 2023 17:56:59 +0100 Subject: [PATCH 13/25] refactor(calendar): update dependencies --- packages/calendar/package.json | 15 +++--- yarn.lock | 93 ++-------------------------------- 2 files changed, 11 insertions(+), 97 deletions(-) diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 8b329754cf8..16593fc8076 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -16,8 +16,8 @@ "bugs": { "url": "https://github.com/adobe/spectrum-web-components/issues" }, - "main": "src/index.js", - "module": "src/index.js", + "main": "./src/index.js", + "module": "./src/index.js", "type": "module", "exports": { ".": { @@ -62,19 +62,18 @@ ], "dependencies": { "@internationalized/date": "^3.2.0", - "@spectrum-web-components/action-button": "^0.33.2", - "@spectrum-web-components/base": "^0.33.2", - "@spectrum-web-components/icons-workflow": "^0.33.2", - "@spectrum-web-components/reactive-controllers": "^0.33.2" + "@spectrum-web-components/action-button": "^0.34.0", + "@spectrum-web-components/base": "^0.34.0", + "@spectrum-web-components/icons-workflow": "^0.34.0", + "@spectrum-web-components/reactive-controllers": "^0.34.0" }, "devDependencies": { - "@spectrum-css/calendar": "^3.1.24" + "@spectrum-css/calendar": "^3.2.6" }, "types": "./src/index.d.ts", "customElements": "custom-elements.json", "sideEffects": [ "./sp-*.js", - "./**/*.dev.js", "./**/*.dev.js" ] } diff --git a/yarn.lock b/yarn.lock index 0b507fc1659..538faa80e9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5346,10 +5346,10 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-6.0.57.tgz#e393ecef4c352e56c289fa660005db294be9d506" integrity sha512-pVdfGIcZdPeWv0Ha0BKICrQx7YiENwKlnT9mZXy3Dw8EAxWbR45zsb1xpsMOLFQ/UZtNn5njKD5FcC3gD2ZVRw== -"@spectrum-css/calendar@^3.1.24": - version "3.1.24" - resolved "https://registry.yarnpkg.com/@spectrum-css/calendar/-/calendar-3.1.24.tgz#64001a1ec91c4b0516043d82ea2bd4992557a3a2" - integrity sha512-zwtfw7Dx60/2IqpL7w0stHpCSaKoCYFpW2cxSSw+ETppAOLiP1Fi94xkd1wzWxx7bsD/7y33585XyseDhFYOZQ== +"@spectrum-css/calendar@^3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@spectrum-css/calendar/-/calendar-3.2.6.tgz#edd700b5b6188a67711087c9604c7dda9ac8920a" + integrity sha512-bB5CXl6B4zpJizEXmRGvv+WJHImXi2D4VaRL0Yi7EBmswYfi0eEjN6CiKljoqe+MBc5nHPp4pimI08Al08q2MA== "@spectrum-css/card@^6.0.4": version "6.0.4" @@ -5616,94 +5616,9 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-9.0.8.tgz#6af3bcdace903b8461f5fcd4c9aa23e70128a456" integrity sha512-rGfd7jqXOdR69bEjrRP58ynuIeJU0czPfwQvzhtCzg7jKVukV+efNHqrs086sC6xutB3W4TF71K/dZMr3oyTyg== -"@spectrum-web-components/action-button@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/action-button/-/action-button-0.32.0.tgz#84a923ce75961e847c5d787b896c2cae489bc2d8" - integrity sha512-DDSH+mkatskddifqUpdR3fgTa1HYIFvd/3N90zxZQAeJnpQECDNViB2Ybt7SRk1ZhHjTodzgwckOLV1HHDZKEg== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/button" "^0.32.0" - "@spectrum-web-components/icon" "^0.32.0" - "@spectrum-web-components/icons-ui" "^0.32.0" - "@spectrum-web-components/shared" "^0.32.0" - -"@spectrum-web-components/base@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/base/-/base-0.32.0.tgz#a9e10acb2e5c7dbd7bc38a4b5402991e8b49cea2" - integrity sha512-AkkWeRM5aAhXRmeAOIgSgLpPdQ2VjoGqNUmMFpmhRvRcrhnR0AqFcjmqNaEE6Zwkw7F2xyry3s3LC3yB+RWnaA== - dependencies: - lit "^2.5.0" - -"@spectrum-web-components/button@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/button/-/button-0.32.0.tgz#eb1f95daae50ccce5a1669289588788a16fae691" - integrity sha512-8lRqT8V4CU+MicJak2/frJZtZSbU6xFHxt7muK/mNv6dfQwuL2fUyadGowTLG6K/TyQi/faGiJZcc78jUspTsw== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/clear-button" "^0.32.0" - "@spectrum-web-components/close-button" "^0.32.0" - "@spectrum-web-components/icon" "^0.32.0" - "@spectrum-web-components/icons-ui" "^0.32.0" - "@spectrum-web-components/shared" "^0.32.0" - -"@spectrum-web-components/clear-button@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/clear-button/-/clear-button-0.32.0.tgz#6bcc0691be6f9d64359d678b009ac7ea31ae7cc4" - integrity sha512-OMnNfJN/V8fFXV0C1fAM0fHZwZQSC2BJbNLECBEUa7YxE8CjN7ENlgBWHk2aMGmpCTvCYXr7MS4yH3P834BzZA== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - -"@spectrum-web-components/close-button@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/close-button/-/close-button-0.32.0.tgz#536f558c0c827c344ccab519646c4868af93d9ec" - integrity sha512-8z7COXCj2+Bf1IpnNB8gojRWf6SJxXlK6d0IndVOO/xtkCOByqUXYPNwJ9s7dxrBZ9HHw0QNT758qkmpmn6icg== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/eslint-plugin@file:./linters/eslint": version "1.1.1" -"@spectrum-web-components/icon@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/icon/-/icon-0.32.0.tgz#6626c662393b3598ad58fb7ca729142f0442a909" - integrity sha512-ZyjVHy72xcE45QrfS+yRA44A6xK9vUCyUc2PqoPONtoJCv3O4aq9nqjwAWa4WLloN8G7yBoCthZHkg+oI5blgA== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/iconset" "^0.32.0" - -"@spectrum-web-components/icons-ui@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/icons-ui/-/icons-ui-0.32.0.tgz#adb828d65eaaa075a0abde8f746dcbc64c17b35f" - integrity sha512-AWPdnJg9QziqC+rViTrknS8r9BEv+6mf+xHB+nmmhKT/oXWKZJ03AltyGotyITOJk9w3UlLCHhAe7JL1xLV0rA== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/icon" "^0.32.0" - "@spectrum-web-components/iconset" "^0.32.0" - -"@spectrum-web-components/icons-workflow@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/icons-workflow/-/icons-workflow-0.32.0.tgz#8e9a2ef67736e57a74e7b47afb71fee504356902" - integrity sha512-aQTCQJDkeC6448MAgrL04GR60dU4y4Z8IQ6hy93HymL3WII7wVmOhNG8ibfznkv8se8Owt9Jb2EC2PvUM//SAg== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - "@spectrum-web-components/icon" "^0.32.0" - -"@spectrum-web-components/iconset@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/iconset/-/iconset-0.32.0.tgz#4a7679ba30609574b78504c1869e6a2abbbc58b2" - integrity sha512-pvauqxLX1ctj8iRRIMR/GnyUzmXsMdc4rL2/njyjwnTg9CTPbHo60m2Xa4l2EdW3R03/Ooz2vSs/e46bRZa6Xw== - dependencies: - "@spectrum-web-components/base" "^0.32.0" - -"@spectrum-web-components/shared@^0.32.0": - version "0.32.0" - resolved "https://registry.yarnpkg.com/@spectrum-web-components/shared/-/shared-0.32.0.tgz#e4e65c35e601320df65ded77404e84a193189e78" - integrity sha512-iPB/ZvYWyfV7ZpgyHwQ0VcB0ukt29iUploLZV9AgwF4YhLwg3GLkWJ2PABbLeQnfUy4uQvGnyUTc0HFW4R36HA== - dependencies: - "@lit-labs/observers" "^2.0.0" - "@spectrum-web-components/base" "^0.32.0" - focus-visible "^5.1.0" - "@storybook/csf-tools@^6.4.9": version "6.4.19" resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-6.4.19.tgz#28bdea11da17501a8bc4e761b821d7721880eaf6" From f9f05cadbfc52a893f7d78f813f42932317eab4c Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 09:05:56 +0100 Subject: [PATCH 14/25] refactor(calendar): changing Lit resource import source --- packages/calendar/src/Calendar.ts | 14 +++++++++----- packages/calendar/stories/calendar.stories.ts | 5 +---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 43e4bf67ecb..aa1feda4e1b 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -25,13 +25,17 @@ import { SpectrumElement, TemplateResult, } from '@spectrum-web-components/base'; +import { + property, + state, +} from '@spectrum-web-components/base/src/decorators.js'; +import { + classMap, + ifDefined, + when, +} from '@spectrum-web-components/base/src/directives.js'; import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; -import { property, state } from 'lit/decorators.js'; -import { classMap } from 'lit/directives/class-map.js'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { when } from 'lit/directives/when.js'; - import { CalendarWeekday, daysInWeek } from './types.js'; import styles from './calendar.css.js'; diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 65e562fd523..3db5d3918eb 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -10,13 +10,10 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ import { html, TemplateResult } from '@spectrum-web-components/base'; - -import { ifDefined } from 'lit/directives/if-defined.js'; +import { ifDefined } from '@spectrum-web-components/base/src/directives.js'; import { spreadProps } from '../../../test/lit-helpers.js'; -import '../sp-calendar.js'; - import '@spectrum-web-components/calendar/sp-calendar.js'; import '@spectrum-web-components/theme/sp-theme.js'; From a4e15e4bbed83aaaec002351737e0689526c4612 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 16:19:45 +0100 Subject: [PATCH 15/25] refactor: add comments and use correct formatters --- packages/calendar/README.md | 2 + packages/calendar/package.json | 3 +- packages/calendar/src/Calendar.ts | 74 +++++++++++++++++++++++++------ yarn.lock | 7 +++ 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/packages/calendar/README.md b/packages/calendar/README.md index daff7fb3a4e..4ac4a0f50d3 100644 --- a/packages/calendar/README.md +++ b/packages/calendar/README.md @@ -33,3 +33,5 @@ import { Calendar } from '@spectrum-web-components/calendar'; - Translate _"Previous"_ and _"Next"_ used in the `title` and `aria-label` of buttons displayed in the header of the calendar - Translate _"Today"_ and _"selected"_ used in the `title` of the day when it is today - Implement keyboard navigation +- Add support for other types of calendars - [React Calendar: International Calendars](https://react-spectrum.adobe.com/react-spectrum/Calendar.html#international-calendars) +- Include `aria-label` in calendar for accessibility - [React Calendar: Labeling](https://react-spectrum.adobe.com/react-spectrum/Calendar.html#labeling) diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 16593fc8076..28109498f25 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "description": "Web component implementation of a Spectrum design Calendar", + "description": "Web component implementation of a Spectrum Calendar", "license": "Apache-2.0", "repository": { "type": "git", @@ -62,6 +62,7 @@ ], "dependencies": { "@internationalized/date": "^3.2.0", + "@internationalized/number": "^3.2.1", "@spectrum-web-components/action-button": "^0.34.0", "@spectrum-web-components/base": "^0.34.0", "@spectrum-web-components/icons-workflow": "^0.34.0", diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index aa1feda4e1b..3ca100ecc4e 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -11,6 +11,7 @@ governing permissions and limitations under the License. */ import { CalendarDate, + DateFormatter, getLocalTimeZone, getWeeksInMonth, isSameDay, @@ -18,6 +19,7 @@ import { startOfWeek, today, } from '@internationalized/date'; +import { NumberFormatter } from '@internationalized/number'; import { CSSResultArray, html, @@ -37,6 +39,7 @@ import { import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; import { CalendarWeekday, daysInWeek } from './types.js'; + import styles from './calendar.css.js'; import '@spectrum-web-components/action-button/sp-action-button.js'; @@ -46,8 +49,8 @@ import '@spectrum-web-components/icons-workflow/icons/sp-icon-chevron-right.js'; /** * @element sp-calendar * - * @slot prev-icon - The icon used in the _"Previous Month"_ button - * @slot next-icon - The icon used in the _"Next Month"_ button + * @slot prev-icon - The icon used in the "Previous Month" button + * @slot next-icon - The icon used in the "Next Month" button * * @event change - Announces when a day is selected by emitting a `Date` object */ @@ -56,21 +59,36 @@ export class Calendar extends SpectrumElement { return [styles]; } - @property({ type: Boolean, reflect: true }) - padded = false; - - @property({ type: Boolean, reflect: true }) - disabled = false; - + /** + * Date used to display the calendar. If no date is given, the current month will be used + */ @property({ reflect: true, attribute: false }) selectedDate?: Date; + /** + * The minimum allowed date a user can select + */ @property({ reflect: true, attribute: false }) min?: Date; + /** + * The maximum allowed date a user can select + */ @property({ reflect: true, attribute: false }) max?: Date; + /** + * Indicates when the calendar should be disabled entirely + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Adds a padding around the calendar + */ + @property({ type: Boolean, reflect: true }) + padded = false; + @state() private _currentDate!: CalendarDate; @@ -279,7 +297,7 @@ export class Calendar extends SpectrumElement { const todayTitle = isToday ? 'Today, ' : ''; const selectedTitle = isToday ? ' selected' : ''; - const title: string = this._capitalFirstLetter( + const title = this._capitalFirstLetter( `${todayTitle}${currentDayTitle}${selectedTitle}` ); @@ -327,6 +345,9 @@ export class Calendar extends SpectrumElement { ); } + /** + * Returns the number of weeks according to the defined month and locale + */ private _getWeeksInCurrentMonth(): number { return getWeeksInMonth(this._currentDate, this._locale); } @@ -393,6 +414,12 @@ export class Calendar extends SpectrumElement { } } + /** + * Returns an array with all days of the week corresponding to the given index, starting with the first day of the + * week according to the locale + * + * @param weekIndex - The index of the week + */ private _getDatesInWeek(weekIndex: number): CalendarDate[] { const dates: CalendarDate[] = []; @@ -417,6 +444,11 @@ export class Calendar extends SpectrumElement { return dates; } + /** + * Converts a `Date` object to a `CalendarDate` + * + * @param date - `Date` object to be converted + */ private _toCalendarDate(date: Date): CalendarDate { return new CalendarDate( date.getFullYear(), @@ -434,20 +466,36 @@ export class Calendar extends SpectrumElement { return !isNaN(date.getTime()); } + /** + * Formats a `CalendarDate` object using the current locale and the provided date format options + * + * @param calendarDate - The `CalendarDate` object that will be used by the formatter + * @param options - All date format options that will be used by the formatter + */ private _formatDate( calendarDate: CalendarDate, options: Intl.DateTimeFormatOptions ): string { - return new Intl.DateTimeFormat(this._locale, options).format( + return new DateFormatter(this._locale, options).format( calendarDate.toDate(this._timeZone) ); } + /** + * Formats a number using the defined locale + * + * @param number - The number to format + */ private _formatNumber(number: number): string { - return new Intl.NumberFormat(this._locale).format(number); + return new NumberFormatter(this._locale).format(number); } - private _capitalFirstLetter(string: string): string { - return `${string.charAt(0).toUpperCase()}${string.substring(1)}`; + /** + * Converts the first letter to uppercase + * + * @param text - The text to be capitalized + */ + private _capitalFirstLetter(text: string): string { + return `${text.charAt(0).toUpperCase()}${text.substring(1)}`; } } diff --git a/yarn.lock b/yarn.lock index 538faa80e9e..03cd4d91c59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2513,6 +2513,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@internationalized/number@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.2.1.tgz#570e4010544a84a8225e65b34a689a36187caaa8" + integrity sha512-hK30sfBlmB1aIe3/OwAPg9Ey0DjjXvHEiGVhNaOiBJl31G0B6wMaX8BN3ibzdlpyRNE9p7X+3EBONmxtJO9Yfg== + dependencies: + "@swc/helpers" "^0.5.0" + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" From 1e8b31968b1dd7e19efe5975efbf75f15e2943ad Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 16:22:31 +0100 Subject: [PATCH 16/25] refactor: convert property `_locale` to a getter --- packages/calendar/src/Calendar.ts | 13 ++++--------- packages/calendar/stories/calendar.stories.ts | 10 +++++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 3ca100ecc4e..5e41658dfe3 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -99,25 +99,24 @@ export class Calendar extends SpectrumElement { private _maxDate!: CalendarDate; private _languageResolver = new LanguageResolutionController(this); - private _locale!: string; private _timeZone: string = getLocalTimeZone(); + private get _locale(): string { + return this._languageResolver.language; + } + public get today(): CalendarDate { return today(this._timeZone); } constructor() { super(); - - this._setLocale(); this._setInitialCalendarDate(); } protected override willUpdate( changedProperties: PropertyValueMap ): void { - this._setLocale(); - if (changedProperties.has('selectedDate')) { this._setCurrentCalendarDate(); } @@ -370,10 +369,6 @@ export class Calendar extends SpectrumElement { }); } - private _setLocale(): void { - this._locale = this._languageResolver.language; - } - private _setInitialCalendarDate(): void { this._currentDate = this.today; } diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 3db5d3918eb..ad3f258aa5b 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -59,7 +59,7 @@ export default { component: 'sp-calendar', argTypes: { - locale: { + lang: { options: locales, control: { type: 'select', @@ -88,7 +88,7 @@ export default { }, args: { - locale: defaultLocale, + lang: defaultLocale, }, parameters: { @@ -103,7 +103,7 @@ export default { }; interface StoryArgs { - locale?: string; + lang?: string; padded?: boolean; disabled?: boolean; @@ -121,11 +121,11 @@ const renderCalendar = ( args: StoryArgs = {} ): TemplateResult => { return html` - +

${title}

Locale: - ${args.locale} + ${args.lang}


From 004029d26da3d0439ab9c67144300672e3fe66ea Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 16:47:14 +0100 Subject: [PATCH 17/25] refactor: remove `_` from private properties and methods --- packages/calendar/src/Calendar.ts | 108 +++++++++--------- packages/calendar/stories/calendar.stories.ts | 12 +- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 5e41658dfe3..df2b51c8724 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -90,49 +90,49 @@ export class Calendar extends SpectrumElement { padded = false; @state() - private _currentDate!: CalendarDate; + private currentDate!: CalendarDate; @state() - private _minDate!: CalendarDate; + private minDate!: CalendarDate; @state() - private _maxDate!: CalendarDate; + private maxDate!: CalendarDate; - private _languageResolver = new LanguageResolutionController(this); - private _timeZone: string = getLocalTimeZone(); + private languageResolver = new LanguageResolutionController(this); + private timeZone: string = getLocalTimeZone(); - private get _locale(): string { - return this._languageResolver.language; + private get locale(): string { + return this.languageResolver.language; } public get today(): CalendarDate { - return today(this._timeZone); + return today(this.timeZone); } constructor() { super(); - this._setInitialCalendarDate(); + this.setInitialCalendarDate(); } protected override willUpdate( changedProperties: PropertyValueMap ): void { if (changedProperties.has('selectedDate')) { - this._setCurrentCalendarDate(); + this.setCurrentCalendarDate(); } if (changedProperties.has('min')) { - this._setMinCalendarDate(); + this.setMinCalendarDate(); } if (changedProperties.has('max')) { - this._setMaxCalendarDate(); + this.setMaxCalendarDate(); } } protected override render(): TemplateResult { return when( - this._currentDate, + this.currentDate, () => html` ${this.renderCalendarHeader()}${this.renderCalendarGrid()} ` @@ -141,7 +141,7 @@ export class Calendar extends SpectrumElement { public renderCalendarHeader(): TemplateResult { const monthAndYear = this._capitalFirstLetter( - this._formatDate(this._currentDate, { + this.formatDate(this.currentDate, { month: 'long', year: 'numeric', }) @@ -220,7 +220,7 @@ export class Calendar extends SpectrumElement { return html` - ${this._getWeekdays().map((weekday) => + ${this.getWeekdays().map((weekday) => this.renderWeekdayColumn(weekday) )} @@ -245,7 +245,7 @@ export class Calendar extends SpectrumElement { public renderCalendarTableBody(): TemplateResult { return html` - ${[...new Array(this._getWeeksInCurrentMonth()).keys()].map( + ${[...new Array(this.getWeeksInCurrentMonth()).keys()].map( (weekIndex) => this.renderCalendarTableRow(weekIndex) )} @@ -255,7 +255,7 @@ export class Calendar extends SpectrumElement { public renderCalendarTableRow(weekIndex: number): TemplateResult { return html` - ${this._getDatesInWeek(weekIndex).map((calendarDate) => + ${this.getDatesInWeek(weekIndex).map((calendarDate) => this.renderCalendarTableCell(calendarDate) )} @@ -263,19 +263,19 @@ export class Calendar extends SpectrumElement { } public renderCalendarTableCell(calendarDate: CalendarDate): TemplateResult { - const isOutsideMonth = calendarDate.month !== this._currentDate.month; + const isOutsideMonth = calendarDate.month !== this.currentDate.month; const isSelected = Boolean( this.selectedDate && - isSameDay(this._toCalendarDate(this.selectedDate), calendarDate) + isSameDay(this.toCalendarDate(this.selectedDate), calendarDate) ); const isToday = Boolean(isSameDay(calendarDate, this.today)); const isDisabled = Boolean( this.disabled || - (this._minDate && calendarDate.compare(this._minDate) < 0) || - (this._maxDate && calendarDate.compare(this._maxDate) > 0) + (this.minDate && calendarDate.compare(this.minDate) < 0) || + (this.maxDate && calendarDate.compare(this.maxDate) > 0) ); const dayClasses = { @@ -285,7 +285,7 @@ export class Calendar extends SpectrumElement { 'is-disabled': isDisabled, }; - const currentDayTitle = this._formatDate(calendarDate, { + const currentDayTitle = this.formatDate(calendarDate, { weekday: 'long', year: 'numeric', month: 'long', @@ -314,25 +314,25 @@ export class Calendar extends SpectrumElement { class="spectrum-Calendar-date ${classMap(dayClasses)}" @click=${() => this.handleDayClick(calendarDate)} > - ${this._formatNumber(calendarDate.day)} + ${this.formatNumber(calendarDate.day)} `; } public handlePreviousMonth(): void { - this._currentDate = startOfMonth(this._currentDate).subtract({ + this.currentDate = startOfMonth(this.currentDate).subtract({ months: 1, }); } public handleNextMonth(): void { - this._currentDate = startOfMonth(this._currentDate).add({ months: 1 }); + this.currentDate = startOfMonth(this.currentDate).add({ months: 1 }); } public handleDayClick(calendarDate: CalendarDate): void { - this.selectedDate = calendarDate.toDate(this._timeZone); - this._setCurrentCalendarDate(); + this.selectedDate = calendarDate.toDate(this.timeZone); + this.setCurrentCalendarDate(); this.dispatchEvent( new CustomEvent('change', { @@ -347,64 +347,64 @@ export class Calendar extends SpectrumElement { /** * Returns the number of weeks according to the defined month and locale */ - private _getWeeksInCurrentMonth(): number { - return getWeeksInMonth(this._currentDate, this._locale); + private getWeeksInCurrentMonth(): number { + return getWeeksInMonth(this.currentDate, this.locale); } /** * Returns data for the days of the week, starting with the first day of the week according to the defined locale * (Sunday, Monday, etc.) */ - private _getWeekdays(): CalendarWeekday[] { + private getWeekdays(): CalendarWeekday[] { return [...new Array(daysInWeek).keys()].map((dayIndex) => { - const weekStart = startOfWeek(this._currentDate, this._locale); + const weekStart = startOfWeek(this.currentDate, this.locale); const date = weekStart.add({ days: dayIndex }); return { - narrow: this._formatDate(date, { weekday: 'narrow' }), + narrow: this.formatDate(date, { weekday: 'narrow' }), long: this._capitalFirstLetter( - this._formatDate(date, { weekday: 'long' }) + this.formatDate(date, { weekday: 'long' }) ), }; }); } - private _setInitialCalendarDate(): void { - this._currentDate = this.today; + private setInitialCalendarDate(): void { + this.currentDate = this.today; } - private _setCurrentCalendarDate(): void { + private setCurrentCalendarDate(): void { if (this.selectedDate) { this.selectedDate = new Date(this.selectedDate); - if (!this._isValidDate(this.selectedDate)) { + if (!this.isValidDate(this.selectedDate)) { this.selectedDate = undefined; } else { - this._currentDate = this._toCalendarDate(this.selectedDate); + this.currentDate = this.toCalendarDate(this.selectedDate); } } } - private _setMinCalendarDate(): void { + private setMinCalendarDate(): void { if (this.min) { this.min = new Date(this.min); - if (!this._isValidDate(this.min)) { + if (!this.isValidDate(this.min)) { this.min = undefined; } else { - this._minDate = this._toCalendarDate(this.min); + this.minDate = this.toCalendarDate(this.min); } } } - private _setMaxCalendarDate(): void { + private setMaxCalendarDate(): void { if (this.max) { this.max = new Date(this.max); - if (!this._isValidDate(this.max)) { + if (!this.isValidDate(this.max)) { this.max = undefined; } else { - this._maxDate = this._toCalendarDate(this.max); + this.maxDate = this.toCalendarDate(this.max); } } } @@ -415,12 +415,12 @@ export class Calendar extends SpectrumElement { * * @param weekIndex - The index of the week */ - private _getDatesInWeek(weekIndex: number): CalendarDate[] { + private getDatesInWeek(weekIndex: number): CalendarDate[] { const dates: CalendarDate[] = []; let date = startOfWeek( - startOfMonth(this._currentDate).add({ weeks: weekIndex }), - this._locale + startOfMonth(this.currentDate).add({ weeks: weekIndex }), + this.locale ); while (dates.length < daysInWeek) { @@ -444,7 +444,7 @@ export class Calendar extends SpectrumElement { * * @param date - `Date` object to be converted */ - private _toCalendarDate(date: Date): CalendarDate { + private toCalendarDate(date: Date): CalendarDate { return new CalendarDate( date.getFullYear(), date.getMonth() + 1, // The month to create a new `CalendarDate` cannot be a zero-based index, unlike `Date` @@ -457,7 +457,7 @@ export class Calendar extends SpectrumElement { * * @param date - `Date` object to validate */ - private _isValidDate(date: Date): boolean { + private isValidDate(date: Date): boolean { return !isNaN(date.getTime()); } @@ -467,12 +467,12 @@ export class Calendar extends SpectrumElement { * @param calendarDate - The `CalendarDate` object that will be used by the formatter * @param options - All date format options that will be used by the formatter */ - private _formatDate( + private formatDate( calendarDate: CalendarDate, options: Intl.DateTimeFormatOptions ): string { - return new DateFormatter(this._locale, options).format( - calendarDate.toDate(this._timeZone) + return new DateFormatter(this.locale, options).format( + calendarDate.toDate(this.timeZone) ); } @@ -481,8 +481,8 @@ export class Calendar extends SpectrumElement { * * @param number - The number to format */ - private _formatNumber(number: number): string { - return new NumberFormatter(this._locale).format(number); + private formatNumber(number: number): string { + return new NumberFormatter(this.locale).format(number); } /** diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index ad3f258aa5b..673c3125b6a 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -72,12 +72,12 @@ export default { }, // Don't render private properties and getters in the Storybook UI - _languageResolver: { ...hiddenProperty }, - _locale: { ...hiddenProperty }, - _timeZone: { ...hiddenProperty }, - _currentDate: { ...hiddenProperty }, - _minDate: { ...hiddenProperty }, - _maxDate: { ...hiddenProperty }, + languageResolver: { ...hiddenProperty }, + locale: { ...hiddenProperty }, + timeZone: { ...hiddenProperty }, + currentDate: { ...hiddenProperty }, + minDate: { ...hiddenProperty }, + maxDate: { ...hiddenProperty }, today: { ...hiddenProperty }, // Inherited From 3208d992629acd74dafa0109b3c11a9ba9856d0a Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 16:58:43 +0100 Subject: [PATCH 18/25] refactor: remove unnecessary method --- packages/calendar/README.md | 7 ++--- packages/calendar/src/Calendar.ts | 44 +++++++++++-------------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/packages/calendar/README.md b/packages/calendar/README.md index 4ac4a0f50d3..6e64f76f36d 100644 --- a/packages/calendar/README.md +++ b/packages/calendar/README.md @@ -29,9 +29,10 @@ import { Calendar } from '@spectrum-web-components/calendar'; ## To-do list -- Attribute `role="heading"` removed from `.spectrum-Calendar-title`, due to error _'The "heading" role requires the attribute "aria-level"'_ -- Translate _"Previous"_ and _"Next"_ used in the `title` and `aria-label` of buttons displayed in the header of the calendar -- Translate _"Today"_ and _"selected"_ used in the `title` of the day when it is today +- Attribute 'role="heading"' removed, due to error 'The "heading" role requires the attribute "aria-level"' +- Translate the "Previous" text used in the "title" and "aria-label" of the button displayed in the header of the calendar +- Translate the "Next" text used in the "title" and "aria-label" of the button displayed in the header of the calendar +- The title must include "Today," and " selected" translated to the current language - Implement keyboard navigation - Add support for other types of calendars - [React Calendar: International Calendars](https://react-spectrum.adobe.com/react-spectrum/Calendar.html#international-calendars) - Include `aria-label` in calendar for accessibility - [React Calendar: Labeling](https://react-spectrum.adobe.com/react-spectrum/Calendar.html#labeling) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index df2b51c8724..4c556d87b47 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -140,12 +140,10 @@ export class Calendar extends SpectrumElement { } public renderCalendarHeader(): TemplateResult { - const monthAndYear = this._capitalFirstLetter( - this.formatDate(this.currentDate, { - month: 'long', - year: 'numeric', - }) - ); + const monthAndYear = this.formatDate(this.currentDate, { + month: 'long', + year: 'numeric', + }); return html`
@@ -161,7 +159,10 @@ export class Calendar extends SpectrumElement { ${monthAndYear}
- + - + Date: Wed, 19 Jul 2023 17:07:37 +0100 Subject: [PATCH 19/25] refactor: remove unnecessary template checking --- packages/calendar/src/Calendar.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 4c556d87b47..10eb84b8335 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -34,7 +34,6 @@ import { import { classMap, ifDefined, - when, } from '@spectrum-web-components/base/src/directives.js'; import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; @@ -131,12 +130,9 @@ export class Calendar extends SpectrumElement { } protected override render(): TemplateResult { - return when( - this.currentDate, - () => html` - ${this.renderCalendarHeader()}${this.renderCalendarGrid()} - ` - ); + return html` + ${this.renderCalendarHeader()}${this.renderCalendarGrid()} + `; } public renderCalendarHeader(): TemplateResult { From fbd2d293a2fc12f47adcdaaea632ec04754c7ae9 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 18:47:24 +0100 Subject: [PATCH 20/25] refactor: add new private properties --- packages/calendar/src/Calendar.ts | 31 +++++++++++++------ packages/calendar/stories/calendar.stories.ts | 8 +++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 10eb84b8335..a5d74a7bffd 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -97,6 +97,12 @@ export class Calendar extends SpectrumElement { @state() private maxDate!: CalendarDate; + @state() + private weeksInCurrentMonth: number[] = []; + + @state() + private weekdays: CalendarWeekday[] = []; + private languageResolver = new LanguageResolutionController(this); private timeZone: string = getLocalTimeZone(); @@ -127,6 +133,9 @@ export class Calendar extends SpectrumElement { if (changedProperties.has('max')) { this.setMaxCalendarDate(); } + + this.setWeeksInCurrentMonth(); + this.setWeekdays(); } protected override render(): TemplateResult { @@ -220,7 +229,7 @@ export class Calendar extends SpectrumElement { return html` - ${this.getWeekdays().map((weekday) => + ${this.weekdays.map((weekday) => this.renderWeekdayColumn(weekday) )} @@ -245,8 +254,8 @@ export class Calendar extends SpectrumElement { public renderCalendarTableBody(): TemplateResult { return html` - ${[...new Array(this.getWeeksInCurrentMonth()).keys()].map( - (weekIndex) => this.renderCalendarTableRow(weekIndex) + ${this.weeksInCurrentMonth.map((weekIndex) => + this.renderCalendarTableRow(weekIndex) )} `; @@ -338,18 +347,20 @@ export class Calendar extends SpectrumElement { } /** - * Returns the number of weeks according to the defined month and locale + * Defines the array with the indexes (starting at zero) of the weeks of the current month */ - private getWeeksInCurrentMonth(): number { - return getWeeksInMonth(this.currentDate, this.locale); + private setWeeksInCurrentMonth(): void { + const numberOfWeeks = getWeeksInMonth(this.currentDate, this.locale); + + this.weeksInCurrentMonth = [...new Array(numberOfWeeks).keys()]; } /** - * Returns data for the days of the week, starting with the first day of the week according to the defined locale - * (Sunday, Monday, etc.) + * Defines the array with data for the days of the week, starting on the first day of the week according to the + * defined location (Sunday, Monday, etc.) */ - private getWeekdays(): CalendarWeekday[] { - return [...new Array(daysInWeek).keys()].map((dayIndex) => { + private setWeekdays(): void { + this.weekdays = [...new Array(daysInWeek).keys()].map((dayIndex) => { const weekStart = startOfWeek(this.currentDate, this.locale); const date = weekStart.add({ days: dayIndex }); diff --git a/packages/calendar/stories/calendar.stories.ts b/packages/calendar/stories/calendar.stories.ts index 673c3125b6a..73c2512e93e 100644 --- a/packages/calendar/stories/calendar.stories.ts +++ b/packages/calendar/stories/calendar.stories.ts @@ -72,12 +72,14 @@ export default { }, // Don't render private properties and getters in the Storybook UI - languageResolver: { ...hiddenProperty }, - locale: { ...hiddenProperty }, - timeZone: { ...hiddenProperty }, currentDate: { ...hiddenProperty }, minDate: { ...hiddenProperty }, maxDate: { ...hiddenProperty }, + weeksInCurrentMonth: { ...hiddenProperty }, + weekdays: { ...hiddenProperty }, + languageResolver: { ...hiddenProperty }, + timeZone: { ...hiddenProperty }, + locale: { ...hiddenProperty }, today: { ...hiddenProperty }, // Inherited From b18c3f1be8f5fa3ca292cc197f9f57fa52d78a44 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 19:18:00 +0100 Subject: [PATCH 21/25] refactor: code improvements, new comments --- packages/calendar/src/Calendar.ts | 68 ++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index a5d74a7bffd..90bb78dd2e1 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -279,7 +279,7 @@ export class Calendar extends SpectrumElement { isSameDay(this.toCalendarDate(this.selectedDate), calendarDate) ); - const isToday = Boolean(isSameDay(calendarDate, this.today)); + const isToday = isSameDay(calendarDate, this.today); const isDisabled = Boolean( this.disabled || @@ -339,7 +339,6 @@ export class Calendar extends SpectrumElement { this.dispatchEvent( new CustomEvent('change', { bubbles: true, - cancelable: true, composed: true, detail: this.selectedDate, }) @@ -371,44 +370,67 @@ export class Calendar extends SpectrumElement { }); } + /** + * Defines the initial date that will be used to render the calendar, if no specific date is provided + */ private setInitialCalendarDate(): void { this.currentDate = this.today; } + /** + * If a date is received by the component via property, it uses that date as the current date to render the calendar + */ private setCurrentCalendarDate(): void { - if (this.selectedDate) { - this.selectedDate = new Date(this.selectedDate); + if (!this.selectedDate) { + return; + } - if (!this.isValidDate(this.selectedDate)) { - this.selectedDate = undefined; - } else { - this.currentDate = this.toCalendarDate(this.selectedDate); - } + this.selectedDate = new Date(this.selectedDate); + + if (!this.isValidDate(this.selectedDate)) { + this.selectedDate = undefined; + return; } + + this.currentDate = this.toCalendarDate(this.selectedDate); } + /** + * Sets the minimum allowed date a user can select by converting a `Date` object to `CalendarDate`, which is the + * type of object used internally by the class + */ private setMinCalendarDate(): void { - if (this.min) { - this.min = new Date(this.min); + if (!this.min) { + return; + } - if (!this.isValidDate(this.min)) { - this.min = undefined; - } else { - this.minDate = this.toCalendarDate(this.min); - } + this.min = new Date(this.min); + + if (!this.isValidDate(this.min)) { + this.min = undefined; + return; } + + this.minDate = this.toCalendarDate(this.min); } + /** + * Sets the maximum allowed date a user can select by converting a `Date` object to `CalendarDate`, which is the + * type of object used internally by the class + */ private setMaxCalendarDate(): void { - if (this.max) { - this.max = new Date(this.max); + if (!this.max) { + return; + } - if (!this.isValidDate(this.max)) { - this.max = undefined; - } else { - this.maxDate = this.toCalendarDate(this.max); - } + this.max = new Date(this.max); + + if (!this.isValidDate(this.max)) { + this.max = undefined; + return; } + + this.maxDate = this.toCalendarDate(this.max); } /** From 185f79fd05f1b0e90806c4c5773fc6a8d8865af3 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Wed, 19 Jul 2023 19:33:56 +0100 Subject: [PATCH 22/25] refactor: remove reflect from properties they don't need --- packages/calendar/src/Calendar.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 90bb78dd2e1..1ad12a77c27 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -61,19 +61,19 @@ export class Calendar extends SpectrumElement { /** * Date used to display the calendar. If no date is given, the current month will be used */ - @property({ reflect: true, attribute: false }) + @property({ attribute: false }) selectedDate?: Date; /** * The minimum allowed date a user can select */ - @property({ reflect: true, attribute: false }) + @property({ attribute: false }) min?: Date; /** * The maximum allowed date a user can select */ - @property({ reflect: true, attribute: false }) + @property({ attribute: false }) max?: Date; /** From dec3be596cc1a0f7182438b8f5e0c19155f535b3 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Mon, 24 Jul 2023 16:58:00 +0100 Subject: [PATCH 23/25] fix: add new package to tsconfig.json --- tools/bundle/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/bundle/tsconfig.json b/tools/bundle/tsconfig.json index 2314367fdc8..bc2b6774fe0 100644 --- a/tools/bundle/tsconfig.json +++ b/tools/bundle/tsconfig.json @@ -18,6 +18,7 @@ { "path": "../../packages/banner" }, { "path": "../../packages/button" }, { "path": "../../packages/button-group" }, + { "path": "../../packages/calendar" }, { "path": "../../packages/card" }, { "path": "../../packages/checkbox" }, { "path": "../../packages/coachmark" }, From d4f08efe6b90d122c2a174e95146235d172776c9 Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Mon, 31 Jul 2023 17:23:15 +0100 Subject: [PATCH 24/25] refactor: use same version of `@internationalized/number` used by other components --- packages/calendar/package.json | 2 +- yarn.lock | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 28109498f25..0a8ff0a1500 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -62,7 +62,7 @@ ], "dependencies": { "@internationalized/date": "^3.2.0", - "@internationalized/number": "^3.2.1", + "@internationalized/number": "^3.1.0", "@spectrum-web-components/action-button": "^0.34.0", "@spectrum-web-components/base": "^0.34.0", "@spectrum-web-components/icons-workflow": "^0.34.0", diff --git a/yarn.lock b/yarn.lock index 03cd4d91c59..538faa80e9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2513,13 +2513,6 @@ dependencies: "@swc/helpers" "^0.4.14" -"@internationalized/number@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.2.1.tgz#570e4010544a84a8225e65b34a689a36187caaa8" - integrity sha512-hK30sfBlmB1aIe3/OwAPg9Ey0DjjXvHEiGVhNaOiBJl31G0B6wMaX8BN3ibzdlpyRNE9p7X+3EBONmxtJO9Yfg== - dependencies: - "@swc/helpers" "^0.5.0" - "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" From c235d4f7536159195ff1565f27b92c49402f3d5c Mon Sep 17 00:00:00 2001 From: Paulo de Tarso Furtado Machado Date: Mon, 31 Jul 2023 17:25:05 +0100 Subject: [PATCH 25/25] refactor(calendar): improvements and new TODOs --- packages/calendar/README.md | 2 ++ packages/calendar/src/Calendar.ts | 13 +++++++++---- tools/base/src/directives.ts | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/calendar/README.md b/packages/calendar/README.md index 6e64f76f36d..36045970735 100644 --- a/packages/calendar/README.md +++ b/packages/calendar/README.md @@ -29,6 +29,8 @@ import { Calendar } from '@spectrum-web-components/calendar'; ## To-do list +- Implement a cache mechanism to store the value of `today` and use this value to initialise `currentDate` +- Include a condition to run the `setWeekdays()` method only when really needed - Attribute 'role="heading"' removed, due to error 'The "heading" role requires the attribute "aria-level"' - Translate the "Previous" text used in the "title" and "aria-label" of the button displayed in the header of the calendar - Translate the "Next" text used in the "title" and "aria-label" of the button displayed in the header of the calendar diff --git a/packages/calendar/src/Calendar.ts b/packages/calendar/src/Calendar.ts index 1ad12a77c27..53da531a31a 100644 --- a/packages/calendar/src/Calendar.ts +++ b/packages/calendar/src/Calendar.ts @@ -32,6 +32,7 @@ import { state, } from '@spectrum-web-components/base/src/decorators.js'; import { + ClassInfo, classMap, ifDefined, } from '@spectrum-web-components/base/src/directives.js'; @@ -110,6 +111,7 @@ export class Calendar extends SpectrumElement { return this.languageResolver.language; } + // TODO: Implement a cache mechanism to store the value of `today` and use this value to initialise `currentDate` public get today(): CalendarDate { return today(this.timeZone); } @@ -135,6 +137,8 @@ export class Calendar extends SpectrumElement { } this.setWeeksInCurrentMonth(); + + // TODO: Include a condition to run the `setWeekdays()` method only when really needed this.setWeekdays(); } @@ -173,7 +177,7 @@ export class Calendar extends SpectrumElement { size="s" aria-label="Previous" title="Previous" - class="spectrum-ActionButton spectrum-Calendar-prevMonth" + class="spectrum-Calendar-prevMonth" ?disabled=${this.disabled} @click=${this.handlePreviousMonth} > @@ -193,7 +197,7 @@ export class Calendar extends SpectrumElement { size="s" aria-label="Next" title="Next" - class="spectrum-ActionButton spectrum-Calendar-nextMonth" + class="spectrum-Calendar-nextMonth" ?disabled=${this.disabled} @click=${this.handleNextMonth} > @@ -287,7 +291,8 @@ export class Calendar extends SpectrumElement { (this.maxDate && calendarDate.compare(this.maxDate) > 0) ); - const dayClasses = { + const dayClasses: ClassInfo = { + 'spectrum-Calendar-date': true, 'is-outsideMonth': isOutsideMonth, 'is-selected': isSelected, 'is-today': isToday, @@ -313,7 +318,7 @@ export class Calendar extends SpectrumElement { > this.handleDayClick(calendarDate)} > ${this.formatNumber(calendarDate.day)} diff --git a/tools/base/src/directives.ts b/tools/base/src/directives.ts index 12b05449945..16780ee6e9b 100644 --- a/tools/base/src/directives.ts +++ b/tools/base/src/directives.ts @@ -13,6 +13,7 @@ governing permissions and limitations under the License. export { ifDefined } from 'lit/directives/if-defined.js'; export { repeat } from 'lit/directives/repeat.js'; export { classMap } from 'lit/directives/class-map.js'; +export type { ClassInfo } from 'lit/directives/class-map.js'; export { styleMap } from 'lit/directives/style-map.js'; export type { StyleInfo } from 'lit/directives/style-map.js'; export { until } from 'lit/directives/until.js';