From a0b4feb08b6e2413197e813ac993f41772d9e4a8 Mon Sep 17 00:00:00 2001 From: Nethmi Rodrigo <34070216+NethmiRodrigo@users.noreply.github.com> Date: Fri, 5 Jul 2024 20:20:58 +0530 Subject: [PATCH] (feat): Enhancements to the OpenmrsDatePicker (#1062) Co-authored-by: Ian --- packages/framework/esm-framework/docs/API.md | 4 +- .../docs/interfaces/OpenmrsDatePickerProps.md | 48 ++++++++--- .../esm-styleguide/src/_overrides.scss | 2 +- .../src/datepicker/datepicker.module.scss | 48 ++++++++++- .../esm-styleguide/src/datepicker/index.tsx | 81 ++++++++++--------- .../esm-styleguide/src/icons/icons.tsx | 4 +- 6 files changed, 131 insertions(+), 56 deletions(-) diff --git a/packages/framework/esm-framework/docs/API.md b/packages/framework/esm-framework/docs/API.md index b297e8c6a..9ecbd1d35 100644 --- a/packages/framework/esm-framework/docs/API.md +++ b/packages/framework/esm-framework/docs/API.md @@ -529,7 +529,7 @@ A type for any of the acceptable date formats #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:48](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L48) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:56](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L56) ___ @@ -1571,7 +1571,7 @@ A date picker component to select a single date. Based on React Aria, but styled #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:260](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L260) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:247](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L247) ___ diff --git a/packages/framework/esm-framework/docs/interfaces/OpenmrsDatePickerProps.md b/packages/framework/esm-framework/docs/interfaces/OpenmrsDatePickerProps.md index 7de35bf49..5e1e3987e 100644 --- a/packages/framework/esm-framework/docs/interfaces/OpenmrsDatePickerProps.md +++ b/packages/framework/esm-framework/docs/interfaces/OpenmrsDatePickerProps.md @@ -27,6 +27,8 @@ Properties for the OpenmrsDatePicker - [hideTimeZone](OpenmrsDatePickerProps.md#hidetimezone) - [hourCycle](OpenmrsDatePickerProps.md#hourcycle) - [id](OpenmrsDatePickerProps.md#id) +- [invalid](OpenmrsDatePickerProps.md#invalid) +- [invalidText](OpenmrsDatePickerProps.md#invalidtext) - [isDisabled](OpenmrsDatePickerProps.md#isdisabled) - [isInvalid](OpenmrsDatePickerProps.md#isinvalid) - [isOpen](OpenmrsDatePickerProps.md#isopen) @@ -169,7 +171,7 @@ Any CSS classes to add to the outer div of the date picker #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:68](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L68) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:74](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L74) ___ @@ -197,7 +199,7 @@ The default value (uncontrolled) #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:72](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L72) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:76](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L76) ___ @@ -267,6 +269,30 @@ node_modules/@react-types/shared/src/dom.d.ts:62 ___ +### invalid + +• `Optional` **invalid**: `boolean` + +Whether the input value is invalid. + +#### Defined in + +[packages/framework/esm-styleguide/src/datepicker/index.tsx:78](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L78) + +___ + +### invalidText + +• `Optional` **invalidText**: `string` + +Text to show if the input is invalid e.g. an error message + +#### Defined in + +[packages/framework/esm-styleguide/src/datepicker/index.tsx:80](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L80) + +___ + ### isDisabled • `Optional` **isDisabled**: `boolean` @@ -357,7 +383,7 @@ The label for this DatePicker element #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:77](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L77) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:85](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L85) ___ @@ -365,11 +391,11 @@ ___ • `Optional` **labelText**: `string` \| `ReactElement`<`any`, `string` \| `JSXElementConstructor`<`any`\>\> -The label for this DatePicker element +The label for this DatePicker element. #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:81](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L81) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:87](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L87) ___ @@ -381,7 +407,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:85](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L85) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:89](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L89) ___ @@ -393,7 +419,7 @@ The latest date it is possible to select #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:89](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L89) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:91](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L91) ___ @@ -499,7 +525,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:101](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L101) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:97](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L97) ___ @@ -542,11 +568,11 @@ ___ • `Optional` **size**: ``"sm"`` \| ``"md"`` \| ``"lg"`` -Specifies the size of the input. Currently supports either `sm`, `md`, or `lg` as an option. +Specifies the size of the input. Currently supports either `sm`, `md`, or `lg` as an option #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:97](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L97) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:95](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L95) ___ @@ -611,7 +637,7 @@ The value (controlled) #### Defined in -[packages/framework/esm-styleguide/src/datepicker/index.tsx:105](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L105) +[packages/framework/esm-styleguide/src/datepicker/index.tsx:99](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/datepicker/index.tsx#L99) ## Methods diff --git a/packages/framework/esm-styleguide/src/_overrides.scss b/packages/framework/esm-styleguide/src/_overrides.scss index a5c0be1ac..99083c7f2 100644 --- a/packages/framework/esm-styleguide/src/_overrides.scss +++ b/packages/framework/esm-styleguide/src/_overrides.scss @@ -685,6 +685,6 @@ html[dir='rtl'] { color: #0f62fe; } -svg.omrs-icon { +.omrs-icon { fill: var(--omrs-icon-fill, 'currentColor'); } diff --git a/packages/framework/esm-styleguide/src/datepicker/datepicker.module.scss b/packages/framework/esm-styleguide/src/datepicker/datepicker.module.scss index b8692e738..aa7705006 100644 --- a/packages/framework/esm-styleguide/src/datepicker/datepicker.module.scss +++ b/packages/framework/esm-styleguide/src/datepicker/datepicker.module.scss @@ -6,6 +6,7 @@ @use '@carbon/styles/scss/utilities/box-shadow'; @use '@carbon/styles/scss/utilities/component-reset'; @use '@carbon/styles/scss/utilities/focus-outline' as focus; +@use '@openmrs/esm-styleguide/src/vars' as *; .calendarGrid { width: 17rem; @@ -34,10 +35,15 @@ outline: unset; } - &:hover:not(:has([aria-disabled='true'])) { + &:hover:not(:has([aria-disabled], [data-selected])) { background-color: theme.$layer-hover; } + &:has([data-selected]) { + background-color: $color-blue-60-2; + color: $ui-background; + } + [aria-disabled] { color: theme.$text-disabled; cursor: default; @@ -68,6 +74,10 @@ } } +[data-invalid] > .flatButton > svg { + --omrs-icon-fill: #{theme.$support-error}; +} + .flatButtonMd { height: spacing.$spacing-08; width: spacing.$spacing-08; @@ -291,3 +301,39 @@ } } } + +.invalidText { + color: theme.$text-error !important; + font-size: 0.75rem; + font-weight: 400 !important; + margin: spacing.$spacing-02 0 0; + overflow: hidden; +} + +.today:not([data-selected]) { + position: relative; + color: $color-blue-60-2; + font-weight: 600; + font-size: var(--cds-body-compact-01-font-size, 0.875rem); + line-height: var(--cds-body-compact-01-line-height, 1.28572); + letter-spacing: var(--cds-body-compact-01-letter-spacing, 0.16px); + display: flex; + align-items: center; + justify-content: center; + block-size: 2.5rem; + cursor: pointer; + inline-size: 2.5rem; + + &::after { + position: absolute; + display: block; + background-color: var(--cds-link-primary, #0f62fe); + block-size: 0.25rem; + content: ''; + inline-size: 0.25rem; + inset-block-end: 0.4375rem; + inset-inline-start: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + } +} diff --git a/packages/framework/esm-styleguide/src/datepicker/index.tsx b/packages/framework/esm-styleguide/src/datepicker/index.tsx index b0cb6d1a9..aa348ce6e 100644 --- a/packages/framework/esm-styleguide/src/datepicker/index.tsx +++ b/packages/framework/esm-styleguide/src/datepicker/index.tsx @@ -11,7 +11,14 @@ import React, { useRef, } from 'react'; import classNames, { type Argument } from 'classnames'; -import { createCalendar, CalendarDate, CalendarDateTime, ZonedDateTime } from '@internationalized/date'; +import { + createCalendar, + CalendarDate, + CalendarDateTime, + ZonedDateTime, + today, + getLocalTimeZone, +} from '@internationalized/date'; import { I18nProvider, type DateValue, useLocale, useDateField } from 'react-aria'; import { useDateFieldState } from 'react-stately'; import { @@ -38,6 +45,7 @@ import { InputContext, Provider, GroupContext, + FieldError, } from 'react-aria-components'; import dayjs, { type Dayjs } from 'dayjs'; import { formatDate, getDefaultCalendar, getLocale } from '@openmrs/esm-utils'; @@ -62,46 +70,32 @@ export type DateInputValue = export interface OpenmrsDatePickerProps // omits here for features we have custom implementations of extends Omit, 'className' | 'defaultValue' | 'value'> { - /** - * Any CSS classes to add to the outer div of the date picker - */ + /** Any CSS classes to add to the outer div of the date picker */ className?: Argument; - /** - * The default value (uncontrolled) - */ + /** The default value (uncontrolled) */ defaultValue?: DateInputValue; + /** Whether the input value is invalid. */ + invalid?: boolean; + /** Text to show if the input is invalid e.g. an error message */ + invalidText?: string; /** * The label for this DatePicker element * @deprecated Use labelText instead */ label?: string | ReactElement; - /** - * The label for this DatePicker element - */ + /** The label for this DatePicker element. */ labelText?: string | ReactElement; - /** - * 'true' to use the light version. - */ + /** 'true' to use the light version. */ light?: boolean; - /** - * The latest date it is possible to select - */ + /** The latest date it is possible to select */ maxDate?: DateInputValue; - /** - * The earliest date it is possible to select - */ + /** The earliest date it is possible to select */ minDate?: DateInputValue; - /** - * Specifies the size of the input. Currently supports either `sm`, `md`, or `lg` as an option. - */ + /** Specifies the size of the input. Currently supports either `sm`, `md`, or `lg` as an option */ size?: 'sm' | 'md' | 'lg'; - /** - * 'true' to use the short version. - */ + /** 'true' to use the short version. */ short?: boolean; - /** - * The value (controlled) - */ + /** The value (controlled) */ value?: DateInputValue; } @@ -196,13 +190,10 @@ const MonthYear = forwardRef(function DatePickerIcon(props, ref) { +const DatePickerIcon = forwardRef(function DatePickerIcon(props, ref) { const state = useContext(DatePickerStateContext); - return state.isInvalid ? ( - - ) : ( - - ); + + return state.isInvalid ? : ; }); // The main reason for this component is to allow us to click inside the date field and trigger the popover @@ -247,11 +238,7 @@ function DatePickerLabel({ labelText }: Pick{labelText}; - } - - return cloneElement(labelText, { className: classNames(labelText.props?.className, 'cds--label') }); + return ; } /** @@ -262,6 +249,9 @@ export const OpenmrsDatePicker = forwardRef dateToInternationalizedDate(rawValue), [rawValue]); const maxDate = useMemo(() => dateToInternationalizedDate(rawMaxDate), [rawMaxDate]); const minDate = useMemo(() => dateToInternationalizedDate(rawMinDate), [rawMinDate]); + const isInvalid = useMemo(() => invalid ?? isInvalidRaw, [invalid, isInvalidRaw]); const locale = getLocale(); + const today_ = today(getLocalTimeZone()); const localeWithCalendar = useMemo(() => { const calendar = getDefaultCalendar(locale); @@ -298,6 +290,7 @@ export const OpenmrsDatePicker = forwardRef + {isInvalid && invalidText && {invalidText}} @@ -338,7 +332,14 @@ export const OpenmrsDatePicker = forwardRef - {(date) => } + {(date) => ( + + )} diff --git a/packages/framework/esm-styleguide/src/icons/icons.tsx b/packages/framework/esm-styleguide/src/icons/icons.tsx index d44948307..9853c2e63 100644 --- a/packages/framework/esm-styleguide/src/icons/icons.tsx +++ b/packages/framework/esm-styleguide/src/icons/icons.tsx @@ -601,7 +601,9 @@ export const Icon = memo( useEffect(() => { if (iconRef.current) { - iconRef.current.style.setProperty('--omrs-icon-fill', fill); + if (fill !== 'currentColor') { + iconRef.current.style.setProperty('--omrs-icon-fill', fill); + } } }, []);