From 3f82afa32c822870b695f83fc8f0fbc2b0a210d3 Mon Sep 17 00:00:00 2001 From: "dave.snider@gmail.com" Date: Wed, 27 Feb 2019 07:07:43 -0800 Subject: [PATCH 1/9] Add guidelines for toasts that have long messages (#1611) * toast guidelines for long messages * remove unused state from modal example * Update src-docs/src/views/guidelines/toasts.js Co-Authored-By: snide * Update src-docs/src/views/guidelines/toasts.js Co-Authored-By: snide * Update src-docs/src/views/guidelines/toasts.js Co-Authored-By: snide * feedback --- src-docs/src/routes.js | 2 +- src-docs/src/views/guidelines/toasts.js | 1053 ++++++++++++--------- src-docs/src/views/modal/overflow_test.js | 7 - 3 files changed, 589 insertions(+), 473 deletions(-) diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index b27b5a9c168f..bbaf7fe1e6ba 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -31,7 +31,7 @@ import SassGuidelines import TextScales from './views/text_scaling/text_scaling_sandbox'; -import ToastGuidelines +import { ToastGuidelines } from './views/guidelines/toasts'; import WritingGuidelines diff --git a/src-docs/src/views/guidelines/toasts.js b/src-docs/src/views/guidelines/toasts.js index 86bfbec4c25b..bf20692597aa 100644 --- a/src-docs/src/views/guidelines/toasts.js +++ b/src-docs/src/views/guidelines/toasts.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Component } from 'react'; import { GuidePage, @@ -13,478 +13,601 @@ import { EuiSpacer, EuiFlexGroup, EuiFlexItem, - EuiToast + EuiToast, + EuiCallOut, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiOverlayMask, + EuiCodeBlock, } from '../../../../src/components'; -export default () => ( - - - -

- This page documents patterns for using toasts, short messages that - appears on the lower right corner and time out after a few seconds. - They are a popular design choice because they don't need to - fit in a layout and don't disrupt the user. -

-
- - Toast types - - - - - - - - - - -

- Success toasts indicate that everything worked out -

-

- They are the most-commonly used toasts. -

-
-
-
- - - - - - - - - - -

- Warning toasts direct user attention to a potential problem -

-

- These toasts work well in monitoring apps when something - significant requires action. -

-
-
-
- - - - - - - - - - -

- Error toasts report a problem -

-

- An error toast might let users know an action didn't complete or that a form has errors. -

-
-
-
- - - - - -
- -
-
- - - -

- Info toasts relay neutral information -

+ +export class ToastGuidelines extends Component { + constructor(props) { + super(props); + + this.state = { + isModalVisible: false, + }; + + this.closeModal = this.closeModal.bind(this); + this.showModal = this.showModal.bind(this); + } + + closeModal() { + this.setState({ isModalVisible: false }); + } + + showModal() { + this.setState({ isModalVisible: true }); + } + + render() { + + let modal; + + if (this.state.isModalVisible) { + modal = ( + + + + + Your visualization has an error + + + + + + + + {`--- FAKE ERROR --- +An extremely long error trace can exist in a modal so you have time +and space to read it properly. Alternatively just link to a full page. +--- + `} + + + + + + Close + + + + + ); + } + return ( + + + +

- The default toast, an info toast might notify users about an ongoing action. + This page documents patterns for using toasts, short messages that + appears on the lower right corner and time out after a few seconds. + They are a popular design choice because they don't need to + fit in a layout and don't disrupt the user.

-
-
- - - - Use a toast for a timely message - - - - - - - - -
- -
-
- -
- - Most often, it's a single line of text - - - -
- - -
-
- - - -
- - + + Toast types + + + + + + + + + -
    -
  • - Username is a required field. -
  • -
  • - Password must be at least 6 characters long. -
  • -
  • - Email is a required field. -
  • -
+

+ Success toasts indicate that everything worked out +

+

+ They are the most-commonly used toasts. +

-
-
-
- -
- - Toasts should only contain a single action - - - - + + + + + + + + + + + +

+ Warning toasts direct user attention to a potential problem +

+

+ These toasts work well in monitoring apps when something + significant requires action. +

+
+
+
+ + + + + + + + + + +

+ Error toasts report a problem +

+

+ An error toast might let users know an action didn't complete or that a form has errors. +

+
+
+
+ + + + + +
+ +
+
+ + + +

+ Info toasts relay neutral information +

+

+ The default toast, an info toast might notify users about an ongoing action. +

+
+
+
+ + + + Use a toast for a timely message + + + + + + + + +
+ +
+
+ +
+ + Most often, it's a single line of text + + -
- - Download - -
- -
-
- - - +
+ + +
+
+ + + +
+ + + +
    +
  • + Username is a required field. +
  • +
  • + Password must be at least 6 characters long. +
  • +
  • + Email is a required field. +
  • +
+
+
+
+
+ +
+ + Toasts should only contain a single action + + - - - - Cancel - - - - - Delete - - - - - - - - - - Icons should emphasize actions - - - -
- - - - - -
- -
- - - - - - - -
- - Display one toast at a time - - - - - - - -
- -
- - Learn more - + +
+ + Download + +
+ +
+ + + + + + + + Cancel + + + + + Delete + + + + + + + + + + Icons should emphasize actions + + + +
+ + + + + +
+ +
+ + + + + + + +
+ + Display one toast at a time + + + + + + + +
+ +
+ + Learn more + +
+
+ + +
- - - - -
- - - - - Keep messages as short as possible - - - -
- -
- -
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -); + + + + + Keep messages as short as possible + + + +
+ +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + Use call-to-action buttons when the content needs more room + + + + +

The maximum bucket size of 200 was exceeded.

+
+ + See the full error + + {modal} +
+
+
+ + + + +

+ An extremely long error trace. +

+
+
+
+
+ + ); + } +} diff --git a/src-docs/src/views/modal/overflow_test.js b/src-docs/src/views/modal/overflow_test.js index 632fff82f540..4853aa72d925 100644 --- a/src-docs/src/views/modal/overflow_test.js +++ b/src-docs/src/views/modal/overflow_test.js @@ -20,19 +20,12 @@ export class OverflowTest extends Component { this.state = { isModalVisible: false, - isSwitchChecked: true, }; this.closeModal = this.closeModal.bind(this); this.showModal = this.showModal.bind(this); } - onSwitchChange = () => { - this.setState({ - isSwitchChecked: !this.state.isSwitchChecked, - }); - } - closeModal() { this.setState({ isModalVisible: false }); } From ff99bfc0973f7dfeb7402ddb5d4cdbee587b1903 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 27 Feb 2019 10:56:41 -0600 Subject: [PATCH 2/9] Prevent unmounted EuiGlobalToastList from causing errors (#1606) * prevent calculations on nullified element * add comment to early return * better inital values for requestAnimationFrame properties * #1606 changelog entry --- CHANGELOG.md | 1 + src/components/toast/global_toast_list.js | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1253a6feb2..b199ae817202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `EuiBasicTable` select all shows up on mobile ([#1462](https://github.com/elastic/eui/pull/1462)) - Adds missing `hasActiveFilters` prop for `EuiFilterButton` type and fixes `onChange` signature for `EuiButtonGroup` ([#1603](https://github.com/elastic/eui/pull/1603)) +- Prevent `EuiGlobalToastList` from attempting calculations on `null` DOM elements ([#1606](https://github.com/elastic/eui/pull/1606)) **Breaking changes** diff --git a/src/components/toast/global_toast_list.js b/src/components/toast/global_toast_list.js index d27171398971..98d7f161f998 100644 --- a/src/components/toast/global_toast_list.js +++ b/src/components/toast/global_toast_list.js @@ -23,6 +23,11 @@ export class EuiGlobalToastList extends Component { this.isScrollingToBottom = false; this.isScrolledToBottom = true; + + // See [Return Value](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#Return_value) + // for information on initial value of 0 + this.isScrollingAnimationFrame = 0; + this.startScrollingAnimationFrame = 0; } static propTypes = { @@ -40,6 +45,10 @@ export class EuiGlobalToastList extends Component { this.isScrollingToBottom = true; const scrollToBottom = () => { + // Although we cancel the requestAnimationFrame in componentWillUnmount, + // it's possible for this.listElement to become null in the meantime + if (!this.listElement) return; + const position = this.listElement.scrollTop; const destination = this.listElement.scrollHeight - this.listElement.clientHeight; const distanceToDestination = destination - position; @@ -54,11 +63,11 @@ export class EuiGlobalToastList extends Component { this.listElement.scrollTop = position + distanceToDestination * 0.25; if (this.isScrollingToBottom) { - window.requestAnimationFrame(scrollToBottom); + this.isScrollingAnimationFrame = window.requestAnimationFrame(scrollToBottom); } }; - window.requestAnimationFrame(scrollToBottom); + this.startScrollingAnimationFrame = window.requestAnimationFrame(scrollToBottom); } onMouseEnter = () => { @@ -162,6 +171,12 @@ export class EuiGlobalToastList extends Component { } componentWillUnmount() { + if (this.isScrollingAnimationFrame !== 0) { + window.cancelAnimationFrame(this.isScrollingAnimationFrame); + } + if (this.startScrollingAnimationFrame !== 0) { + window.cancelAnimationFrame(this.startScrollingAnimationFrame); + } this.listElement.removeEventListener('scroll', this.onScroll); this.listElement.removeEventListener('mouseenter', this.onMouseEnter); this.listElement.removeEventListener('mouseleave', this.onMouseLeave); From e3c649be15f8e2c75f2291d85640ac8783536160 Mon Sep 17 00:00:00 2001 From: Darren Meiss Date: Wed, 27 Feb 2019 11:57:57 -0500 Subject: [PATCH 3/9] Minors edits to text in guidelines/modals.js (#1604) --- src-docs/src/views/guidelines/modals.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src-docs/src/views/guidelines/modals.js b/src-docs/src/views/guidelines/modals.js index ec1cb2e415a9..ee993420159d 100644 --- a/src-docs/src/views/guidelines/modals.js +++ b/src-docs/src/views/guidelines/modals.js @@ -98,7 +98,7 @@ export default () => ( heading="" description="A modal can gather input necessary for continuing the current workflow. This type of modal works best for a short, focused task. - Use input modals sparingly—they interrput the user's workflow. + Use input modals sparingly—they interrupt the user's workflow. " > @@ -204,8 +204,8 @@ export default () => ( Date: Wed, 27 Feb 2019 12:13:31 -0500 Subject: [PATCH 4/9] Edit to JSDoc comment in bottom_bar.js (#1616) --- src/components/bottom_bar/bottom_bar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/bottom_bar/bottom_bar.js b/src/components/bottom_bar/bottom_bar.js index 7e4122fe1d7a..81fa407cd33a 100644 --- a/src/components/bottom_bar/bottom_bar.js +++ b/src/components/bottom_bar/bottom_bar.js @@ -75,7 +75,7 @@ export class EuiBottomBar extends Component { EuiBottomBar.propTypes = { children: PropTypes.node, /** - * Optional class applied to the bar iteself + * Optional class applied to the bar itself */ className: PropTypes.string, /** From 3f5f6b3018989e07c97f772cbc50010294b6e77c Mon Sep 17 00:00:00 2001 From: Darren Meiss Date: Wed, 27 Feb 2019 12:14:05 -0500 Subject: [PATCH 5/9] Edits to text in accordion/accordion_example.js (#1612) --- src-docs/src/views/accordion/accordion_example.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src-docs/src/views/accordion/accordion_example.js b/src-docs/src/views/accordion/accordion_example.js index 6376d4b552b7..8aa71a0a07b7 100644 --- a/src-docs/src/views/accordion/accordion_example.js +++ b/src-docs/src/views/accordion/accordion_example.js @@ -43,7 +43,7 @@ export const AccordionExample = {

EuiFlexGroup's negative margins can sometimes create scrollbars within EuiAccordion because of - the overflow tricks the used to hide content. If you run into this issue make + the overflow tricks used to hide content. If you run into this issue make sure your paddingSize prop is large enough to account for the gutterSize of any nested flex groups.

@@ -66,7 +66,7 @@ export const AccordionExample = {

EuiAccordion is purposely bare so that you can put whatever styling you need on it (see the accordion form example). The only - styling we force on you in the caret, which gives the user an understaning + styling we force on you is the caret, which gives the user an understanding that the content will open up.

@@ -75,8 +75,8 @@ export const AccordionExample = { based on the height of those children.

- For styling needs. Classes can be individually applied with - className (for the accordion entire), + For styling needs, classes can be individually applied with + className (for the entire accordion), and buttonClassName (for the clickable area).

@@ -98,7 +98,7 @@ export const AccordionExample = { displayed on the right of any accordion. Usually this is a delete or button, but can be anything. Note that this action is separate from the click state that expands the accordion. This is needed to make - it accessibile. + it accessible.

), demo: , From 849a56d86b753b406ded13e1749cf4c011c2b84e Mon Sep 17 00:00:00 2001 From: Darren Meiss Date: Wed, 27 Feb 2019 12:14:42 -0500 Subject: [PATCH 6/9] Edits to text in guidelines/writing.js (#1609) --- src-docs/src/views/guidelines/writing.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src-docs/src/views/guidelines/writing.js b/src-docs/src/views/guidelines/writing.js index 08b2db22d801..f4f4a3aa46f5 100644 --- a/src-docs/src/views/guidelines/writing.js +++ b/src-docs/src/views/guidelines/writing.js @@ -257,7 +257,7 @@ export default () => ( We noticed that you don't have any data in your cluster. Try our sample data and dashboards or jump in with your own data. @@ -301,7 +301,7 @@ export default () => ( heading="Don't use unneccessary punctuation" description="Although punctuation can help clarify meaning, it can also clutter the UI. Don't add a colon after a label, an ellipsis (...) - at the end of an action, an (s) at the end of a noun, or add parenthesis + at the end of an action, an (s) at the end of a noun, or add parentheses (())." > @@ -512,7 +512,7 @@ export default () => ( @@ -577,7 +577,7 @@ export default () => ( Date: Wed, 27 Feb 2019 10:17:46 -0700 Subject: [PATCH 7/9] Process typedefs for FunctionComponent into propTypes (#1617) --- .../babel/proptypes-from-ts-props/index.js | 8 ++-- .../proptypes-from-ts-props/index.test.js | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/scripts/babel/proptypes-from-ts-props/index.js b/scripts/babel/proptypes-from-ts-props/index.js index 02ccac3d65b1..ae2979fa9384 100644 --- a/scripts/babel/proptypes-from-ts-props/index.js +++ b/scripts/babel/proptypes-from-ts-props/index.js @@ -1136,7 +1136,8 @@ module.exports = function propTypesFromTypeScript({ types }) { const { left, right } = idTypeAnnotation.typeAnnotation.typeName; if (left.name === 'React') { - if (right.name === 'SFC') { + const rightName = right.name; + if (rightName === 'SFC' || rightName === 'FunctionComponent') { processComponentDeclaration(idTypeAnnotation.typeAnnotation.typeParameters.params[0], nodePath, state); fileCodeNeedsUpdating = true; } else { @@ -1144,8 +1145,9 @@ module.exports = function propTypesFromTypeScript({ types }) { } } } else if (idTypeAnnotation.typeAnnotation.typeName.type === 'Identifier') { - if (idTypeAnnotation.typeAnnotation.typeName.name === 'SFC') { - if (state.get('importsFromReact').has('SFC')) { + const typeName = idTypeAnnotation.typeAnnotation.typeName.name; + if (typeName === 'SFC' || typeName === 'FunctionComponent') { + if (state.get('importsFromReact').has(typeName)) { processComponentDeclaration(idTypeAnnotation.typeAnnotation.typeParameters.params[0], nodePath, state); fileCodeNeedsUpdating = true; } diff --git a/scripts/babel/proptypes-from-ts-props/index.test.js b/scripts/babel/proptypes-from-ts-props/index.test.js index 252c7bae2b02..005744d83dc7 100644 --- a/scripts/babel/proptypes-from-ts-props/index.test.js +++ b/scripts/babel/proptypes-from-ts-props/index.test.js @@ -1976,6 +1976,52 @@ const FooComponent = () => { return
Hello World
; }; +FooComponent.propTypes = { + foo: PropTypes.string.isRequired, + bar: PropTypes.number +};`); + }); + + it('annotates FunctionComponent components', () => { + const result = transform( + ` +import React, { FunctionComponent } from 'react'; +const FooComponent: FunctionComponent<{foo: string, bar?: number}> = () => { + return (
Hello World
); +}`, + babelOptions + ); + + expect(result.code).toBe(`import React from 'react'; +import PropTypes from "prop-types"; + +const FooComponent = () => { + return
Hello World
; +}; + +FooComponent.propTypes = { + foo: PropTypes.string.isRequired, + bar: PropTypes.number +};`); + }); + + it('annotates React.FunctionComponent components', () => { + const result = transform( + ` +import React from 'react'; +const FooComponent: React.FunctionComponent<{foo: string, bar?: number}> = () => { + return (
Hello World
); +}`, + babelOptions + ); + + expect(result.code).toBe(`import React from 'react'; +import PropTypes from "prop-types"; + +const FooComponent = () => { + return
Hello World
; +}; + FooComponent.propTypes = { foo: PropTypes.string.isRequired, bar: PropTypes.number From 9e89dbfe734883bb800a200baaef3c16aa28d890 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 27 Feb 2019 11:10:38 -0700 Subject: [PATCH 8/9] Move react-datepicker types into EUI (#1618) * Move react-datepicker types into EUI * changelog * Re-added basic popper-based props that do not require popper dependency --- CHANGELOG.md | 1 + package.json | 1 - scripts/dtsgenerator.js | 2 +- src-docs/src/i18ntokens.json | 16 +-- src/components/date_picker/index.d.ts | 9 +- .../date_picker/react-datepicker.d.ts | 102 ++++++++++++++++++ yarn.lock | 19 ---- 7 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 src/components/date_picker/react-datepicker.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b199ae817202..e3e8b95a65bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `EuiBasicTable` select all shows up on mobile ([#1462](https://github.com/elastic/eui/pull/1462)) - Adds missing `hasActiveFilters` prop for `EuiFilterButton` type and fixes `onChange` signature for `EuiButtonGroup` ([#1603](https://github.com/elastic/eui/pull/1603)) +- Included `react-datepicker` TS types in EUI itself to avoid outside dependency ([#1618](https://github.com/elastic/eui/pull/1618)) - Prevent `EuiGlobalToastList` from attempting calculations on `null` DOM elements ([#1606](https://github.com/elastic/eui/pull/1606)) **Breaking changes** diff --git a/package.json b/package.json index 413dd9b5fb7e..88db05b551f2 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "@types/enzyme": "^3.1.13", "@types/jest": "^24.0.6", "@types/react": "^16.8.4", - "@types/react-datepicker": "1.8.0", "@types/react-is": "~16.3.0", "@types/react-virtualized": "^9.18.6", "@types/uuid": "^3.4.4", diff --git a/scripts/dtsgenerator.js b/scripts/dtsgenerator.js index 927ffcf4cbf2..a494fe78ee44 100644 --- a/scripts/dtsgenerator.js +++ b/scripts/dtsgenerator.js @@ -54,7 +54,7 @@ const generator = dtsGenerator({ params.importedModuleId, { basedir: importFromBaseDir, - extensions: ['.ts', '.tsx'], + extensions: ['.ts', '.tsx', '.d.ts'], } ); diff --git a/src-docs/src/i18ntokens.json b/src-docs/src/i18ntokens.json index 939e60108732..1899b5f1b5a9 100644 --- a/src-docs/src/i18ntokens.json +++ b/src-docs/src/i18ntokens.json @@ -5,11 +5,11 @@ "highlighting": "string", "loc": { "start": { - "line": 421, + "line": 432, "column": 10 }, "end": { - "line": 425, + "line": 436, "column": 12 } }, @@ -21,12 +21,12 @@ "highlighting": "string", "loc": { "start": { - "line": 458, - "column": 10 + "line": 468, + "column": 6 }, "end": { - "line": 458, - "column": 81 + "line": 468, + "column": 77 } }, "filepath": "src/components/basic_table/basic_table.js" @@ -37,11 +37,11 @@ "highlighting": "string", "loc": { "start": { - "line": 736, + "line": 769, "column": 8 }, "end": { - "line": 736, + "line": 769, "column": 79 } }, diff --git a/src/components/date_picker/index.d.ts b/src/components/date_picker/index.d.ts index f8032489cd7c..e243a3d3ca4e 100644 --- a/src/components/date_picker/index.d.ts +++ b/src/components/date_picker/index.d.ts @@ -1,7 +1,7 @@ import React from 'react'; import { CommonProps } from '../common'; import { IconType } from '../icon'; -import ReactDatePicker, { ReactDatePickerProps } from 'react-datepicker'; +import _ReactDatePicker, { ReactDatePickerProps as _ReactDatePickerProps } from './react-datepicker'; import { Moment } from 'moment'; declare module '@elastic/eui' { @@ -17,12 +17,12 @@ declare module '@elastic/eui' { refreshInterval: number; } - interface EuiExtendedDatePickerProps extends ReactDatePickerProps { + interface EuiExtendedDatePickerProps extends _ReactDatePickerProps { fullWidth?: boolean; isInvalid?: boolean; isLoading?: boolean; injectTimes?: Moment[]; // added here because the type is missing in @types/react-datepicker@1.8.0 - inputRef?: React.Ref; + inputRef?: React.Ref; placeholder?: string; shadow?: boolean; showIcon?: boolean; @@ -73,4 +73,7 @@ declare module '@elastic/eui' { }; export const EuiSuperDatePicker: React.SFC; + + export const ReactDatePicker: typeof _ReactDatePicker; + export const ReactDatePickerProps: _ReactDatePickerProps; } diff --git a/src/components/date_picker/react-datepicker.d.ts b/src/components/date_picker/react-datepicker.d.ts new file mode 100644 index 000000000000..2629b2c3e36b --- /dev/null +++ b/src/components/date_picker/react-datepicker.d.ts @@ -0,0 +1,102 @@ +// Type definitions for react-datepicker 1.8 +// Project: https://github.com/Hacker0x01/react-datepicker +// Definitions by: Rajab Shakirov , +// Andrey Balokha , +// Greg Smith , +// Platon Pronko +// Roy Xue +// Koala Human +// Sean Kelley +// Justin Grant +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +import * as React from "react"; +import * as moment from "moment"; + +export interface ReactDatePickerProps { + adjustDateOnChange?: boolean; + allowSameDay?: boolean; + autoComplete?: string; + autoFocus?: boolean; + calendarClassName?: string; + children?: React.ReactNode; + className?: string; + customInput?: React.ReactNode; + customInputRef?: string; + dateFormat?: string | string[]; + dateFormatCalendar?: string; + dayClassName?(date: moment.Moment): string | null; + disabled?: boolean; + disabledKeyboardNavigation?: boolean; + dropdownMode?: 'scroll' | 'select'; + endDate?: moment.Moment; + excludeDates?: moment.Moment[]; + excludeTimes?: moment.Moment[]; + filterDate?(date: moment.Moment): boolean; + fixedHeight?: boolean; + forceShowMonthNavigation?: boolean; + formatWeekNumber?(date: moment.Moment): string | number; + highlightDates?: moment.Moment[]; + id?: string; + includeDates?: moment.Moment[]; + includeTimes?: moment.Moment[]; + inline?: boolean; + isClearable?: boolean; + locale?: string; + maxDate?: moment.Moment; + maxTime?: moment.Moment; + minDate?: moment.Moment; + minTime?: moment.Moment; + monthsShown?: number; + name?: string; + onBlur?(event: React.FocusEvent): void; + onChange(date: moment.Moment | null, event: React.SyntheticEvent | undefined): void; + onChangeRaw?(event: React.FocusEvent): void; + onClickOutside?(event: React.MouseEvent): void; + onFocus?(event: React.FocusEvent): void; + onKeyDown?(event: React.KeyboardEvent): void; + onMonthChange?(date: moment.Moment): void; + onSelect?(date: moment.Moment, event: React.SyntheticEvent | undefined): void; + onWeekSelect?(firstDayOfWeek: moment.Moment, weekNumber: string | number, event: React.SyntheticEvent | undefined): void; + onYearChange?(date: moment.Moment): void; + openToDate?: moment.Moment; + peekNextMonth?: boolean; + placeholderText?: string; + popperClassName?: string; + popperContainer?(props: { children: React.ReactNode[] }): React.ReactNode; + popperPlacement?: string; + preventOpenOnFocus?: boolean; + readOnly?: boolean; + required?: boolean; + scrollableMonthYearDropdown?: boolean; + scrollableYearDropdown?: boolean; + selected?: moment.Moment | null; + selectsEnd?: boolean; + selectsStart?: boolean; + shouldCloseOnSelect?: boolean; + showDisabledMonthNavigation?: boolean; + showMonthDropdown?: boolean; + showMonthYearDropdown?: boolean; + showTimeSelect?: boolean; + showTimeSelectOnly?: boolean; + showWeekNumbers?: boolean; + showYearDropdown?: boolean; + startDate?: moment.Moment; + startOpen?: boolean; + tabIndex?: number; + timeCaption?: string; + timeFormat?: string; + timeIntervals?: number; + title?: string; + todayButton?: string; + useShortMonthInDropdown?: boolean; + useWeekdaysShort?: boolean; + utcOffset?: number; + value?: string; + weekLabel?: string; + withPortal?: boolean; + yearDropdownItemNumber?: number; +} +declare const ReactDatePicker: React.ClassicComponentClass; +export default ReactDatePicker; diff --git a/yarn.lock b/yarn.lock index b27a79e4c05e..ad613b8ba667 100644 --- a/yarn.lock +++ b/yarn.lock @@ -977,15 +977,6 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.9.tgz#f2d14df87b0739041bc53a7d75e3d77d726a3ec0" integrity sha512-Nha5b+jmBI271jdTMwrHiNXM+DvThjHOfyZtMX9kj/c/LUj2xiLHsG/1L3tJ8DjAoQN48cHwUwtqBotjyXaSdQ== -"@types/react-datepicker@1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-1.8.0.tgz#b8b4f69d3e5398500c136f5338e0746ed98d46e8" - integrity sha512-QyHMOFCOFIkcyDCXUGnL7OyM+Gj2aG95d3t18wgrLTxQJseVQXeQFTVnUeXmmF2cZxeWtGTfRl1uYPTr3/rAFg== - dependencies: - "@types/react" "*" - moment ">=2.14.0" - popper.js "^1.14.1" - "@types/react-is@~16.3.0": version "16.3.1" resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-16.3.1.tgz#f3e1dee9d0eb58c049825540cb061b5588022a9e" @@ -9005,11 +8996,6 @@ moment@2.x.x: resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a" integrity sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ== -moment@>=2.14.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== - moment@^2.20.1: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" @@ -10359,11 +10345,6 @@ pngjs@~2.2.0: resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-2.2.0.tgz#649663609a0ebab87c8f08b3fe724048b51d9d7f" integrity sha1-ZJZjYJoOurh8jwiz/nJASLUdnX8= -popper.js@^1.14.1: - version "1.14.7" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" - integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== - portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" From a2363c3003470719946fa2bf7975fabc60ac221b Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 27 Feb 2019 13:02:45 -0600 Subject: [PATCH 9/9] misc form row fixes (#1522) * misc form row fixes * #1522 changelog entry * use error as key; changelog update * update changelog entry --- CHANGELOG.md | 2 ++ .../described_form_group/described_form_group.js | 2 +- src/components/form/form_row/form_row.js | 13 ++++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3e8b95a65bf..6360c6744591 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added `numActiveFilters` prop to `EuiFilterButton` ([#1589](https://github.com/elastic/eui/pull/1589)) - Updated style of `EuiFilterButton` to match `EuiFacetButton` ([#1589](https://github.com/elastic/eui/pull/1589)) - Added `size` and `color` props to `EuiNotificationBadge` ([#1589](https://github.com/elastic/eui/pull/1589)) +- Allow `EuiDescribedFormGroup` to exist as a description-only row ([#1522](https://github.com/elastic/eui/pull/1522)) **Bug fixes** @@ -13,6 +14,7 @@ - Adds missing `hasActiveFilters` prop for `EuiFilterButton` type and fixes `onChange` signature for `EuiButtonGroup` ([#1603](https://github.com/elastic/eui/pull/1603)) - Included `react-datepicker` TS types in EUI itself to avoid outside dependency ([#1618](https://github.com/elastic/eui/pull/1618)) - Prevent `EuiGlobalToastList` from attempting calculations on `null` DOM elements ([#1606](https://github.com/elastic/eui/pull/1606)) +- Fixed `EuiFormRow` errors from the possibility of having duplicate `key` values ([#1522](https://github.com/elastic/eui/pull/1522)) **Breaking changes** diff --git a/src/components/form/described_form_group/described_form_group.js b/src/components/form/described_form_group/described_form_group.js index bff5751531f7..8b0f13d260fb 100644 --- a/src/components/form/described_form_group/described_form_group.js +++ b/src/components/form/described_form_group/described_form_group.js @@ -101,7 +101,7 @@ EuiDescribedFormGroup.propTypes = { /** * One or more `EuiFormRow`s */ - children: PropTypes.node.isRequired, + children: PropTypes.node, className: PropTypes.string, /** * Passed to `EuiFlexGroup` diff --git a/src/components/form/form_row/form_row.js b/src/components/form/form_row/form_row.js index 3694d5fd173c..4fc557e5eb58 100644 --- a/src/components/form/form_row/form_row.js +++ b/src/components/form/form_row/form_row.js @@ -93,11 +93,14 @@ export class EuiFormRow extends Component { if (error && isInvalid) { const errorTexts = Array.isArray(error) ? error : [error]; - optionalErrors = errorTexts.map((error, i) => ( - - {error} - - )); + optionalErrors = errorTexts.map((error, i) =>{ + const key = typeof error === 'string' ? error : i; + return ( + + {error} + + );} + ); } let optionalLabel;