diff --git a/packages/web/src/components/list/MultiList.d.ts b/packages/web/src/components/list/MultiList.d.ts index 8f2008678..14e484d20 100644 --- a/packages/web/src/components/list/MultiList.d.ts +++ b/packages/web/src/components/list/MultiList.d.ts @@ -26,6 +26,7 @@ export interface MultiList extends CommonProps { selectAllLabel?: string; showCheckbox: boolean; showCount?: boolean; + showItemCount?: boolean; showFilter?: boolean; showSearch?: boolean; size?: number; diff --git a/packages/web/src/components/list/MultiList.js b/packages/web/src/components/list/MultiList.js index 9a933ddbb..b5f8fbea4 100644 --- a/packages/web/src/components/list/MultiList.js +++ b/packages/web/src/components/list/MultiList.js @@ -29,7 +29,7 @@ import { import { replaceDiacritics } from '@appbaseio/reactivecore/lib/utils/suggestions'; import types from '@appbaseio/reactivecore/lib/utils/types'; -import Title from '../../styles/Title'; +import Title, { TitleCount } from '../../styles/Title'; import Input from '../../styles/Input'; import Button, { loadMoreContainer } from '../../styles/Button'; import Container from '../../styles/Container'; @@ -445,6 +445,16 @@ class MultiList extends Component { return listItems; } + /** + * The number of items shown next to the title when `showItemCount` is set. + * Counts the items currently rendered, so it stays in sync with the list as + * `showSearch` narrows it down, and reflects the buckets actually returned + * rather than the requested `size`. + */ + get itemCount() { + return this.listItems.length; + } + getComponent() { const { error, isLoading, rawData } = this.props; const { currentValue } = this.state; @@ -469,6 +479,7 @@ class MultiList extends Component { error, isLoading, showCount, + showItemCount, total, } = this.props; const { isLastBucket } = this.state; @@ -493,6 +504,15 @@ class MultiList extends Component { {this.props.title && ( {this.props.title} + {showItemCount && ( + <TitleCount + className={ + getClassName(this.props.innerClass, 'itemCount') || null + } + > + {this.itemCount} + </TitleCount> + )} )} {this.renderSearch()} @@ -648,6 +668,7 @@ MultiList.propTypes = { selectAllLabel: types.string, showCheckbox: types.boolRequired, showCount: types.bool, + showItemCount: types.bool, showSearch: types.bool, size: types.number, sortBy: types.sortByWithCount, @@ -669,6 +690,7 @@ MultiList.defaultProps = { queryFormat: 'or', showCheckbox: true, showCount: true, + showItemCount: false, showSearch: true, size: 100, sortBy: 'count', diff --git a/packages/web/src/components/list/MultiList.test.js b/packages/web/src/components/list/MultiList.test.js index 302aca791..c2a9bd5c8 100644 --- a/packages/web/src/components/list/MultiList.test.js +++ b/packages/web/src/components/list/MultiList.test.js @@ -161,6 +161,46 @@ it('should use render prop to render the list item', () => { expect(elem).toMatchSnapshot(); }); +it('should render item count next to the title when showItemCount is true', () => { + const elem = renderer + .create( + + + , + ) + .toJSON(); + expect(elem).toMatchSnapshot(); +}); + +it('should not render item count when showItemCount is false', () => { + const elem = renderer + .create( + + + , + ) + .toJSON(); + expect(elem).toMatchSnapshot(); +}); + it('should select default value', () => { const elem = renderer .create( diff --git a/packages/web/src/components/list/SingleList.d.ts b/packages/web/src/components/list/SingleList.d.ts index cc443dea3..9c3da4800 100644 --- a/packages/web/src/components/list/SingleList.d.ts +++ b/packages/web/src/components/list/SingleList.d.ts @@ -24,6 +24,7 @@ export interface SingleList extends CommonProps { transformData?: (...args: any[]) => any; selectAllLabel?: string; showCount?: boolean; + showItemCount?: boolean; showFilter?: boolean; showRadio?: boolean; showSearch?: boolean; diff --git a/packages/web/src/components/list/SingleList.js b/packages/web/src/components/list/SingleList.js index 6ad88fd8c..ae255de5c 100644 --- a/packages/web/src/components/list/SingleList.js +++ b/packages/web/src/components/list/SingleList.js @@ -28,7 +28,7 @@ import { replaceDiacritics } from '@appbaseio/reactivecore/lib/utils/suggestions import types from '@appbaseio/reactivecore/lib/utils/types'; import { componentTypes } from '@appbaseio/reactivecore/lib/utils/constants'; import { getInternalComponentID } from '@appbaseio/reactivecore/lib/utils/transform'; -import Title from '../../styles/Title'; +import Title, { TitleCount } from '../../styles/Title'; import Input from '../../styles/Input'; import Button, { loadMoreContainer } from '../../styles/Button'; import Container from '../../styles/Container'; @@ -340,6 +340,16 @@ class SingleList extends Component { return listItems; } + /** + * The number of items shown next to the title when `showItemCount` is set. + * Counts the items currently rendered, so it stays in sync with the list as + * `showSearch` narrows it down, and reflects the buckets actually returned + * rather than the requested `size`. + */ + get itemCount() { + return this.listItems.length; + } + getComponent() { const { error, isLoading, rawData } = this.props; const { currentValue } = this.state; @@ -363,6 +373,7 @@ class SingleList extends Component { renderError, error, isLoading, + showItemCount, total, } = this.props; const { isLastBucket } = this.state; @@ -390,6 +401,15 @@ class SingleList extends Component { {this.props.title && ( {this.props.title} + {showItemCount && ( + <TitleCount + className={ + getClassName(this.props.innerClass, 'itemCount') || null + } + > + {this.itemCount} + </TitleCount> + )} )} {this.renderSearch()} @@ -535,6 +555,7 @@ SingleList.propTypes = { transformData: types.func, selectAllLabel: types.string, showCount: types.bool, + showItemCount: types.bool, showFilter: types.bool, showRadio: types.boolRequired, showSearch: types.bool, @@ -558,6 +579,7 @@ SingleList.defaultProps = { className: null, placeholder: 'Search', showCount: true, + showItemCount: false, showFilter: true, showRadio: true, showSearch: true, diff --git a/packages/web/src/components/list/SingleList.test.js b/packages/web/src/components/list/SingleList.test.js index 983104295..7cb84e43e 100644 --- a/packages/web/src/components/list/SingleList.test.js +++ b/packages/web/src/components/list/SingleList.test.js @@ -158,6 +158,46 @@ it('should use render prop to render the list item', () => { expect(elem).toMatchSnapshot(); }); +it('should render item count next to the title when showItemCount is true', () => { + const elem = renderer + .create( + + + , + ) + .toJSON(); + expect(elem).toMatchSnapshot(); +}); + +it('should not render item count when showItemCount is false', () => { + const elem = renderer + .create( + + + , + ) + .toJSON(); + expect(elem).toMatchSnapshot(); +}); + it('should select default value', () => { const elem = renderer .create( diff --git a/packages/web/src/components/list/__snapshots__/MultiList.test.js.snap b/packages/web/src/components/list/__snapshots__/MultiList.test.js.snap index b17435686..59260d0b1 100644 --- a/packages/web/src/components/list/__snapshots__/MultiList.test.js.snap +++ b/packages/web/src/components/list/__snapshots__/MultiList.test.js.snap @@ -1,5 +1,320 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`should not render item count when showItemCount is false 1`] = ` +.emotion-0 { + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Noto Sans","Ubuntu","Droid Sans","Helvetica Neue",sans-serif; + font-size: 16px; + color: #424242; + width: 100%; +} + +.emotion-0 input, +.emotion-0 button, +.emotion-0 textarea, +.emotion-0 select { + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Noto Sans","Ubuntu","Droid Sans","Helvetica Neue",sans-serif; +} + +.emotion-0 *, +.emotion-0 *:before, +.emotion-0 *:after { + box-sizing: border-box; +} + +.emotion-4 { + margin: 0 0 8px; + font-size: 1rem; + color: #424242; +} + +.emotion-6 { + width: 100%; + line-height: 1.5; + min-height: 42px; + padding: 8px 12px; + border: 1px solid #ccc; + background-color: #fafafa; + font-size: 0.9rem; + outline: none; +} + +.emotion-6:focus { + background-color: #fff; +} + +.emotion-6[type='search']::-webkit-search-decoration, +.emotion-6[type='search']::-webkit-search-cancel-button, +.emotion-6[type='search']::-webkit-search-results-button, +.emotion-6[type='search']::-webkit-search-results-decoration { + display: none; +} + +.emotion-8 { + list-style: none; + padding: 0; + margin: 0; + max-height: 240px; + position: relative; + overflow-y: auto; + padding-bottom: 12px; +} + +.emotion-8 li { + min-height: 30px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding-left: 2px; +} + +.emotion-10 { + border: 0; + -webkit-clip: rect(1px,1px,1px,1px); + clip: rect(1px,1px,1px,1px); + -webkit-clip-path: inset(50%); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + white-space: nowrap; +} + +.emotion-10:focus+label::before { + box-shadow: 0 0 0 2px #d7e7ff; +} + +.emotion-10:hover+label::before { + border-color: #0B6AFF; +} + +.emotion-10:active+label::before { + -webkit-transition-duration: 0; + transition-duration: 0; +} + +.emotion-10+label { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + height: 100%; + margin: 0.4rem 0; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + cursor: pointer; +} + +.emotion-10+label:hover { + color: #0B6AFF; +} + +.emotion-10+label>span { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + line-height: 1.3rem; +} + +.emotion-10+label>span>span:first-of-type { + padding-right: 5px; +} + +.emotion-10+label>span>span:nth-of-type(2) { + color: #9b9b9b; +} + +.emotion-10+label::before { + background-color: #fff; + border: 1px solid #595959; + box-sizing: content-box; + content: ''; + color: #0B6AFF; + margin-right: calc(16px * 0.5); + top: 50%; + left: 0; + width: calc(16px + 1px); + height: 16px; + display: inline-block; + vertical-align: middle; + margin-top: 2px; +} + +.emotion-10+label::after { + box-sizing: content-box; + content: ''; + background-color: #0B6AFF; + position: absolute; + top: 11px; + left: calc(1px + 4px / 2); + width: calc(16px - 4px); + height: calc(16px - 4px); + margin-top: calc(16px / -2 - 4px / -2); + -webkit-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); + -webkit-transform-origin: 50%; + -ms-transform-origin: 50%; + transform-origin: 50%; + -webkit-transition: -webkit-transform 200ms ease-out; + -webkit-transition: transform 200ms ease-out; + transition: transform 200ms ease-out; +} + +.emotion-10+label::before, +.emotion-10+label::after { + border-radius: 2px; +} + +.emotion-10+label::after { + background-color: transparent; + top: 10px; + left: calc(1px + 16px / 5); + width: calc(16px / 2); + height: calc(16px / 5); + margin-top: calc(16px / -2 / 2 * 0.8); + border-style: solid; + border-color: #fff; + border-width: 0 0 2px 2px; + border-radius: 0; + border-image: none; + -webkit-transform: rotate(-45deg) scale(0); + -ms-transform: rotate(-45deg) scale(0); + transform: rotate(-45deg) scale(0); + -webkit-transition: none; + transition: none; +} + +.emotion-10:checked+label::before { + border-color: #0B6AFF; + background-color: #0B6AFF; +} + +.emotion-10:checked+label::after { + content: ''; + -webkit-transform: rotate(-45deg) scale(1); + -ms-transform: rotate(-45deg) scale(1); + transform: rotate(-45deg) scale(1); + -webkit-transition: -webkit-transform 200ms ease-out; + -webkit-transition: transform 200ms ease-out; + transition: transform 200ms ease-out; +} + +
+
+

+ Authors +

+ + +
+
+`; + exports[`should not render search/count/checkbox when showSearch/showCount/showCheckbox are false 1`] = ` .emotion-0 { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Noto Sans","Ubuntu","Droid Sans","Helvetica Neue",sans-serif; @@ -31,7 +346,322 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC padding-bottom: 12px; } -.emotion-4 li { +.emotion-4 li { + min-height: 30px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding-left: 2px; +} + +.emotion-6 { + border: 0; + -webkit-clip: rect(1px,1px,1px,1px); + clip: rect(1px,1px,1px,1px); + -webkit-clip-path: inset(50%); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + white-space: nowrap; +} + +.emotion-6:focus+label::before { + box-shadow: 0 0 0 2px #d7e7ff; +} + +.emotion-6:hover+label::before { + border-color: #0B6AFF; +} + +.emotion-6:active+label::before { + -webkit-transition-duration: 0; + transition-duration: 0; +} + +.emotion-6+label { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + height: 100%; + margin: 0.4rem 0; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + cursor: pointer; +} + +.emotion-6+label:hover { + color: #0B6AFF; +} + +.emotion-6+label>span { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + line-height: 1.3rem; +} + +.emotion-6+label>span>span:first-of-type { + padding-right: 5px; +} + +.emotion-6+label>span>span:nth-of-type(2) { + color: #9b9b9b; +} + +.emotion-6+label::before { + background-color: #fff; + border: 1px solid #595959; + box-sizing: content-box; + content: ''; + color: #0B6AFF; + margin-right: calc(16px * 0.5); + top: 50%; + left: 0; + width: calc(16px + 1px); + height: 16px; + display: inline-block; + vertical-align: middle; + margin-top: 2px; +} + +.emotion-6+label::after { + box-sizing: content-box; + content: ''; + background-color: #0B6AFF; + position: absolute; + top: 11px; + left: calc(1px + 4px / 2); + width: calc(16px - 4px); + height: calc(16px - 4px); + margin-top: calc(16px / -2 - 4px / -2); + -webkit-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); + -webkit-transform-origin: 50%; + -ms-transform-origin: 50%; + transform-origin: 50%; + -webkit-transition: -webkit-transform 200ms ease-out; + -webkit-transition: transform 200ms ease-out; + transition: transform 200ms ease-out; +} + +.emotion-6+label { + padding-left: 0; +} + +.emotion-6+label::before, +.emotion-6+label::after { + width: 0; + height: 0; + border: 0; + margin: 0; + visibility: hidden; +} + +.emotion-6:checked+label { + font-weight: bold; +} + +.emotion-6+label::before, +.emotion-6+label::after { + border-radius: 2px; +} + +.emotion-6+label::after { + background-color: transparent; + top: 10px; + left: calc(1px + 16px / 5); + width: calc(16px / 2); + height: calc(16px / 5); + margin-top: calc(16px / -2 / 2 * 0.8); + border-style: solid; + border-color: #fff; + border-width: 0 0 2px 2px; + border-radius: 0; + border-image: none; + -webkit-transform: rotate(-45deg) scale(0); + -ms-transform: rotate(-45deg) scale(0); + transform: rotate(-45deg) scale(0); + -webkit-transition: none; + transition: none; +} + +.emotion-6:checked+label::before { + border-color: #0B6AFF; + background-color: #0B6AFF; +} + +.emotion-6:checked+label::after { + content: ''; + -webkit-transform: rotate(-45deg) scale(1); + -ms-transform: rotate(-45deg) scale(1); + transform: rotate(-45deg) scale(1); + -webkit-transition: -webkit-transform 200ms ease-out; + -webkit-transition: transform 200ms ease-out; + transition: transform 200ms ease-out; +} + +
+
+ +
+
+`; + +exports[`should render item count next to the title when showItemCount is true 1`] = ` +.emotion-0 { + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Noto Sans","Ubuntu","Droid Sans","Helvetica Neue",sans-serif; + font-size: 16px; + color: #424242; + width: 100%; +} + +.emotion-0 input, +.emotion-0 button, +.emotion-0 textarea, +.emotion-0 select { + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Noto Sans","Ubuntu","Droid Sans","Helvetica Neue",sans-serif; +} + +.emotion-0 *, +.emotion-0 *:before, +.emotion-0 *:after { + box-sizing: border-box; +} + +.emotion-4 { + margin: 0 0 8px; + font-size: 1rem; + color: #424242; +} + +.emotion-6 { + margin-left: 5px; + font-weight: normal; + color: #9b9b9b; +} + +.emotion-8 { + width: 100%; + line-height: 1.5; + min-height: 42px; + padding: 8px 12px; + border: 1px solid #ccc; + background-color: #fafafa; + font-size: 0.9rem; + outline: none; +} + +.emotion-8:focus { + background-color: #fff; +} + +.emotion-8[type='search']::-webkit-search-decoration, +.emotion-8[type='search']::-webkit-search-cancel-button, +.emotion-8[type='search']::-webkit-search-results-button, +.emotion-8[type='search']::-webkit-search-results-decoration { + display: none; +} + +.emotion-10 { + list-style: none; + padding: 0; + margin: 0; + max-height: 240px; + position: relative; + overflow-y: auto; + padding-bottom: 12px; +} + +.emotion-10 li { min-height: 30px; display: -webkit-box; display: -webkit-flex; @@ -47,7 +677,7 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC padding-left: 2px; } -.emotion-6 { +.emotion-12 { border: 0; -webkit-clip: rect(1px,1px,1px,1px); clip: rect(1px,1px,1px,1px); @@ -61,20 +691,20 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC white-space: nowrap; } -.emotion-6:focus+label::before { +.emotion-12:focus+label::before { box-shadow: 0 0 0 2px #d7e7ff; } -.emotion-6:hover+label::before { +.emotion-12:hover+label::before { border-color: #0B6AFF; } -.emotion-6:active+label::before { +.emotion-12:active+label::before { -webkit-transition-duration: 0; transition-duration: 0; } -.emotion-6+label { +.emotion-12+label { position: relative; -webkit-user-select: none; -moz-user-select: none; @@ -94,11 +724,11 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC cursor: pointer; } -.emotion-6+label:hover { +.emotion-12+label:hover { color: #0B6AFF; } -.emotion-6+label>span { +.emotion-12+label>span { width: 100%; display: -webkit-box; display: -webkit-flex; @@ -114,15 +744,15 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC line-height: 1.3rem; } -.emotion-6+label>span>span:first-of-type { +.emotion-12+label>span>span:first-of-type { padding-right: 5px; } -.emotion-6+label>span>span:nth-of-type(2) { +.emotion-12+label>span>span:nth-of-type(2) { color: #9b9b9b; } -.emotion-6+label::before { +.emotion-12+label::before { background-color: #fff; border: 1px solid #595959; box-sizing: content-box; @@ -138,7 +768,7 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC margin-top: 2px; } -.emotion-6+label::after { +.emotion-12+label::after { box-sizing: content-box; content: ''; background-color: #0B6AFF; @@ -159,29 +789,12 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC transition: transform 200ms ease-out; } -.emotion-6+label { - padding-left: 0; -} - -.emotion-6+label::before, -.emotion-6+label::after { - width: 0; - height: 0; - border: 0; - margin: 0; - visibility: hidden; -} - -.emotion-6:checked+label { - font-weight: bold; -} - -.emotion-6+label::before, -.emotion-6+label::after { +.emotion-12+label::before, +.emotion-12+label::after { border-radius: 2px; } -.emotion-6+label::after { +.emotion-12+label::after { background-color: transparent; top: 10px; left: calc(1px + 16px / 5); @@ -200,12 +813,12 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC transition: none; } -.emotion-6:checked+label::before { +.emotion-12:checked+label::before { border-color: #0B6AFF; background-color: #0B6AFF; } -.emotion-6:checked+label::after { +.emotion-12:checked+label::after { content: ''; -webkit-transform: rotate(-45deg) scale(1); -ms-transform: rotate(-45deg) scale(1); @@ -223,9 +836,31 @@ exports[`should not render search/count/checkbox when showSearch/showCount/showC className="emotion-2 emotion-3" style={Object {}} > +

+ Authors + + 2 + +

+