diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0911e3c41..087242cd678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Added a fully black (no matter the theme) color SASS variable `$euiColorInk` ([2060](https://github.com/elastic/eui/pull/2060)) - Added `autoFocus` prop to `EuiTabbedContent` ([2062](https://github.com/elastic/eui/pull/2062)) - Changed `popout` glyph in `EuiIcon` to look more like external link ([2064](https://github.com/elastic/eui/pull/2064)) +- Tweaked `SuperDatePicker` to make the start/end date selection more obvious ([#2049](https://github.com/elastic/eui/pull/2049)) +- Added `toSentenceCase` string service ([#2049](https://github.com/elastic/eui/pull/2049)) **Bug fixes** diff --git a/src/components/date_picker/super_date_picker/date_modes.js b/src/components/date_picker/super_date_picker/date_modes.js index 5f0733024b8..16f9924bf0a 100644 --- a/src/components/date_picker/super_date_picker/date_modes.js +++ b/src/components/date_picker/super_date_picker/date_modes.js @@ -19,7 +19,7 @@ export function getDateMode(value) { return DATE_MODES.RELATIVE; } - return DATE_MODES.absolute; + return DATE_MODES.ABSOLUTE; } export function toAbsoluteString(value, roundUp) { diff --git a/src/components/date_picker/super_date_picker/date_popover/_date_popover_button.scss b/src/components/date_picker/super_date_picker/date_popover/_date_popover_button.scss index b779c68eccf..88046e593fb 100644 --- a/src/components/date_picker/super_date_picker/date_popover/_date_popover_button.scss +++ b/src/components/date_picker/super_date_picker/date_popover/_date_popover_button.scss @@ -4,26 +4,37 @@ .euiDatePopoverButton { @include euiSuperDatePickerText; + background-size: 100%; // For the bottom "border" via background-image - $backgroundColor: tintOrShade($euiColorSuccess, 90%, 70%); - $textColor: makeHighContrastColor($euiColorSuccess, $backgroundColor); - - &-isSelected, - &-needsUpdating, - &:hover, - &:focus { - background-color: $backgroundColor; + &:focus, + &-isSelected { + background-image: euiFormControlGradient(); } &-needsUpdating { + $backgroundColor: tintOrShade($euiColorSuccess, 90%, 70%); + $textColor: makeHighContrastColor($euiColorSuccess, $backgroundColor); + + background-color: $backgroundColor; color: $textColor; + + &:focus, + &.euiDatePopoverButton-isSelected { + background-image: euiFormControlGradient($euiColorSuccess); + } } &-isInvalid { $backgroundColor: tintOrShade($euiColorDanger, 90%, 70%); $textColor: makeHighContrastColor($euiColorDanger, $backgroundColor); + background-color: $backgroundColor; color: $textColor; + + &:focus, + &.euiDatePopoverButton-isSelected { + background-image: euiFormControlGradient($euiColorDanger); + } } } diff --git a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.js b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.js index 542d59594b6..30269280f05 100644 --- a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.js +++ b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.js @@ -6,7 +6,8 @@ import moment from 'moment'; import dateMath from '@elastic/datemath'; import { EuiDatePicker } from '../../date_picker'; -import { EuiFormRow, EuiFieldText } from '../../../form'; +import { EuiFormRow, EuiFieldText, EuiFormLabel } from '../../../form'; +import { toSentenceCase } from '../../../../services/string/to_case'; const INPUT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS'; @@ -17,10 +18,13 @@ export class EuiAbsoluteTab extends Component { const parsedValue = dateMath.parse(props.value, { roundUp: props.roundUp }); const valueAsMoment = parsedValue && parsedValue.isValid() ? parsedValue : moment(); + const sentenceCasedPosition = toSentenceCase(props.position); + this.state = { valueAsMoment, textInputValue: valueAsMoment.format(INPUT_DATE_FORMAT), isTextInvalid: false, + sentenceCasedPosition, }; } @@ -70,6 +74,11 @@ export class EuiAbsoluteTab extends Component { value={this.state.textInputValue} onChange={this.handleTextChange} data-test-subj={'superDatePickerAbsoluteDateInput'} + prepend={ + + {this.state.sentenceCasedPosition} date + + } /> @@ -82,4 +91,5 @@ EuiAbsoluteTab.propTypes = { value: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, roundUp: PropTypes.bool.isRequired, + position: PropTypes.oneOf(['start', 'end']), }; diff --git a/src/components/date_picker/super_date_picker/date_popover/date_popover_button.js b/src/components/date_picker/super_date_picker/date_popover/date_popover_button.js index 6b38af26a5e..7bd2165d653 100644 --- a/src/components/date_picker/super_date_picker/date_popover/date_popover_button.js +++ b/src/components/date_picker/super_date_picker/date_popover/date_popover_button.js @@ -67,6 +67,7 @@ export function EuiDatePopoverButton(props) { roundUp={roundUp} onChange={onChange} dateFormat={dateFormat} + position={position} /> ); diff --git a/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js b/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js index 79629bd5323..b42930a5a77 100644 --- a/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js +++ b/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js @@ -20,6 +20,7 @@ export function EuiDatePopoverContent({ roundUp, onChange, dateFormat, + position, }) { const onTabClick = selectedTab => { switch (selectedTab.id) { @@ -32,6 +33,8 @@ export function EuiDatePopoverContent({ } }; + const ariaLabel = `${position === 'start' ? 'Start' : 'End'} date:`; + const renderTabs = () => { return [ { @@ -43,9 +46,11 @@ export function EuiDatePopoverContent({ value={value} onChange={onChange} roundUp={roundUp} + position={position} /> ), 'data-test-subj': 'superDatePickerAbsoluteTab', + 'aria-label': `${ariaLabel} Absolute`, }, { id: DATE_MODES.RELATIVE, @@ -56,9 +61,11 @@ export function EuiDatePopoverContent({ value={value} onChange={onChange} roundUp={roundUp} + position={position} /> ), 'data-test-subj': 'superDatePickerRelativeTab', + 'aria-label': `${ariaLabel} Relative`, }, { id: DATE_MODES.NOW, @@ -78,11 +85,12 @@ export function EuiDatePopoverContent({ fullWidth size="s" fill> - Set date and time to now + Set {position} date and time to now ), 'data-test-subj': 'superDatePickerNowTab', + 'aria-label': `${ariaLabel} Now`, }, ]; }; @@ -105,6 +113,7 @@ EuiDatePopoverContent.propTypes = { onChange: PropTypes.func.isRequired, roundUp: PropTypes.bool, dateFormat: PropTypes.string.isRequired, + position: PropTypes.oneOf(['start', 'end']), }; EuiDatePopoverContent.defaultProps = { diff --git a/src/components/date_picker/super_date_picker/date_popover/relative_tab.js b/src/components/date_picker/super_date_picker/date_popover/relative_tab.js index 4bc14e02c6e..008913739e1 100644 --- a/src/components/date_picker/super_date_picker/date_popover/relative_tab.js +++ b/src/components/date_picker/super_date_picker/date_popover/relative_tab.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import dateMath from '@elastic/datemath'; +import { toSentenceCase } from '../../../../services/string/to_case'; import { EuiFlexGroup, EuiFlexItem } from '../../../flex'; import { @@ -10,6 +11,7 @@ import { EuiFieldNumber, EuiFieldText, EuiSwitch, + EuiFormLabel, } from '../../../form'; import { EuiSpacer } from '../../../spacer'; @@ -23,9 +25,11 @@ import { export class EuiRelativeTab extends Component { constructor(props) { super(props); + const sentenceCasedPosition = toSentenceCase(props.position); this.state = { ...parseRelativeParts(this.props.value), + sentenceCasedPosition, }; } @@ -108,7 +112,13 @@ export class EuiRelativeTab extends Component { onChange={this.onRoundChange} /> - + {this.state.sentenceCasedPosition} date + } + /> ); } @@ -119,4 +129,5 @@ EuiRelativeTab.propTypes = { value: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, roundUp: PropTypes.bool, + position: PropTypes.oneOf(['start', 'end']), }; diff --git a/src/services/string/index.ts b/src/services/string/index.ts index efb8d00af88..6ed792e589c 100644 --- a/src/services/string/index.ts +++ b/src/services/string/index.ts @@ -1 +1,2 @@ export { toInitials } from './to_initials'; +export { toSentenceCase } from './to_case'; diff --git a/src/services/string/to_case.test.ts b/src/services/string/to_case.test.ts new file mode 100644 index 00000000000..58888c0d8ee --- /dev/null +++ b/src/services/string/to_case.test.ts @@ -0,0 +1,17 @@ +import { toSentenceCase } from './to_case'; + +describe('toSentenceCase', () => { + it("should return the same single word with the first letter capitalized for 'single'", () => { + expect(toSentenceCase('single')).toBe('Single'); + }); + + it("should return all the words with ony the first letter of the first word capitalized for 'two words'", () => { + expect(toSentenceCase('two words')).toBe('Two words'); + }); + + it("should return all the words with ony the first letter of the first word capitalized for 'opposite Of Sentence Case'", () => { + expect(toSentenceCase('opposite Of Sentence Case')).toBe( + 'Opposite of sentence case' + ); + }); +}); diff --git a/src/services/string/to_case.ts b/src/services/string/to_case.ts new file mode 100644 index 00000000000..dd49167ce16 --- /dev/null +++ b/src/services/string/to_case.ts @@ -0,0 +1,13 @@ +/** + * This function returns the same string with the first letter of the first word capitalized. + * + * @param {string} strint The input string + */ + +export function toSentenceCase(string: string): string { + // First lowercase all letters + const lowercase = string.toLowerCase(); + + // Then just uppercase the first letter; + return string.charAt(0).toUpperCase() + lowercase.slice(1); +}