From 3b9095f8dcd3fbf05cc9b24aa078c885690b0f1a Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 4 Jan 2019 11:21:41 -0700 Subject: [PATCH 01/15] Added EuiContext and I18n --- .../babel/proptypes-from-ts-props/index.js | 2 +- src-docs/src/routes.js | 4 ++ src-docs/src/views/context/context.js | 62 +++++++++++++++++++ src-docs/src/views/context/context_example.js | 40 ++++++++++++ src/components/context/context.tsx | 21 +++++++ src/components/context/index.ts | 4 ++ src/components/i18n/i18n.tsx | 51 +++++++++++++++ src/components/i18n/index.ts | 1 + src/components/index.js | 9 +++ 9 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src-docs/src/views/context/context.js create mode 100644 src-docs/src/views/context/context_example.js create mode 100644 src/components/context/context.tsx create mode 100644 src/components/context/index.ts create mode 100644 src/components/i18n/i18n.tsx create mode 100644 src/components/i18n/index.ts diff --git a/scripts/babel/proptypes-from-ts-props/index.js b/scripts/babel/proptypes-from-ts-props/index.js index a35cace5684..45cbaf898b2 100644 --- a/scripts/babel/proptypes-from-ts-props/index.js +++ b/scripts/babel/proptypes-from-ts-props/index.js @@ -967,7 +967,7 @@ module.exports = function propTypesFromTypeScript({ types }) { processComponentDeclaration(idTypeAnnotation.typeAnnotation.typeParameters.params[0], nodePath, state); fileCodeNeedsUpdating = true; } else { - throw new Error(`Cannot process annotation id React.${right.name}`); + // throw new Error(`Cannot process annotation id React.${right.name}`); } } } else if (idTypeAnnotation.typeAnnotation.typeName.type === 'Identifier') { diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index 29a5a4f6ca9..2fca6547785 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -90,6 +90,9 @@ import { ColorPickerExample } import { ComboBoxExample } from './views/combo_box/combo_box_example'; +import { ContextExample } + from './views/context/context_example'; + import { ContextMenuExample } from './views/context_menu/context_menu_example'; @@ -405,6 +408,7 @@ const navigation = [{ items: [ AccessibilityExample, ColorPaletteExample, + ContextExample, CopyExample, UtilityClassesExample, DelayHideExample, diff --git a/src-docs/src/views/context/context.js b/src-docs/src/views/context/context.js new file mode 100644 index 00000000000..2ad99248296 --- /dev/null +++ b/src-docs/src/views/context/context.js @@ -0,0 +1,62 @@ +import React, { Component, Fragment } from 'react'; + +import { + EuiContext, + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiSpacer, + I18n, +} from '../../../../src/components'; + +const mappings = { + fr: { + greeting: 'Salutations!', + question: 'Quel est votre nom?', + placeholder: 'Jean Dupont', + action: 'Soumettre', + }, +}; + +export default class extends Component { + state = { + language: 'en', + name: '' + } + + setLanguage = (language) => this.setState({ language }) + + render() { + return ( + +
+ this.setLanguage('en')}>English + this.setLanguage('fr')}>French + + + + + + + + {question =>

{question}

}
+ + + + + {([placeholder, action]) => ( + + + + {action} + + )} + +
+
+ ); + } +} diff --git a/src-docs/src/views/context/context_example.js b/src-docs/src/views/context/context_example.js new file mode 100644 index 00000000000..057928f54dc --- /dev/null +++ b/src-docs/src/views/context/context_example.js @@ -0,0 +1,40 @@ +import React from 'react'; + +import { renderToHtml } from '../../services'; + +import { + GuideSectionTypes, +} from '../../components'; + +import { + EuiCode, + EuiContext, + I18n, +} from '../../../../src/components'; + +import Context from './context'; +const contextSource = require('!!raw-loader!./context'); +const contextHtml = renderToHtml(Context); + +export const ContextExample = { + title: 'Context', + sections: [{ + source: [{ + type: GuideSectionTypes.JS, + code: contextSource, + }, { + type: GuideSectionTypes.HTML, + code: contextHtml, + }], + text: ( +

+ EuiContext allows setting global internationalization copy for + EUI components. Any components used within this context will lookup their display values + from this mapping. +

+ ), + components: { EuiContext }, + demo: , + props: { EuiContext, I18n }, + }], +}; diff --git a/src/components/context/context.tsx b/src/components/context/context.tsx new file mode 100644 index 00000000000..0445ba92aa6 --- /dev/null +++ b/src/components/context/context.tsx @@ -0,0 +1,21 @@ +import React, { createContext, ReactElement } from 'react'; + +export interface I18nMappingShape { + [key: string]: ReactElement; +} + +const I18nContext: React.Context = createContext({}); +const { Provider: EuiI18nProvider, Consumer: EuiI18nConsumer } = I18nContext; + +interface IEuiContextProps { + i18n: I18nMappingShape; + children: React.ReactNode; +} + +const EuiContext: React.SFC = ({i18n = {}, children}) => ( + + {children} + +); + +export { EuiContext, EuiI18nConsumer }; diff --git a/src/components/context/index.ts b/src/components/context/index.ts new file mode 100644 index 00000000000..4f56b7e8adf --- /dev/null +++ b/src/components/context/index.ts @@ -0,0 +1,4 @@ +export { + EuiContext, + EuiI18nConsumer +} from './context'; diff --git a/src/components/i18n/i18n.tsx b/src/components/i18n/i18n.tsx new file mode 100644 index 00000000000..2d759f20601 --- /dev/null +++ b/src/components/i18n/i18n.tsx @@ -0,0 +1,51 @@ +import React, { ReactElement } from 'react'; +import { EuiI18nConsumer } from '../context'; +import { ExclusiveUnion } from '../common'; +import { I18nMappingShape } from '../context/context'; + +// +// {(foo) =>

foo

}
+// {([foo, bar]) =>

{foo}, {bar}

+ +function lookupToken(token: string, i18nMapping: I18nMappingShape, valueDefault: ReactElement) { + return i18nMapping[token] || valueDefault; +} + +interface I18nTokenShape { + token: string; + default: ReactElement; + children?: (x: ReactElement) => ReactElement; +} + +interface I18nTokensShape { + tokens: string[]; + defaults: Array>; + children: (x: Array>) => ReactElement; +} + +type I18nProps = ExclusiveUnion; + +function hasTokens(x: I18nProps): x is I18nTokensShape { + return x.tokens != null; +} + +const I18n: React.SFC = (props) => ( + + { + (i18nConfig) => { + if (hasTokens(props)) { + return props.children(props.tokens.map((token, idx) => lookupToken(token, i18nConfig, props.defaults[idx]))); + } + + const tokenValue = lookupToken(props.token, i18nConfig, props.default); + if (props.children) { + return props.children(tokenValue); + } else { + return tokenValue; + } + } + } + +); + +export { I18n }; diff --git a/src/components/i18n/index.ts b/src/components/i18n/index.ts new file mode 100644 index 00000000000..663e6665060 --- /dev/null +++ b/src/components/i18n/index.ts @@ -0,0 +1 @@ +export {I18n} from './i18n'; diff --git a/src/components/index.js b/src/components/index.js index e71d9a4f250..53c13b2dbba 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -60,6 +60,11 @@ export { EuiComboBox, } from './combo_box'; +export { + EuiContext, + EuiI18nConsumer +} from './context'; + export { EuiContextMenu, EuiContextMenuPanel, @@ -181,6 +186,10 @@ export { EuiImage, } from './image'; +export { + I18n, +} from './i18n'; + export { EuiLoadingKibana, EuiLoadingChart, From b153ad0ad8a7c6cb018f02095155ace15432b365 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 4 Jan 2019 12:05:41 -0700 Subject: [PATCH 02/15] Update types for mapping values --- src/components/context/context.tsx | 4 ++-- src/components/i18n/i18n.tsx | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/context/context.tsx b/src/components/context/context.tsx index 0445ba92aa6..8c53b57b81f 100644 --- a/src/components/context/context.tsx +++ b/src/components/context/context.tsx @@ -1,7 +1,7 @@ -import React, { createContext, ReactElement } from 'react'; +import React, { createContext, ReactChild } from 'react'; export interface I18nMappingShape { - [key: string]: ReactElement; + [key: string]: ReactChild; } const I18nContext: React.Context = createContext({}); diff --git a/src/components/i18n/i18n.tsx b/src/components/i18n/i18n.tsx index 2d759f20601..305825f811f 100644 --- a/src/components/i18n/i18n.tsx +++ b/src/components/i18n/i18n.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement } from 'react'; +import React, { ReactChild, ReactElement } from 'react'; import { EuiI18nConsumer } from '../context'; import { ExclusiveUnion } from '../common'; import { I18nMappingShape } from '../context/context'; @@ -7,20 +7,20 @@ import { I18nMappingShape } from '../context/context'; // {(foo) =>

foo

}
// {([foo, bar]) =>

{foo}, {bar}

-function lookupToken(token: string, i18nMapping: I18nMappingShape, valueDefault: ReactElement) { +function lookupToken(token: string, i18nMapping: I18nMappingShape, valueDefault: ReactChild) { return i18nMapping[token] || valueDefault; } interface I18nTokenShape { token: string; - default: ReactElement; - children?: (x: ReactElement) => ReactElement; + default: ReactChild; + children?: (x: ReactChild) => ReactElement; } interface I18nTokensShape { tokens: string[]; - defaults: Array>; - children: (x: Array>) => ReactElement; + defaults: ReactChild[]; + children: (x: ReactChild[]) => ReactElement; } type I18nProps = ExclusiveUnion; From b545ff4920bbfae31d36f9b2879235db268e1fa0 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Tue, 8 Jan 2019 10:11:32 -0700 Subject: [PATCH 03/15] wip --- src-docs/src/views/context/context.js | 6 +++++- src/components/context/context.tsx | 12 ++++++++---- src/components/i18n/i18n.tsx | 11 ++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src-docs/src/views/context/context.js b/src-docs/src/views/context/context.js index 2ad99248296..1c8a4d81f78 100644 --- a/src-docs/src/views/context/context.js +++ b/src-docs/src/views/context/context.js @@ -27,8 +27,12 @@ export default class extends Component { setLanguage = (language) => this.setState({ language }) render() { + const i18n = { + mapping: mappings[this.state.language] + }; + return ( - +
this.setLanguage('en')}>English this.setLanguage('fr')}>French diff --git a/src/components/context/context.tsx b/src/components/context/context.tsx index 8c53b57b81f..2cf35d4ccd5 100644 --- a/src/components/context/context.tsx +++ b/src/components/context/context.tsx @@ -1,14 +1,18 @@ import React, { createContext, ReactChild } from 'react'; -export interface I18nMappingShape { - [key: string]: ReactChild; +export interface I18nShape { + mapping?: { + [key: string]: ReactChild; + }; + formatNumber?: (x: number) => string; + formatDate?: (x: Date) => string; } -const I18nContext: React.Context = createContext({}); +const I18nContext: React.Context = createContext({}); const { Provider: EuiI18nProvider, Consumer: EuiI18nConsumer } = I18nContext; interface IEuiContextProps { - i18n: I18nMappingShape; + i18n: I18nShape; children: React.ReactNode; } diff --git a/src/components/i18n/i18n.tsx b/src/components/i18n/i18n.tsx index 305825f811f..d7ef656abc5 100644 --- a/src/components/i18n/i18n.tsx +++ b/src/components/i18n/i18n.tsx @@ -1,14 +1,14 @@ import React, { ReactChild, ReactElement } from 'react'; import { EuiI18nConsumer } from '../context'; import { ExclusiveUnion } from '../common'; -import { I18nMappingShape } from '../context/context'; +import { I18nShape } from '../context/context'; // // {(foo) =>

foo

}
// {([foo, bar]) =>

{foo}, {bar}

-function lookupToken(token: string, i18nMapping: I18nMappingShape, valueDefault: ReactChild) { - return i18nMapping[token] || valueDefault; +function lookupToken(token: string, i18nMapping: I18nShape['mapping'], valueDefault: ReactChild) { + return (i18nMapping && i18nMapping[token]) || valueDefault; } interface I18nTokenShape { @@ -33,11 +33,12 @@ const I18n: React.SFC = (props) => ( { (i18nConfig) => { + const { mapping } = i18nConfig; if (hasTokens(props)) { - return props.children(props.tokens.map((token, idx) => lookupToken(token, i18nConfig, props.defaults[idx]))); + return props.children(props.tokens.map((token, idx) => lookupToken(token, mapping, props.defaults[idx]))); } - const tokenValue = lookupToken(props.token, i18nConfig, props.default); + const tokenValue = lookupToken(props.token, mapping, props.default); if (props.children) { return props.children(tokenValue); } else { From 362af8b0938ae2e941b1c344f29aec36a0c954a3 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Tue, 8 Jan 2019 10:58:01 -0700 Subject: [PATCH 04/15] added I18nNumber --- .../babel/proptypes-from-ts-props/index.js | 5 +- src-docs/src/views/context/context.js | 9 +++- src/components/context/context.tsx | 2 +- src/components/i18n/i18n_number.tsx | 47 +++++++++++++++++++ src/components/i18n/index.ts | 3 +- src/components/index.js | 1 + 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/components/i18n/i18n_number.tsx diff --git a/scripts/babel/proptypes-from-ts-props/index.js b/scripts/babel/proptypes-from-ts-props/index.js index 45cbaf898b2..68db9adeff5 100644 --- a/scripts/babel/proptypes-from-ts-props/index.js +++ b/scripts/babel/proptypes-from-ts-props/index.js @@ -346,6 +346,9 @@ function getPropTypesForNode(node, optional, state) { [ types.objectExpression( node.members.map(property => { + // skip TS index signatures + if (types.isTSIndexSignature(property)) return null; + const objectProperty = types.objectProperty( types.identifier(property.key.name || `"${property.key.value}"`), getPropTypesForNode(property.typeAnnotation, property.optional, state) @@ -354,7 +357,7 @@ function getPropTypesForNode(node, optional, state) { objectProperty.leadingComments = property.leadingComments.map(({ type, value }) => ({ type, value })); } return objectProperty; - }) + }).filter(x => x != null) ) ] ); diff --git a/src-docs/src/views/context/context.js b/src-docs/src/views/context/context.js index 1c8a4d81f78..130b9cf4dda 100644 --- a/src-docs/src/views/context/context.js +++ b/src-docs/src/views/context/context.js @@ -7,11 +7,13 @@ import { EuiFieldText, EuiSpacer, I18n, + I18nNumber, } from '../../../../src/components'; const mappings = { fr: { greeting: 'Salutations!', + guestNo: 'Vous êtes invité #', question: 'Quel est votre nom?', placeholder: 'Jean Dupont', action: 'Soumettre', @@ -28,7 +30,8 @@ export default class extends Component { render() { const i18n = { - mapping: mappings[this.state.language] + mapping: mappings[this.state.language], + formatNumber: (value) => new Intl.NumberFormat(this.state.language).format(value), }; return ( @@ -43,6 +46,10 @@ export default class extends Component { +

+ + + {question =>

{question}

}
diff --git a/src/components/context/context.tsx b/src/components/context/context.tsx index 2cf35d4ccd5..be1fb75aa3e 100644 --- a/src/components/context/context.tsx +++ b/src/components/context/context.tsx @@ -5,7 +5,7 @@ export interface I18nShape { [key: string]: ReactChild; }; formatNumber?: (x: number) => string; - formatDate?: (x: Date) => string; + formatDateTime?: (x: Date) => string; } const I18nContext: React.Context = createContext({}); diff --git a/src/components/i18n/i18n_number.tsx b/src/components/i18n/i18n_number.tsx new file mode 100644 index 00000000000..dc04bc839b1 --- /dev/null +++ b/src/components/i18n/i18n_number.tsx @@ -0,0 +1,47 @@ +import React, { ReactChild, ReactElement } from 'react'; +import { EuiI18nConsumer } from '../context'; +import { ExclusiveUnion } from '../common'; + +const defaultFormatter = new Intl.NumberFormat('en'); +function defaultFormatNumber(value: number) { + return defaultFormatter.format(value); +} + +interface I18nNumberValueShape { + value: number; + children?: (x: ReactChild) => ReactElement; +} + +interface I18nNumberValuesShape { + values: number[]; + children: (x: ReactChild[]) => ReactElement; +} + +type I18nNumberProps = ExclusiveUnion; + +function hasValues(x: I18nNumberProps): x is I18nNumberValuesShape { + return x.values != null; +} + +const I18nNumber: React.SFC = (props) => ( + + { + (i18nConfig) => { + const formatNumber = i18nConfig.formatNumber || defaultFormatNumber; + + if (hasValues(props)) { + return props.children(props.values.map(value => formatNumber(value))); + } + + const formattedValue = (formatNumber || defaultFormatNumber)(props.value); + if (props.children) { + return props.children(formattedValue); + } else { + return formattedValue; + } + } + } + +); + +export { I18nNumber }; diff --git a/src/components/i18n/index.ts b/src/components/i18n/index.ts index 663e6665060..22be80a856c 100644 --- a/src/components/i18n/index.ts +++ b/src/components/i18n/index.ts @@ -1 +1,2 @@ -export {I18n} from './i18n'; +export { I18n } from './i18n'; +export { I18nNumber } from './i18n_number'; diff --git a/src/components/index.js b/src/components/index.js index 53c13b2dbba..177b6ab353c 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -188,6 +188,7 @@ export { export { I18n, + I18nNumber, } from './i18n'; export { From 20ef6eae6c946c0fa995b02c46e4e282f25d2f6e Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 9 Jan 2019 11:02:49 -0700 Subject: [PATCH 05/15] wip --- src-docs/src/views/context/context.js | 45 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src-docs/src/views/context/context.js b/src-docs/src/views/context/context.js index 130b9cf4dda..26e92a7ff02 100644 --- a/src-docs/src/views/context/context.js +++ b/src-docs/src/views/context/context.js @@ -3,8 +3,10 @@ import React, { Component, Fragment } from 'react'; import { EuiContext, EuiButton, - EuiButtonEmpty, EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, EuiSpacer, I18n, I18nNumber, @@ -12,6 +14,8 @@ import { const mappings = { fr: { + english: 'Anglais', + french: 'Française', greeting: 'Salutations!', guestNo: 'Vous êtes invité #', question: 'Quel est votre nom?', @@ -37,8 +41,19 @@ export default class extends Component { return (
- this.setLanguage('en')}>English - this.setLanguage('fr')}>French + + + this.setLanguage('en')}> + + + + + + this.setLanguage('fr')}> + + + + @@ -50,17 +65,23 @@ export default class extends Component { - {question =>

{question}

}
+ + {([question, action]) => ( + + - + + {placeholder => ( + + )} + - - {([placeholder, action]) => ( - - + {action} From 542fecdfcb9227a98bbc0c594c668db28a116cc1 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 9 Jan 2019 12:16:35 -0700 Subject: [PATCH 06/15] Rename I18n to EuiI18n, updated EuiTablePagination to use EuiI18n --- src-docs/src/views/context/context.js | 20 +++++++++---------- src/components/i18n/i18n.tsx | 8 ++++---- src/components/i18n/i18n_number.tsx | 12 +++++------ src/components/i18n/index.ts | 4 ++-- src/components/index.js | 4 ++-- .../table_pagination/table_pagination.js | 3 ++- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src-docs/src/views/context/context.js b/src-docs/src/views/context/context.js index 26e92a7ff02..8bdb0b7506d 100644 --- a/src-docs/src/views/context/context.js +++ b/src-docs/src/views/context/context.js @@ -8,8 +8,8 @@ import { EuiFlexItem, EuiFormRow, EuiSpacer, - I18n, - I18nNumber, + EuiI18n, + EuiI18nNumber, } from '../../../../src/components'; const mappings = { @@ -44,49 +44,49 @@ export default class extends Component { this.setLanguage('en')}> - + this.setLanguage('fr')}> - + - + -

+

- + {([question, action]) => ( - + {placeholder => ( )} - + {action} )} - +
); diff --git a/src/components/i18n/i18n.tsx b/src/components/i18n/i18n.tsx index d7ef656abc5..4530104d598 100644 --- a/src/components/i18n/i18n.tsx +++ b/src/components/i18n/i18n.tsx @@ -23,13 +23,13 @@ interface I18nTokensShape { children: (x: ReactChild[]) => ReactElement; } -type I18nProps = ExclusiveUnion; +type EuiI18nProps = ExclusiveUnion; -function hasTokens(x: I18nProps): x is I18nTokensShape { +function hasTokens(x: EuiI18nProps): x is I18nTokensShape { return x.tokens != null; } -const I18n: React.SFC = (props) => ( +const EuiI18n: React.SFC = (props) => ( { (i18nConfig) => { @@ -49,4 +49,4 @@ const I18n: React.SFC = (props) => ( ); -export { I18n }; +export { EuiI18n }; diff --git a/src/components/i18n/i18n_number.tsx b/src/components/i18n/i18n_number.tsx index dc04bc839b1..412f43fb5c4 100644 --- a/src/components/i18n/i18n_number.tsx +++ b/src/components/i18n/i18n_number.tsx @@ -7,23 +7,23 @@ function defaultFormatNumber(value: number) { return defaultFormatter.format(value); } -interface I18nNumberValueShape { +interface EuiI18nNumberValueShape { value: number; children?: (x: ReactChild) => ReactElement; } -interface I18nNumberValuesShape { +interface EuiI18nNumberValuesShape { values: number[]; children: (x: ReactChild[]) => ReactElement; } -type I18nNumberProps = ExclusiveUnion; +type EuiI18nNumberProps = ExclusiveUnion; -function hasValues(x: I18nNumberProps): x is I18nNumberValuesShape { +function hasValues(x: EuiI18nNumberProps): x is EuiI18nNumberValuesShape { return x.values != null; } -const I18nNumber: React.SFC = (props) => ( +const EuiI18nNumber: React.SFC = (props) => ( { (i18nConfig) => { @@ -44,4 +44,4 @@ const I18nNumber: React.SFC = (props) => ( ); -export { I18nNumber }; +export { EuiI18nNumber }; diff --git a/src/components/i18n/index.ts b/src/components/i18n/index.ts index 22be80a856c..900959c7cae 100644 --- a/src/components/i18n/index.ts +++ b/src/components/i18n/index.ts @@ -1,2 +1,2 @@ -export { I18n } from './i18n'; -export { I18nNumber } from './i18n_number'; +export { EuiI18n } from './i18n'; +export { EuiI18nNumber } from './i18n_number'; diff --git a/src/components/index.js b/src/components/index.js index 177b6ab353c..62d9693d061 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -187,8 +187,8 @@ export { } from './image'; export { - I18n, - I18nNumber, + EuiI18n, + EuiI18nNumber, } from './i18n'; export { diff --git a/src/components/table/table_pagination/table_pagination.js b/src/components/table/table_pagination/table_pagination.js index cccbf78d0f8..3b84ef4c313 100644 --- a/src/components/table/table_pagination/table_pagination.js +++ b/src/components/table/table_pagination/table_pagination.js @@ -8,6 +8,7 @@ import { EuiContextMenuItem, EuiContextMenuPanel } from '../../context_menu'; import { EuiFlexGroup, EuiFlexItem } from '../../flex'; import { EuiPagination } from '../../pagination'; import { EuiPopover } from '../../popover'; +import { EuiI18n } from '../../i18n'; export class EuiTablePagination extends Component { constructor(props) { @@ -49,7 +50,7 @@ export class EuiTablePagination extends Component { iconSide="right" onClick={this.onButtonClick} > - {`Rows per page: ${itemsPerPage}`} + : {itemsPerPage} ); From 8b0816f0bb37fce5758c3ff9ccc48ad4bde4834a Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 9 Jan 2019 13:57:08 -0700 Subject: [PATCH 07/15] Fix renamed import --- src-docs/src/views/context/context_example.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-docs/src/views/context/context_example.js b/src-docs/src/views/context/context_example.js index 057928f54dc..2308cb6fe51 100644 --- a/src-docs/src/views/context/context_example.js +++ b/src-docs/src/views/context/context_example.js @@ -9,7 +9,7 @@ import { import { EuiCode, EuiContext, - I18n, + EuiI18n, } from '../../../../src/components'; import Context from './context'; @@ -35,6 +35,6 @@ export const ContextExample = { ), components: { EuiContext }, demo: , - props: { EuiContext, I18n }, + props: { EuiContext, EuiI18n }, }], }; From 278cd308b1b7404b173a27f7c551a7c79b8fc85b Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 11 Jan 2019 13:55:38 -0700 Subject: [PATCH 08/15] Update proptypes-from-ts-props understanding of ExclusiveUnion --- .../babel/proptypes-from-ts-props/index.js | 158 +++++++++++++++--- .../proptypes-from-ts-props/index.test.js | 6 +- 2 files changed, 134 insertions(+), 30 deletions(-) diff --git a/scripts/babel/proptypes-from-ts-props/index.js b/scripts/babel/proptypes-from-ts-props/index.js index 68db9adeff5..d5a75d5854e 100644 --- a/scripts/babel/proptypes-from-ts-props/index.js +++ b/scripts/babel/proptypes-from-ts-props/index.js @@ -127,6 +127,7 @@ function resolveIdentifierToPropTypes(node, state) { ); // PropTypes.node + case 'ReactChild': case 'ReactNode': return types.memberExpression( types.identifier('PropTypes'), @@ -139,7 +140,36 @@ function resolveIdentifierToPropTypes(node, state) { if (identifier.name === 'ExclusiveUnion') { // We use ExclusiveUnion at the top level to exclusively discriminate between types // propTypes itself must be an object so merge the union sets together as an intersection - return getPropTypesForNode( + + // Any types that are optional or non-existant on one side must be optional after the union + const aPropType = getPropTypesForNode(node.typeParameters.params[0], true, state); + const bPropType = getPropTypesForNode(node.typeParameters.params[1], true, state); + + const propsOnA = types.isCallExpression(aPropType) ? aPropType.arguments[0].properties : []; + const propsOnB = types.isCallExpression(bPropType) ? bPropType.arguments[0].properties : []; + + // optional props is any prop that is optional or non-existant on one side + const optionalProps = new Set(); + for (let i = 0; i < propsOnA.length; i++) { + const property = propsOnA[i]; + const propertyName = property.key.name; + const isOptional = !isPropTypeRequired(types, property.value); + const existsOnB = propsOnB.find(property => property.key.name === propertyName) != null; + if (isOptional || !existsOnB) { + optionalProps.add(propertyName); + } + } + for (let i = 0; i < propsOnB.length; i++) { + const property = propsOnB[i]; + const propertyName = property.key.name; + const isOptional = !isPropTypeRequired(types, property.value); + const existsOnA = propsOnA.find(property => property.key.name === propertyName) != null; + if (isOptional || !existsOnA) { + optionalProps.add(propertyName); + } + } + + const propTypes = getPropTypesForNode( { type: 'TSIntersectionType', types: node.typeParameters.params, @@ -147,6 +177,19 @@ function resolveIdentifierToPropTypes(node, state) { true, state ); + + if (types.isCallExpression(propTypes)) { + // apply the optionals + const properties = propTypes.arguments[0].properties; + for (let i = 0; i < properties.length; i++) { + const property = properties[i]; + if (optionalProps.has(property.key.name)) { + property.value = makePropTypeOptional(types, property.value); + } + } + } + + return propTypes; } // Lookup this identifier from types/interfaces defined in code @@ -172,6 +215,41 @@ function buildPropTypePrimitiveExpression(types, typeName) { ); } +function isPropTypeRequired(types, propType) { + return types.isMemberExpression(propType) && + types.isIdentifier(propType.property) && + propType.property.name === 'isRequired'; +} + +function makePropTypeRequired(types, propType) { + return types.memberExpression( + propType, + types.identifier('isRequired') + ); +} + +function makePropTypeOptional(types, propType) { + if (isPropTypeRequired(types, propType)) { + // strip the .isRequired member expression + return propType.object; + } + return propType; +} + +function areExpressionsIdentical(a, b) { + const aCode = babelCore.transformFromAst(babelCore.types.program([ + babelCore.types.expressionStatement( + babelCore.types.removeComments(babelCore.types.cloneDeep(a)) + ) + ])).code; + const bCode = babelCore.transformFromAst(babelCore.types.program([ + babelCore.types.expressionStatement( + babelCore.types.removeComments(babelCore.types.cloneDeep(b)) + ) + ])).code; + return aCode === bCode; +} + /** * Heavy lifter to generate the proptype AST for a node. Initially called by `processComponentDeclaration`, * its return value is set as the component's `propTypes` value. This function calls itself recursively to translate @@ -202,31 +280,35 @@ function getPropTypesForNode(node, optional, state) { // translates intersections (Foo & Bar & Baz) to a shape with the types' members (Foo, Bar, Baz) merged together case 'TSIntersectionType': + const usableNodes = node.types.filter(node => { + const nodePropTypes = getPropTypesForNode(node, true, state); + + if ( + types.isMemberExpression(nodePropTypes) && + nodePropTypes.object.name === 'PropTypes' && + nodePropTypes.property.name === 'any' + ) { + return false; + } + + // validate that this resulted in a shape, otherwise we don't know how to extract/merge the values + if ( + !types.isCallExpression(nodePropTypes) || + !types.isMemberExpression(nodePropTypes.callee) || + nodePropTypes.callee.object.name !== 'PropTypes' || + nodePropTypes.callee.property.name !== 'shape' + ) { + return false; + } + + return true; + }); + // merge the resolved proptypes for each intersection member into one object, mergedProperties - const mergedProperties = node.types.reduce( + const mergedProperties = usableNodes.reduce( (mergedProperties, node) => { const nodePropTypes = getPropTypesForNode(node, true, state); - // if this propType is PropTypes.any there is nothing to do here - if ( - types.isMemberExpression(nodePropTypes) && - nodePropTypes.object.name === 'PropTypes' && - nodePropTypes.property.name === 'any' - ) { - return mergedProperties; - } - - // validate that this resulted in a shape, otherwise we don't know how to extract/merge the values - if ( - !types.isCallExpression(nodePropTypes) || - !types.isMemberExpression(nodePropTypes.callee) || - nodePropTypes.callee.object.name !== 'PropTypes' || - nodePropTypes.callee.property.name !== 'shape' - ) { - return mergedProperties; - // throw new Error('Cannot process an encountered type intersection'); - } - // iterate over this type's members, adding them (and their comments) to `mergedProperties` const typeProperties = nodePropTypes.arguments[0].properties; // properties on the ObjectExpression passed to PropTypes.shape() for (let i = 0; i < typeProperties.length; i++) { @@ -237,7 +319,32 @@ function getPropTypesForNode(node, optional, state) { ...(typeProperty.leadingComments || []), ...((mergedProperties[typeProperty.key.name] ? mergedProperties[typeProperty.key.name].leadingComments : null) || []), ]; - mergedProperties[typeProperty.key.name] = typeProperty.value; + + // if this property has already been found, the only action is to potentially change it to optional + if (mergedProperties.hasOwnProperty(typeProperty.key.name)) { + const existing = mergedProperties[typeProperty.key.name]; + if (!areExpressionsIdentical(existing, typeProperty.value)) { + mergedProperties[typeProperty.key.name] = types.callExpression( + types.memberExpression( + types.identifier('PropTypes'), + types.identifier('oneOfType'), + ), + [ + types.arrayExpression( + [existing, typeProperty.value] + ) + ] + ); + + if (isPropTypeRequired(types, existing) && isPropTypeRequired(types, typeProperty.value)) { + mergedProperties[typeProperty.key.name] = makePropTypeRequired(types, mergedProperties[typeProperty.key.name]); + } + } + } else { + // property hasn't been seen yet, add it + mergedProperties[typeProperty.key.name] = typeProperty.value; + } + mergedProperties[typeProperty.key.name].leadingComments = leadingComments; } @@ -551,10 +658,7 @@ function getPropTypesForNode(node, optional, state) { if (optional) { return propType; } else { - return types.memberExpression( - propType, - types.identifier('isRequired') - ); + return makePropTypeRequired(types, propType); } } diff --git a/scripts/babel/proptypes-from-ts-props/index.test.js b/scripts/babel/proptypes-from-ts-props/index.test.js index 77a4b7d88f1..e6bea1f615b 100644 --- a/scripts/babel/proptypes-from-ts-props/index.test.js +++ b/scripts/babel/proptypes-from-ts-props/index.test.js @@ -984,7 +984,7 @@ import React from 'react'; export type ExclusiveUnion = any; interface BaseProps { asdf: boolean } interface IFooProps extends BaseProps {d: number, foo?: string} -interface IBarProps extends BaseProps {d: string, bar?: string} +interface IBarProps extends BaseProps {d: string, foo: string, bar: string} const FooComponent: React.SFC> = () => { return (
Hello World
); }`, @@ -999,8 +999,8 @@ const FooComponent = () => { }; FooComponent.propTypes = { - d: PropTypes.string.isRequired, - foo: PropTypes.string, + d: PropTypes.oneOfType([PropTypes.number.isRequired, PropTypes.string.isRequired]).isRequired, + foo: PropTypes.oneOfType([PropTypes.string, PropTypes.string.isRequired]), asdf: PropTypes.bool.isRequired, bar: PropTypes.string };`); From f979558f5d5798b31de7abaf3ed432b45ed67e6b Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 11 Jan 2019 14:14:11 -0700 Subject: [PATCH 09/15] Update enzyme react adapter --- package.json | 2 +- scripts/jest/setup/enzyme.js | 2 +- .../in_memory_table.test.js.snap | 16 +++++- ...eld_value_toggle_group_filter.test.js.snap | 32 ++++++++--- yarn.lock | 57 ++++++++++++------- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 7b2e68b9f46..fda5c6fd942 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "cssnano": "^4.0.5", "dts-generator": "^2.1.0", "enzyme": "^3.1.0", - "enzyme-adapter-react-16": "^1.0.2", + "enzyme-adapter-react-16.3": "^1.4.1", "enzyme-to-json": "^3.3.0", "eslint": "^4.9.0", "eslint-config-prettier": "^2.9.0", diff --git a/scripts/jest/setup/enzyme.js b/scripts/jest/setup/enzyme.js index 82edfc9e5ad..7c4def46489 100644 --- a/scripts/jest/setup/enzyme.js +++ b/scripts/jest/setup/enzyme.js @@ -1,4 +1,4 @@ import { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; +import Adapter from 'enzyme-adapter-react-16.3'; configure({ adapter: new Adapter() }); diff --git a/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap b/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap index d5b85d37573..1b02e14568a 100644 --- a/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap +++ b/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap @@ -282,7 +282,12 @@ exports[`EuiInMemoryTable behavior pagination 1`] = ` size="xs" type="button" > - Rows per page: 2 + + : + 2 } closePopover={[Function]} @@ -365,7 +370,14 @@ exports[`EuiInMemoryTable behavior pagination 1`] = ` - Rows per page: 2 + + Rows per page + + : + 2 diff --git a/src/components/search_bar/filters/__snapshots__/field_value_toggle_group_filter.test.js.snap b/src/components/search_bar/filters/__snapshots__/field_value_toggle_group_filter.test.js.snap index ca46513be20..f9694849c33 100644 --- a/src/components/search_bar/filters/__snapshots__/field_value_toggle_group_filter.test.js.snap +++ b/src/components/search_bar/filters/__snapshots__/field_value_toggle_group_filter.test.js.snap @@ -11,7 +11,9 @@ Array [ noDivider={true} onClick={[Function]} type="button" - />, + > + Kibana + , , + > + Elasticsearch + , ] `; @@ -36,7 +40,9 @@ Array [ noDivider={true} onClick={[Function]} type="button" - />, + > + -Kibana + , , + > + Elasticsearch + , ] `; @@ -61,7 +69,9 @@ Array [ noDivider={true} onClick={[Function]} type="button" - />, + > + Not Kibana + , , + > + Elasticsearch + , ] `; @@ -86,7 +98,9 @@ Array [ noDivider={true} onClick={[Function]} type="button" - />, + > + Kibana + , , + > + Elasticsearch + , ] `; diff --git a/yarn.lock b/yarn.lock index cb50cec5d39..dce4007a1c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4278,27 +4278,29 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -enzyme-adapter-react-16@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4" - integrity sha512-kC8pAtU2Jk3OJ0EG8Y2813dg9Ol0TXi7UNxHzHiWs30Jo/hj7alc//G1YpKUsPP1oKl9X+Lkx+WlGJpPYA+nvw== +enzyme-adapter-react-16.3@^16.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16.3/-/enzyme-adapter-react-16.3-1.4.1.tgz#7da00e529ddecf62aafd4f7cda132c13f18c99ee" + integrity sha512-5jhavjTSid0KqW0pPKDZV3CpNX3Pfw6Urwbz/Lt8k1iX5qnxh+7hbICjbEK9IGh5FeMQMO5VGOpmFk77C+EL/A== dependencies: - enzyme-adapter-utils "^1.3.0" - lodash "^4.17.4" - object.assign "^4.0.4" + enzyme-adapter-utils "^1.9.0" + function.prototype.name "^1.1.0" + object.assign "^4.1.0" object.values "^1.0.4" - prop-types "^15.6.0" + prop-types "^15.6.2" + react-is "^16.6.1" react-reconciler "^0.7.0" - react-test-renderer "^16.0.0-0" + react-test-renderer "~16.3.0-0" -enzyme-adapter-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz#d6c85756826c257a8544d362cc7a67e97ea698c7" - integrity sha512-vVXSt6uDv230DIv+ebCG66T1Pm36Kv+m74L1TrF4kaE7e1V7Q/LcxO0QRkajk5cA6R3uu9wJf5h13wOTezTbjA== +enzyme-adapter-utils@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.9.1.tgz#68196fdaf2a9f51f31603cbae874618661233d72" + integrity sha512-LWc88BbKztLXlpRf5Ba/pSMJRaNezAwZBvis3N/IuB65ltZEh2E2obWU9B36pAbw7rORYeBUuqc79OL17ZzN1A== dependencies: - lodash "^4.17.4" - object.assign "^4.0.4" - prop-types "^15.6.0" + function.prototype.name "^1.1.0" + object.assign "^4.1.0" + prop-types "^15.6.2" + semver "^5.6.0" enzyme-to-json@^3.3.0: version "3.3.1" @@ -5597,7 +5599,7 @@ function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.0.3: +function.prototype.name@^1.0.3, function.prototype.name@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327" integrity sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg== @@ -9468,7 +9470,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.0.3, object.assign@^4.0.4, object.assign@^4.1.0: +object.assign@^4.0.3, object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== @@ -10905,7 +10907,7 @@ prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.6.0: loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.5.8: +prop-types@^15.5.8, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== @@ -11207,6 +11209,11 @@ react-input-autosize@^2.2.1: dependencies: prop-types "^15.5.8" +react-is@^16.3.2, react-is@^16.6.1: + version "16.7.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" + integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g== + react-motion@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316" @@ -11256,7 +11263,7 @@ react-router@^3.2.0: prop-types "^15.5.6" warning "^3.0.0" -react-test-renderer@^16.0.0-0, react-test-renderer@^16.2.0: +react-test-renderer@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211" integrity sha512-Kd4gJFtpNziR9ElOE/C23LeflKLZPRpNQYWP3nQBY43SJ5a+xyEGSeMrm2zxNKXcnCbBS/q1UpD9gqd5Dv+rew== @@ -11265,6 +11272,16 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.2.0: object-assign "^4.1.1" prop-types "^15.6.0" +react-test-renderer@~16.3.0-0: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.2.tgz#3d1ed74fda8db42521fdf03328e933312214749a" + integrity sha512-lL8WHIpCTMdSe+CRkt0rfMxBkJFyhVrpdQ54BaJRIrXf9aVmbeHbRA8GFRpTvohPN5tPzMabmrzW2PUfWCfWwQ== + dependencies: + fbjs "^0.8.16" + object-assign "^4.1.1" + prop-types "^15.6.0" + react-is "^16.3.2" + react-virtualized@^9.18.5: version "9.18.5" resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.18.5.tgz#42dd390ebaa7ea809bfcaf775d39872641679b89" From 88890c9bcc52e0b41c6446d100228955ab0ee8c0 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Mon, 14 Jan 2019 08:32:22 -0700 Subject: [PATCH 10/15] update reference to enyzme adapter --- src-docs/src/services/string/render_to_html.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-docs/src/services/string/render_to_html.js b/src-docs/src/services/string/render_to_html.js index 1cd47b401c0..f632809b77b 100644 --- a/src-docs/src/services/string/render_to_html.js +++ b/src-docs/src/services/string/render_to_html.js @@ -5,7 +5,7 @@ import { configure } from 'enzyme'; -import EnzymeAdapter from 'enzyme-adapter-react-16'; +import EnzymeAdapter from 'enzyme-adapter-react-16.3'; import html from 'html'; From 7158137d95555ec8b1ae55e95ab09563ad2116fd Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Tue, 15 Jan 2019 14:01:09 -0700 Subject: [PATCH 11/15] modified yarn.lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 3136e69c34b..a18daba0bdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4275,7 +4275,7 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -enzyme-adapter-react-16.3@^16.4.1: +enzyme-adapter-react-16.3@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16.3/-/enzyme-adapter-react-16.3-1.4.1.tgz#7da00e529ddecf62aafd4f7cda132c13f18c99ee" integrity sha512-5jhavjTSid0KqW0pPKDZV3CpNX3Pfw6Urwbz/Lt8k1iX5qnxh+7hbICjbEK9IGh5FeMQMO5VGOpmFk77C+EL/A== From e0f04737e49cdf6bddf2c5acc11dfa7a1f5d99a7 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 16 Jan 2019 11:01:00 -0700 Subject: [PATCH 12/15] update I18n token pagination.rowsPerPage -> euiTablePagination.rowsPerPage --- src/components/table/table_pagination/table_pagination.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/table/table_pagination/table_pagination.js b/src/components/table/table_pagination/table_pagination.js index 3b84ef4c313..002f75a6351 100644 --- a/src/components/table/table_pagination/table_pagination.js +++ b/src/components/table/table_pagination/table_pagination.js @@ -50,7 +50,7 @@ export class EuiTablePagination extends Component { iconSide="right" onClick={this.onButtonClick} > - : {itemsPerPage} + : {itemsPerPage} ); From f52649f1536dce6bed994beaada898cf210e22d4 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 16 Jan 2019 14:43:40 -0700 Subject: [PATCH 13/15] Simple docs page for EuiI18n --- src-docs/src/routes.js | 4 ++ src-docs/src/views/i18n/i18n_basic.js | 16 +++++ src-docs/src/views/i18n/i18n_example.js | 80 ++++++++++++++++++++++ src-docs/src/views/i18n/i18n_multi.js | 25 +++++++ src-docs/src/views/i18n/i18n_renderprop.js | 22 ++++++ 5 files changed, 147 insertions(+) create mode 100644 src-docs/src/views/i18n/i18n_basic.js create mode 100644 src-docs/src/views/i18n/i18n_example.js create mode 100644 src-docs/src/views/i18n/i18n_multi.js create mode 100644 src-docs/src/views/i18n/i18n_renderprop.js diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index 95867f00478..db3a82744a4 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -150,6 +150,9 @@ import { HighlightExample } import { HorizontalRuleExample } from './views/horizontal_rule/horizontal_rule_example'; +import { I18nExample } + from './views/i18n/i18n_example'; + import { IconExample } from './views/icon/icon_example'; @@ -418,6 +421,7 @@ const navigation = [{ DelayHideExample, ErrorBoundaryExample, HighlightExample, + I18nExample, IsColorDarkExample, MutationObserverExample, OutsideClickDetectorExample, diff --git a/src-docs/src/views/i18n/i18n_basic.js b/src-docs/src/views/i18n/i18n_basic.js new file mode 100644 index 00000000000..4fa95c923a6 --- /dev/null +++ b/src-docs/src/views/i18n/i18n_basic.js @@ -0,0 +1,16 @@ +import React from 'react'; + +import { + EuiI18n, +} from '../../../../src/components'; + +export default () => { + return ( +

+ +

+ ); +}; diff --git a/src-docs/src/views/i18n/i18n_example.js b/src-docs/src/views/i18n/i18n_example.js new file mode 100644 index 00000000000..598f04025c9 --- /dev/null +++ b/src-docs/src/views/i18n/i18n_example.js @@ -0,0 +1,80 @@ +import React from 'react'; + +import { renderToHtml } from '../../services'; + +import { + GuideSectionTypes, +} from '../../components'; + +import { + EuiCode, + EuiI18n, +} from '../../../../src/components'; + +import I18nBasic from './i18n_basic'; +const i18nBasicSource = require('!!raw-loader!./i18n_basic'); +const i18nBasicHtml = renderToHtml(I18nBasic); + +import I18nRenderProp from './i18n_renderprop'; +const i18nRenderPropSource = require('!!raw-loader!./i18n_renderprop'); +const i18nRenderPropHtml = renderToHtml(I18nRenderProp); + +import I18nMulti from './i18n_multi'; +const I18nMultiSource = require('!!raw-loader!./i18n_multi'); +const I18nMultiHtml = renderToHtml(I18nMulti); + +export const I18nExample = { + title: 'I18n', + sections: [{ + source: [{ + type: GuideSectionTypes.JS, + code: i18nBasicSource, + }, { + type: GuideSectionTypes.HTML, + code: i18nBasicHtml, + }], + text: ( +

+ EuiI18n allows localizing string and numeric values for internationalization. At its simplest, + the component takes token and default props.  + token provides a reference to use when looking for a localized value to render + and default provides the untranslated value. +

+ ), + demo: , + props: { EuiI18n }, + }, { + title: 'As a render prop', + source: [{ + type: GuideSectionTypes.JS, + code: i18nRenderPropSource, + }, { + type: GuideSectionTypes.HTML, + code: i18nRenderPropHtml, + }], + text: ( +

+ Some times a localized value is needed for a prop instead of rendering directly to the DOM. In + these cases EuiI18n can be passed a render prop child which is called with the localized value. +

+ ), + demo: , + }, { + title: 'Multi-value lookup', + source: [{ + type: GuideSectionTypes.JS, + code: I18nMultiSource, + }, { + type: GuideSectionTypes.HTML, + code: I18nMultiHtml, + }], + text: ( +

+ If many localized values are needed in a small area, multiple tokens can be retrieved in a single render prop. + In this case the token/default props are replaced + by the pluralized tokens/defaults. +

+ ), + demo: , + }], +}; diff --git a/src-docs/src/views/i18n/i18n_multi.js b/src-docs/src/views/i18n/i18n_multi.js new file mode 100644 index 00000000000..35a93f4bb49 --- /dev/null +++ b/src-docs/src/views/i18n/i18n_multi.js @@ -0,0 +1,25 @@ +import React from 'react'; + +import { + EuiCard, + EuiCode, + EuiI18n, +} from '../../../../src/components'; + +export default () => { + return ( +
+

+ Both title and description for the card are looked up in one call to EuiI18n +

+ + {([title, description]) => ( + + )} + +
+ ); +}; diff --git a/src-docs/src/views/i18n/i18n_renderprop.js b/src-docs/src/views/i18n/i18n_renderprop.js new file mode 100644 index 00000000000..68e518a25da --- /dev/null +++ b/src-docs/src/views/i18n/i18n_renderprop.js @@ -0,0 +1,22 @@ +import React, { Fragment } from 'react'; + +import { + EuiCode, + EuiFieldText, + EuiI18n, +} from '../../../../src/components'; + +export default () => { + return ( + +

+ This text field's placeholder reads from i18n.renderpropexample +

+
+ + {placeholderName => } + +
+
+ ); +}; From e3355c6077138caee37631ef16ebd65c34f76e99 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 16 Jan 2019 15:29:15 -0700 Subject: [PATCH 14/15] Docs for EuiI18nNumber --- src-docs/src/views/i18n/i18n_example.js | 21 +++++++++++++++++++++ src-docs/src/views/i18n/i18n_number.js | 13 +++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src-docs/src/views/i18n/i18n_number.js diff --git a/src-docs/src/views/i18n/i18n_example.js b/src-docs/src/views/i18n/i18n_example.js index 598f04025c9..3d9db2fba43 100644 --- a/src-docs/src/views/i18n/i18n_example.js +++ b/src-docs/src/views/i18n/i18n_example.js @@ -23,6 +23,10 @@ import I18nMulti from './i18n_multi'; const I18nMultiSource = require('!!raw-loader!./i18n_multi'); const I18nMultiHtml = renderToHtml(I18nMulti); +import I18nNumber from './i18n_number'; +const I18nNumberSource = require('!!raw-loader!./i18n_number'); +const I18nNumberHtml = renderToHtml(I18nNumber); + export const I18nExample = { title: 'I18n', sections: [{ @@ -76,5 +80,22 @@ export const I18nExample = {

), demo: , + }, { + title: 'Number localization', + source: [{ + type: GuideSectionTypes.JS, + code: I18nNumberSource, + }, { + type: GuideSectionTypes.HTML, + code: I18nNumberHtml, + }], + text: ( +

+ EuiI18nNumber can be used to format one or more numbers. Similarly + to EuiI18n, it takes value or + values and can render directly to the DOM or call a render prop. +

+ ), + demo: , }], }; diff --git a/src-docs/src/views/i18n/i18n_number.js b/src-docs/src/views/i18n/i18n_number.js new file mode 100644 index 00000000000..d1b5775216b --- /dev/null +++ b/src-docs/src/views/i18n/i18n_number.js @@ -0,0 +1,13 @@ +import React from 'react'; + +import { + EuiI18nNumber, +} from '../../../../src/components'; + +export default () => { + return ( +

+ Formatted count of users: +

+ ); +}; From fcb71f187c09774901f8e25dd314ea2722ac1dfb Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 16 Jan 2019 15:35:33 -0700 Subject: [PATCH 15/15] update snapshot --- .../basic_table/__snapshots__/in_memory_table.test.js.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap b/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap index 1b02e14568a..266a20f8453 100644 --- a/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap +++ b/src/components/basic_table/__snapshots__/in_memory_table.test.js.snap @@ -284,7 +284,7 @@ exports[`EuiInMemoryTable behavior pagination 1`] = ` > : 2 @@ -372,7 +372,7 @@ exports[`EuiInMemoryTable behavior pagination 1`] = ` > Rows per page