From ddedc83e081aab796f7ab4fec7cc3a01ba123f0d Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Mon, 30 Aug 2021 13:54:35 +0200 Subject: [PATCH 1/4] feat(Multiselect): add itemToElement to Multiselect --- .../MultiSelect/FilterableMultiSelect.js | 20 +++++++- .../MultiSelect/MultiSelect-story.js | 46 +++++++++++++++++++ .../src/components/MultiSelect/MultiSelect.js | 17 ++++++- 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js index 2b5df5ad53eb..ee0260cff312 100644 --- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js +++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js @@ -71,6 +71,12 @@ export default class FilterableMultiSelect extends React.Component { */ invalidText: PropTypes.node, + /** + * Function to render items as custom components instead of strings. + * Defaults to null and is overridden by a getter + */ + itemToElement: PropTypes.func, + /** * Helper function passed to downshift that allows the library to render a * given item to a string label. By default, it extracts the `label` field @@ -175,6 +181,7 @@ export default class FilterableMultiSelect extends React.Component { filterItems: defaultFilterItems, initialSelectedItems: [], itemToString: defaultItemToString, + itemToElement: null, locale: 'en', sortItems: defaultSortItems, light: false, @@ -287,6 +294,7 @@ export default class FilterableMultiSelect extends React.Component { disabled, filterItems, items, + itemToElement, itemToString, titleText, helperText, @@ -310,6 +318,9 @@ export default class FilterableMultiSelect extends React.Component { const inline = type === 'inline'; const showWarning = !invalid && warn; + // needs to be capitalized for react to render it correctly + const ItemToElement = itemToElement; + const wrapperClasses = cx( `${prefix}--multi-select__wrapper`, `${prefix}--list-box__wrapper`, @@ -561,7 +572,14 @@ export default class FilterableMultiSelect extends React.Component { className={`${prefix}--checkbox-label`} data-contained-checkbox-state={isChecked} id={`${itemProps.id}-item`}> - {itemText} + {itemToElement ? ( + + ) : ( + itemToString(item) + )} diff --git a/packages/react/src/components/MultiSelect/MultiSelect-story.js b/packages/react/src/components/MultiSelect/MultiSelect-story.js index 97303f5660ae..b83299725350 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect-story.js +++ b/packages/react/src/components/MultiSelect/MultiSelect-story.js @@ -141,6 +141,52 @@ export const Default = withReadme(readme, () => { ); }); +export const ItemToElement = withReadme(readme, () => { + return ( +
+ (item ? item.text : '')} + itemToElement={(item) => + item ? ( + + {item.text}{' '} + + {' '} + 🔥 + + + ) : ( + '' + ) + } + /> +
+ (item ? item.text : '')} + itemToElement={(item) => + item ? ( + + {item.text}{' '} + + {' '} + 🔥 + + + ) : ( + '' + ) + } + /> +
+ ); +}); + Default.storyName = 'default'; Default.parameters = { diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index 231abe29df4b..ede001c49b48 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -41,6 +41,7 @@ const MultiSelect = React.forwardRef(function MultiSelect( className: containerClassName, id, items, + itemToElement, itemToString, titleText, helperText, @@ -155,6 +156,9 @@ const MultiSelect = React.forwardRef(function MultiSelect( [`${prefix}--list-box--up`]: direction === 'top', }); + // needs to be capitalized for react to render it correctly + const ItemToElement = itemToElement; + const sortOptions = { selectedItems: controlledSelectedItems, itemToString, @@ -284,7 +288,11 @@ const MultiSelect = React.forwardRef(function MultiSelect( className={`${prefix}--checkbox-label`} data-contained-checkbox-state={isChecked} id={`${itemProps.id}__checkbox`}> - {itemText} + {itemToElement ? ( + + ) : ( + itemToString(item) + )} @@ -351,6 +359,12 @@ MultiSelect.propTypes = { */ invalidText: PropTypes.node, + /** + * Function to render items as custom components instead of strings. + * Defaults to null and is overridden by a getter + */ + itemToElement: PropTypes.func, + /** * Helper function passed to downshift that allows the library to render a * given item to a string label. By default, it extracts the `label` field @@ -447,6 +461,7 @@ MultiSelect.defaultProps = { compareItems: defaultCompareItems, disabled: false, locale: 'en', + itemToElement: null, itemToString: defaultItemToString, initialSelectedItems: [], sortItems: defaultSortItems, From 9c71d846430972a1c6aae0a9199e6ef3e348dd81 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Mon, 30 Aug 2021 14:16:27 +0200 Subject: [PATCH 2/4] test(Multiselect): update snapshots, add new test for itemToElement --- .../__snapshots__/PublicAPI-test.js.snap | 12 +++++++ .../MultiSelect/__tests__/MultiSelect-test.js | 32 +++++++++++++++++++ .../FilterableMultiSelect-test.js.snap | 1 + 3 files changed, 45 insertions(+) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 8e6a87d2662a..3e2ed78353a2 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -2888,6 +2888,7 @@ Map { "disabled": false, "filterItems": [Function], "initialSelectedItems": Array [], + "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", @@ -3052,6 +3053,9 @@ Map { "invalidText": Object { "type": "node", }, + "itemToElement": Object { + "type": "func", + }, "itemToString": Object { "type": "func", }, @@ -3818,6 +3822,7 @@ Map { "disabled": false, "filterItems": [Function], "initialSelectedItems": Array [], + "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", @@ -3982,6 +3987,9 @@ Map { "invalidText": Object { "type": "node", }, + "itemToElement": Object { + "type": "func", + }, "itemToString": Object { "type": "func", }, @@ -4054,6 +4062,7 @@ Map { "direction": "bottom", "disabled": false, "initialSelectedItems": Array [], + "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", @@ -4223,6 +4232,9 @@ Map { "invalidText": Object { "type": "node", }, + "itemToElement": Object { + "type": "func", + }, "itemToString": Object { "type": "func", }, diff --git a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js index 7d512303d656..091edd89eb16 100644 --- a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js +++ b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js @@ -311,6 +311,38 @@ describe('MultiSelect', () => { expect(getByText(container, 'marky')).toBeTruthy(); }); + it('should support a custom itemToElement', () => { + const items = [{ text: 'test-item' }]; + const label = 'test-label'; + const { container } = render( + (item ? item.text : '')} + itemToElement={(item) => + item ? ( + + {item.text}{' '} + + {' '} + 🔥 + + + ) : ( + '' + ) + } + /> + ); + + const labelNode = getByText(container, label); + Simulate.click(labelNode); + + expect(document.querySelector('.test-element')).toBeTruthy(); + expect(document.querySelector('span[role="img"]')).toBeTruthy(); + }); + it('should support custom translation with translateWithId', () => { const items = generateItems(4, generateGenericItem); const label = 'test-label'; diff --git a/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap b/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap index 92728708ec62..c2c587fe108f 100644 --- a/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap +++ b/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap @@ -9,6 +9,7 @@ exports[`FilterableMultiSelect should render 1`] = ` filterItems={[Function]} id="test-filterable-multiselect" initialSelectedItems={Array []} + itemToElement={null} itemToString={[Function]} items={ Array [ From e1a81682b7e422e39924a54e78609a4db874dbb7 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Mon, 30 Aug 2021 14:27:18 +0200 Subject: [PATCH 3/4] fix(MultiSelect): use existing variable --- .../react/src/components/MultiSelect/FilterableMultiSelect.js | 2 +- packages/react/src/components/MultiSelect/MultiSelect.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js index ee0260cff312..ac76bd465d30 100644 --- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js +++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js @@ -578,7 +578,7 @@ export default class FilterableMultiSelect extends React.Component { {...item} /> ) : ( - itemToString(item) + itemText )} diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index ede001c49b48..07d347fe5eaf 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -291,7 +291,7 @@ const MultiSelect = React.forwardRef(function MultiSelect( {itemToElement ? ( ) : ( - itemToString(item) + itemText )} From bff08f4f317f380a0a911b4cb89ed475f453242a Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Tue, 31 Aug 2021 17:56:48 +0200 Subject: [PATCH 4/4] fix(MultiSelect): remove itemToElement defaultProp --- .../__tests__/__snapshots__/grid-test.js.snap | 9 ++++--- .../__snapshots__/PublicAPI-test.js.snap | 24 +++++++++++++++++++ .../__snapshots__/PublicAPI-test.js.snap | 3 --- .../MultiSelect/FilterableMultiSelect.js | 1 - .../src/components/MultiSelect/MultiSelect.js | 1 - .../FilterableMultiSelect-test.js.snap | 1 - 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/components/src/globals/grid/__tests__/__snapshots__/grid-test.js.snap b/packages/components/src/globals/grid/__tests__/__snapshots__/grid-test.js.snap index 200b0e05a0d3..2c5c88f01694 100644 --- a/packages/components/src/globals/grid/__tests__/__snapshots__/grid-test.js.snap +++ b/packages/components/src/globals/grid/__tests__/__snapshots__/grid-test.js.snap @@ -1,7 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`_grid.scss should generate grid code when the grid feature flag is on 1`] = ` -"h1 { +"/* stylelint-disable number-max-precision */ +h1 { font-size: 2.625rem; font-weight: 300; line-height: 1.199; @@ -16,7 +17,7 @@ h2 { h3 { font-size: 1.75rem; font-weight: 400; - line-height: 1.29; + line-height: 1.28572; letter-spacing: 0; } h4 { @@ -34,7 +35,7 @@ h5 { h6 { font-size: 0.875rem; font-weight: 600; - line-height: 1.29; + line-height: 1.28572; letter-spacing: 0.16px; } p { @@ -49,6 +50,7 @@ a { em { font-style: italic; } +/* stylelint-disable number-max-precision */ @keyframes skeleton { 0% { opacity: 0.3; @@ -81,6 +83,7 @@ em { transform: scaleX(0); transform-origin: left; } } +/* stylelint-disable number-max-precision */ .bx--grid { margin-right: auto; margin-left: auto; diff --git a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap index ad11fb463ce9..8d62e1a6b1db 100644 --- a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -31,6 +31,10 @@ Array [ "blue70", "blue80", "blue90", + "body01", + "body02", + "bodyCompact01", + "bodyCompact02", "bodyLong01", "bodyLong02", "bodyShort01", @@ -124,6 +128,17 @@ Array [ "fieldDisabled", "fieldHover", "fluid", + "fluidDisplay01", + "fluidDisplay02", + "fluidDisplay03", + "fluidDisplay04", + "fluidHeading03", + "fluidHeading04", + "fluidHeading05", + "fluidHeading06", + "fluidParagraph01", + "fluidQuotation01", + "fluidQuotation02", "fluidSpacing", "fluidSpacing01", "fluidSpacing02", @@ -166,6 +181,13 @@ Array [ "green90", "heading01", "heading02", + "heading03", + "heading04", + "heading05", + "heading06", + "heading07", + "headingCompact01", + "headingCompact02", "helperText01", "helperText02", "highlight", @@ -226,6 +248,8 @@ Array [ "layout05", "layout06", "layout07", + "legal01", + "legal02", "link01", "link02", "linkInverse", diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 3e2ed78353a2..501a4d80c4a8 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -2888,7 +2888,6 @@ Map { "disabled": false, "filterItems": [Function], "initialSelectedItems": Array [], - "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", @@ -3822,7 +3821,6 @@ Map { "disabled": false, "filterItems": [Function], "initialSelectedItems": Array [], - "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", @@ -4062,7 +4060,6 @@ Map { "direction": "bottom", "disabled": false, "initialSelectedItems": Array [], - "itemToElement": null, "itemToString": [Function], "light": false, "locale": "en", diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js index ac76bd465d30..21d308b8686a 100644 --- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js +++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js @@ -181,7 +181,6 @@ export default class FilterableMultiSelect extends React.Component { filterItems: defaultFilterItems, initialSelectedItems: [], itemToString: defaultItemToString, - itemToElement: null, locale: 'en', sortItems: defaultSortItems, light: false, diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index 07d347fe5eaf..3b637223af93 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -461,7 +461,6 @@ MultiSelect.defaultProps = { compareItems: defaultCompareItems, disabled: false, locale: 'en', - itemToElement: null, itemToString: defaultItemToString, initialSelectedItems: [], sortItems: defaultSortItems, diff --git a/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap b/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap index c2c587fe108f..92728708ec62 100644 --- a/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap +++ b/packages/react/src/components/MultiSelect/__tests__/__snapshots__/FilterableMultiSelect-test.js.snap @@ -9,7 +9,6 @@ exports[`FilterableMultiSelect should render 1`] = ` filterItems={[Function]} id="test-filterable-multiselect" initialSelectedItems={Array []} - itemToElement={null} itemToString={[Function]} items={ Array [