From e0fbd55b6b98dd64301f113fd394dce57552d94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= <20689156+shortcuts@users.noreply.github.com> Date: Mon, 5 Jul 2021 09:28:42 +0200 Subject: [PATCH] fix(ts): make template types consistent (#4785) * fix(ts): make templates types consistent * fix: `Answers` type naming * fix: remove `ComponentTemplates` type utils * fix: remove unneeded comment * fix: inline `searchBoxTemplateProps` templates * fix: remove unneeded casts * fix: move internal type to widget file * rename template component type to `RefinementListComponentTemplates` * fix: make `searchableNoResults` optional * fix: remove unneeded default template * fix: type `defaultTemplates` * fix: apply changes from suggestion Co-authored-by: Haroen Viaene --- src/components/Answers/Answers.tsx | 8 +- src/components/Breadcrumb/Breadcrumb.tsx | 12 +- .../ClearRefinements/ClearRefinements.tsx | 6 +- src/components/Hits/Hits.tsx | 4 +- src/components/Hits/__tests__/Hits-test.tsx | 4 +- src/components/InfiniteHits/InfiniteHits.tsx | 4 +- src/components/MenuSelect/MenuSelect.tsx | 4 +- src/components/Pagination/Pagination.tsx | 4 +- src/components/Panel/Panel.tsx | 6 +- .../QueryRuleCustomData.tsx | 6 +- src/components/RangeInput/RangeInput.tsx | 4 +- .../RefinementList/RefinementList.tsx | 45 +++-- .../__tests__/RefinementList-test.tsx | 10 +- src/components/RelevantSort/RelevantSort.tsx | 4 +- src/components/SearchBox/SearchBox.tsx | 4 +- src/components/Stats/Stats.tsx | 4 +- .../ToggleRefinement/ToggleRefinement.tsx | 6 +- src/components/VoiceSearch/VoiceSearch.tsx | 4 +- src/widgets/answers/answers.tsx | 10 +- src/widgets/answers/defaultTemplates.ts | 6 +- src/widgets/breadcrumb/breadcrumb.tsx | 12 +- src/widgets/breadcrumb/defaultTemplates.ts | 6 +- .../clear-refinements/clear-refinements.tsx | 2 +- .../clear-refinements/defaultTemplates.ts | 6 +- src/widgets/geo-search/defaultTemplates.ts | 6 +- src/widgets/geo-search/geo-search.ts | 12 +- .../hierarchical-menu/defaultTemplates.ts | 5 +- .../hierarchical-menu/hierarchical-menu.tsx | 18 +- .../hits/__tests__/defaultTemplates-test.ts | 11 +- src/widgets/hits/defaultTemplates.ts | 6 +- src/widgets/hits/hits.tsx | 2 +- .../__tests__/defaultTemplates-test.ts | 11 +- src/widgets/infinite-hits/defaultTemplates.ts | 6 +- src/widgets/infinite-hits/infinite-hits.tsx | 2 +- src/widgets/menu-select/defaultTemplates.ts | 6 +- src/widgets/menu-select/menu-select.tsx | 15 +- src/widgets/menu/defaultTemplates.ts | 6 +- src/widgets/menu/menu.tsx | 18 +- src/widgets/numeric-menu/defaultTemplates.ts | 6 +- src/widgets/numeric-menu/numeric-menu.tsx | 4 +- src/widgets/pagination/pagination.tsx | 18 +- .../query-rule-custom-data.tsx | 21 ++- src/widgets/range-input/range-input.tsx | 13 +- src/widgets/rating-menu/defaultTemplates.ts | 6 +- src/widgets/rating-menu/rating-menu.tsx | 22 ++- .../refinement-list/refinement-list.tsx | 154 +++++++++--------- src/widgets/relevant-sort/defaultTemplates.ts | 6 +- src/widgets/relevant-sort/relevant-sort.tsx | 21 +-- src/widgets/search-box/defaultTemplates.ts | 6 +- src/widgets/search-box/search-box.tsx | 19 ++- src/widgets/sort-by/sort-by.tsx | 8 +- src/widgets/stats/stats.tsx | 15 +- .../toggle-refinement/defaultTemplates.ts | 6 +- .../toggle-refinement/toggle-refinement.tsx | 15 +- src/widgets/voice-search/defaultTemplates.ts | 4 +- src/widgets/voice-search/voice-search.tsx | 49 +++--- 56 files changed, 431 insertions(+), 267 deletions(-) diff --git a/src/components/Answers/Answers.tsx b/src/components/Answers/Answers.tsx index 0bc4001688..863957ab56 100644 --- a/src/components/Answers/Answers.tsx +++ b/src/components/Answers/Answers.tsx @@ -9,15 +9,17 @@ import { } from '../../widgets/answers/answers'; import { ComponentCSSClasses, Hits } from '../../types'; -export type AnswerComponentCSSClasses = ComponentCSSClasses; +export type AnswersComponentCSSClasses = ComponentCSSClasses; + +export type AnswersComponentTemplates = Required; export type AnswersProps = { hits: Hits; isLoading: boolean; - cssClasses: AnswerComponentCSSClasses; + cssClasses: AnswersComponentCSSClasses; templateProps: { [key: string]: any; - templates: AnswersTemplates; + templates: AnswersComponentTemplates; }; }; diff --git a/src/components/Breadcrumb/Breadcrumb.tsx b/src/components/Breadcrumb/Breadcrumb.tsx index 6d8fde9dd8..2196e84cda 100644 --- a/src/components/Breadcrumb/Breadcrumb.tsx +++ b/src/components/Breadcrumb/Breadcrumb.tsx @@ -3,7 +3,10 @@ import { h } from 'preact'; import cx from 'classnames'; import Template from '../Template/Template'; -import { BreadcrumbCSSClasses } from '../../widgets/breadcrumb/breadcrumb'; +import { + BreadcrumbCSSClasses, + BreadcrumbTemplates, +} from '../../widgets/breadcrumb/breadcrumb'; import { ComponentCSSClasses } from '../../types'; type BreadcrumbItem = { @@ -15,16 +18,13 @@ export type BreadcrumbComponentCSSClasses = ComponentCSSClasses< BreadcrumbCSSClasses >; -type BreadcrumbTemplates = { - home: string; - separator: string; -}; +export type BreadcrumbComponentTemplates = Required; export type BreadcrumbProps = { items: BreadcrumbItem[]; cssClasses: BreadcrumbComponentCSSClasses; templateProps: { - templates: BreadcrumbTemplates; + templates: BreadcrumbComponentTemplates; }; createURL(value: string | undefined): string; refine(value: string | undefined): void; diff --git a/src/components/ClearRefinements/ClearRefinements.tsx b/src/components/ClearRefinements/ClearRefinements.tsx index 9f5df7026c..7aa8a04fc3 100644 --- a/src/components/ClearRefinements/ClearRefinements.tsx +++ b/src/components/ClearRefinements/ClearRefinements.tsx @@ -14,13 +14,17 @@ export type ClearRefinementsComponentCSSClasses = ComponentCSSClasses< ClearRefinementsCSSClasses >; +export type ClearRefinementsComponentTemplates = Required< + ClearRefinementsTemplates +>; + export type ClearRefinementsProps = { refine: ClearRefinementsRenderState['refine']; cssClasses: ClearRefinementsComponentCSSClasses; hasRefinements: ClearRefinementsRenderState['hasRefinements']; templateProps: { [key: string]: any; - templates: ClearRefinementsTemplates; + templates: ClearRefinementsComponentTemplates; }; }; diff --git a/src/components/Hits/Hits.tsx b/src/components/Hits/Hits.tsx index ac817c84bc..1e9345f6ef 100644 --- a/src/components/Hits/Hits.tsx +++ b/src/components/Hits/Hits.tsx @@ -10,6 +10,8 @@ import { HitsCSSClasses, HitsTemplates } from '../../widgets/hits/hits'; export type HitsComponentCSSClasses = ComponentCSSClasses; +export type HitsComponentTemplates = Required; + export type HitsProps = { results: SearchResults; hits: HitsArray; @@ -18,7 +20,7 @@ export type HitsProps = { cssClasses: HitsComponentCSSClasses; templateProps: { [key: string]: any; - templates: HitsTemplates; + templates: HitsComponentTemplates; }; }; diff --git a/src/components/Hits/__tests__/Hits-test.tsx b/src/components/Hits/__tests__/Hits-test.tsx index b163ffe37b..8d4a9791be 100644 --- a/src/components/Hits/__tests__/Hits-test.tsx +++ b/src/components/Hits/__tests__/Hits-test.tsx @@ -20,7 +20,7 @@ describe('Hits', () => { function shallowRender(extraProps = {}) { const props = { cssClasses, - templateProps: { templates: {} }, + templateProps: { templates: { empty: 'No results', item: 'item' } }, ...extraProps, }; @@ -244,6 +244,7 @@ describe('Hits', () => { templateProps: { templates: { item: 'item', + empty: 'No results', }, }, cssClasses, @@ -295,6 +296,7 @@ describe('Hits', () => { hit, }); }, + empty: 'No results', }, }, cssClasses, diff --git a/src/components/InfiniteHits/InfiniteHits.tsx b/src/components/InfiniteHits/InfiniteHits.tsx index a1ff7217fe..5569e93cec 100644 --- a/src/components/InfiniteHits/InfiniteHits.tsx +++ b/src/components/InfiniteHits/InfiniteHits.tsx @@ -15,6 +15,8 @@ export type InfiniteHitsComponentCSSClasses = ComponentCSSClasses< InfiniteHitsCSSClasses >; +export type InfiniteHitsComponentTemplates = Required; + export type InfiniteHitsProps = { cssClasses: InfiniteHitsComponentCSSClasses; hits: Hits; @@ -24,7 +26,7 @@ export type InfiniteHitsProps = { showMore: () => void; templateProps: { [key: string]: any; - templates: InfiniteHitsTemplates; + templates: InfiniteHitsComponentTemplates; }; isFirstPage: boolean; isLastPage: boolean; diff --git a/src/components/MenuSelect/MenuSelect.tsx b/src/components/MenuSelect/MenuSelect.tsx index 2352fe9303..96f298ca9f 100644 --- a/src/components/MenuSelect/MenuSelect.tsx +++ b/src/components/MenuSelect/MenuSelect.tsx @@ -15,6 +15,8 @@ export type MenuSelectComponentCSSClasses = ComponentCSSClasses< MenuSelectCSSClasses >; +export type MenuSelectComponentTemplates = Required; + type MenuItem = { /** * The value of the menu item. @@ -39,7 +41,7 @@ type Props = { items: MenuItem[]; refine: MenuRenderState['refine']; templateProps: { - templates: MenuSelectTemplates; + templates: MenuSelectComponentTemplates; }; }; diff --git a/src/components/Pagination/Pagination.tsx b/src/components/Pagination/Pagination.tsx index 5f8676b16d..732ae5b02e 100644 --- a/src/components/Pagination/Pagination.tsx +++ b/src/components/Pagination/Pagination.tsx @@ -15,11 +15,13 @@ export type PaginationComponentCSSClasses = ComponentCSSClasses< PaginationCSSClasses >; +export type PaginationComponentTemplates = Required; + export type PaginationProps = { createURL(value: number): string; cssClasses: PaginationComponentCSSClasses; currentPage: number; - templates: PaginationTemplates; + templates: PaginationComponentTemplates; nbPages?: number; pages?: number[]; isFirstPage: boolean; diff --git a/src/components/Panel/Panel.tsx b/src/components/Panel/Panel.tsx index a25f4a21bb..e92cefc71f 100644 --- a/src/components/Panel/Panel.tsx +++ b/src/components/Panel/Panel.tsx @@ -16,13 +16,17 @@ export type PanelComponentCSSClasses = ComponentCSSClasses< Omit >; +export type PanelComponentTemplates< + TWidget extends UnknownWidgetFactory +> = Required>; + export type PanelProps = { hidden: boolean; collapsible: boolean; isCollapsed: boolean; data: RenderOptions; cssClasses: PanelComponentCSSClasses; - templates: Required>; + templates: PanelComponentTemplates; bodyElement: HTMLElement; }; diff --git a/src/components/QueryRuleCustomData/QueryRuleCustomData.tsx b/src/components/QueryRuleCustomData/QueryRuleCustomData.tsx index 6a0319dbe0..a9935525cd 100644 --- a/src/components/QueryRuleCustomData/QueryRuleCustomData.tsx +++ b/src/components/QueryRuleCustomData/QueryRuleCustomData.tsx @@ -12,9 +12,13 @@ export type QueryRuleCustomDataComponentCSSClasses = ComponentCSSClasses< QueryRuleCustomDataCSSClasses >; +export type QueryRuleCustomDataComponentTemplates = Required< + QueryRuleCustomDataTemplates +>; + export type QueryRuleCustomDataProps = { cssClasses: QueryRuleCustomDataComponentCSSClasses; - templates: QueryRuleCustomDataTemplates; + templates: QueryRuleCustomDataComponentTemplates; items: any[]; }; diff --git a/src/components/RangeInput/RangeInput.tsx b/src/components/RangeInput/RangeInput.tsx index ac49bd8845..7769045c95 100644 --- a/src/components/RangeInput/RangeInput.tsx +++ b/src/components/RangeInput/RangeInput.tsx @@ -14,6 +14,8 @@ export type RangeInputComponentCSSClasses = ComponentCSSClasses< RangeInputCSSClasses >; +export type RangeInputComponentTemplates = Required; + export type RangeInputProps = { min?: number; max?: number; @@ -21,7 +23,7 @@ export type RangeInputProps = { values: Partial; cssClasses: RangeInputComponentCSSClasses; templateProps: { - templates: RangeInputTemplates; + templates: RangeInputComponentTemplates; }; refine(rangeValue: RangeBoundaries): void; }; diff --git a/src/components/RefinementList/RefinementList.tsx b/src/components/RefinementList/RefinementList.tsx index a15bdadbb8..381e4d6426 100644 --- a/src/components/RefinementList/RefinementList.tsx +++ b/src/components/RefinementList/RefinementList.tsx @@ -8,15 +8,24 @@ import Template from '../Template/Template'; import RefinementListItem from './RefinementListItem'; import SearchBox, { SearchBoxComponentCSSClasses, + SearchBoxComponentTemplates, } from '../SearchBox/SearchBox'; import { RefinementListItem as TRefinementListItem } from '../../connectors/refinement-list/connectRefinementList'; import { HierarchicalMenuItem } from '../../connectors/hierarchical-menu/connectHierarchicalMenu'; -import { SearchBoxTemplates } from '../../widgets/search-box/search-box'; -import { ComponentCSSClasses, CreateURL, Templates } from '../../types'; -import { RefinementListOwnCSSClasses } from '../../widgets/refinement-list/refinement-list'; +import { + ComponentCSSClasses, + CreateURL, + Templates, + Template as TemplateType, +} from '../../types'; +import { + RefinementListOwnCSSClasses, + RefinementListOwnTemplates, +} from '../../widgets/refinement-list/refinement-list'; import { RatingMenuComponentCSSClasses } from '../../widgets/rating-menu/rating-menu'; import { HierarchicalMenuComponentCSSClasses } from '../../widgets/hierarchical-menu/hierarchical-menu'; +// CSS types type RefinementListOptionalClasses = | 'noResults' | 'checkbox' @@ -29,19 +38,25 @@ type RefinementListWidgetCSSClasses = ComponentCSSClasses< RefinementListOwnCSSClasses >; -type RefinementListRequired = Omit< +type RefinementListRequiredCSSClasses = Omit< RefinementListWidgetCSSClasses, RefinementListOptionalClasses > & Partial>; -export type RefinementListComponentCSSClasses = RefinementListRequired & { +export type RefinementListComponentCSSClasses = RefinementListRequiredCSSClasses & { searchable?: SearchBoxComponentCSSClasses; } & Partial> & Partial< Pick >; +export type RefinementListComponentTemplates = Required< + RefinementListOwnTemplates +> & { + searchableNoResults?: TemplateType; +}; + type FacetValue = TRefinementListItem | HierarchicalMenuItem; type FacetValues = TRefinementListItem[] | HierarchicalMenuItem[]; @@ -51,20 +66,22 @@ export type RefinementListProps = { depth?: number; facetValues?: FacetValues; attribute?: string; - templateProps?: PreparedTemplateProps; - searchBoxTemplateProps?: PreparedTemplateProps; + templateProps: PreparedTemplateProps; toggleRefinement: (value: string) => void; - searchFacetValues?: (query: string) => void; - searchPlaceholder?: string; - isFromSearch?: boolean; showMore?: boolean; toggleShowMore?: () => void; isShowingMore?: boolean; hasExhaustiveItems?: boolean; canToggleShowMore?: boolean; - searchIsAlwaysActive?: boolean; className?: string; children?: h.JSX.Element; + + // searchable props are optional, but will definitely be present in a searchable context + isFromSearch?: boolean; + searchIsAlwaysActive?: boolean; + searchFacetValues?: (query: string) => void; + searchPlaceholder?: string; + searchBoxTemplateProps?: PreparedTemplateProps; }; const defaultProps = { @@ -302,10 +319,6 @@ class RefinementList extends Component< this.props.searchIsAlwaysActive !== true && !(this.props.isFromSearch || !this.props.hasExhaustiveItems); - const templates = this.props.searchBoxTemplateProps - ? this.props.searchBoxTemplateProps.templates - : undefined; - const searchBox = this.props.searchFacetValues && (
extends Component< placeholder={this.props.searchPlaceholder} disabled={shouldDisableSearchBox} cssClasses={this.props.cssClasses.searchable!} - templates={templates} + templates={this.props.searchBoxTemplateProps!.templates} onChange={(event: Event) => this.props.searchFacetValues!( (event.target as HTMLInputElement).value diff --git a/src/components/RefinementList/__tests__/RefinementList-test.tsx b/src/components/RefinementList/__tests__/RefinementList-test.tsx index f50c994a80..830910d475 100644 --- a/src/components/RefinementList/__tests__/RefinementList-test.tsx +++ b/src/components/RefinementList/__tests__/RefinementList-test.tsx @@ -544,10 +544,7 @@ describe('RefinementList', () => { canToggleShowMore: true, templateProps: { templatesConfig: {}, - templates: { - item: (item: RefinementListItemData) => item.value, - showMoreText: (x: any) => JSON.stringify(x), - }, + templates, useCustomCompileOptions: {}, }, toggleRefinement: () => {}, @@ -588,10 +585,7 @@ describe('RefinementList', () => { canToggleShowMore: false, templateProps: { templatesConfig: {}, - templates: { - item: (item: RefinementListItemData) => item.value, - showMoreText: (x: any) => JSON.stringify(x), - }, + templates, useCustomCompileOptions: {}, }, toggleRefinement: () => {}, diff --git a/src/components/RelevantSort/RelevantSort.tsx b/src/components/RelevantSort/RelevantSort.tsx index 1ab4599a6c..0508e41615 100644 --- a/src/components/RelevantSort/RelevantSort.tsx +++ b/src/components/RelevantSort/RelevantSort.tsx @@ -12,9 +12,11 @@ export type RelevantSortComponentCSSClasses = ComponentCSSClasses< RelevantSortCSSClasses >; +export type RelevantSortComponentTemplates = Required; + type RelevantSortProps = { cssClasses: RelevantSortComponentCSSClasses; - templates: RelevantSortTemplates; + templates: RelevantSortComponentTemplates; isRelevantSorted: boolean; isVirtualReplica: boolean; refine(relevancyStrictness: number | undefined): void; diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index 4aeb2987c9..40cc4fbb27 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -13,10 +13,12 @@ export type SearchBoxComponentCSSClasses = ComponentCSSClasses< SearchBoxCSSClasses >; +export type SearchBoxComponentTemplates = Required; + type SearchBoxProps = { placeholder?: string; cssClasses: SearchBoxComponentCSSClasses; - templates?: SearchBoxTemplates; + templates: SearchBoxComponentTemplates; query?: string; showSubmit?: boolean; showReset?: boolean; diff --git a/src/components/Stats/Stats.tsx b/src/components/Stats/Stats.tsx index 82a15496a3..912d92e6cc 100644 --- a/src/components/Stats/Stats.tsx +++ b/src/components/Stats/Stats.tsx @@ -8,11 +8,13 @@ import { ComponentCSSClasses } from '../../types'; export type StatsComponentCSSClasses = ComponentCSSClasses; +export type StatsComponentTemplates = Required; + type StatsProps = { cssClasses: StatsComponentCSSClasses; templateProps: { [key: string]: any; - templates: StatsTemplates; + templates: StatsComponentTemplates; }; hitsPerPage: number | undefined; nbHits: number; diff --git a/src/components/ToggleRefinement/ToggleRefinement.tsx b/src/components/ToggleRefinement/ToggleRefinement.tsx index 1542ad3191..dca95f3687 100644 --- a/src/components/ToggleRefinement/ToggleRefinement.tsx +++ b/src/components/ToggleRefinement/ToggleRefinement.tsx @@ -18,11 +18,15 @@ export type ToggleRefinementComponentCSSClasses = ComponentCSSClasses< ToggleRefinementCSSClasses >; +export type ToggleRefinementComponentTemplates = Required< + ToggleRefinementTemplates +>; + export type ToggleRefinementProps = { currentRefinement: ToggleRefinementValue; refine: ToggleRefinementRenderState['refine']; cssClasses: ToggleRefinementComponentCSSClasses; - templateProps: PreparedTemplateProps; + templateProps: PreparedTemplateProps; }; const ToggleRefinement = ({ diff --git a/src/components/VoiceSearch/VoiceSearch.tsx b/src/components/VoiceSearch/VoiceSearch.tsx index bad8a3265a..383fee3358 100644 --- a/src/components/VoiceSearch/VoiceSearch.tsx +++ b/src/components/VoiceSearch/VoiceSearch.tsx @@ -14,13 +14,15 @@ export type VoiceSearchComponentCSSClasses = ComponentCSSClasses< VoiceSearchCSSClasses >; +export type VoiceSearchComponentTemplates = Required; + export type VoiceSearchProps = { cssClasses: VoiceSearchComponentCSSClasses; isBrowserSupported: boolean; isListening: boolean; toggleListening: () => void; voiceListeningState: VoiceListeningState; - templates: VoiceSearchTemplates; + templates: VoiceSearchComponentTemplates; }; const VoiceSearch = ({ diff --git a/src/widgets/answers/answers.tsx b/src/widgets/answers/answers.tsx index a35f63b953..abe6ecc880 100644 --- a/src/widgets/answers/answers.tsx +++ b/src/widgets/answers/answers.tsx @@ -53,7 +53,7 @@ export type AnswersTemplates = { /** * Template to use for the header. This template will receive an object containing `hits` and `isLoading`. */ - header: Template<{ + header?: Template<{ hits: Hit[]; isLoading: boolean; }>; @@ -61,12 +61,12 @@ export type AnswersTemplates = { /** * Template to use for the loader. */ - loader: Template; + loader?: Template; /** * Template to use for each result. This template will receive an object containing a single record. */ - item: Template; + item?: Template; }; export type AnswersCSSClasses = { @@ -110,7 +110,7 @@ export type AnswersWidgetParams = { /** * The templates to use for the widget. */ - templates?: Partial; + templates?: AnswersTemplates; /** * The CSS classes to override. @@ -134,7 +134,7 @@ const answersWidget: AnswersWidget = widgetParams => { renderDebounceTime, escapeHTML, extraParameters, - templates = defaultTemplates, + templates = {}, cssClasses: userCssClasses = {}, } = widgetParams || {}; diff --git a/src/widgets/answers/defaultTemplates.ts b/src/widgets/answers/defaultTemplates.ts index 49c352e693..76f6e125f9 100644 --- a/src/widgets/answers/defaultTemplates.ts +++ b/src/widgets/answers/defaultTemplates.ts @@ -1,5 +1,9 @@ -export default { +import { AnswersComponentTemplates } from '../../components/Answers/Answers'; + +const defaultTemplates: AnswersComponentTemplates = { header: '', loader: '', item: item => JSON.stringify(item), }; + +export default defaultTemplates; diff --git a/src/widgets/breadcrumb/breadcrumb.tsx b/src/widgets/breadcrumb/breadcrumb.tsx index 1407ab735e..bc7a3d899d 100644 --- a/src/widgets/breadcrumb/breadcrumb.tsx +++ b/src/widgets/breadcrumb/breadcrumb.tsx @@ -6,6 +6,7 @@ import Breadcrumb from '../../components/Breadcrumb/Breadcrumb'; import connectBreadcrumb, { BreadcrumbWidgetDescription, BreadcrumbConnectorParams, + BreadcrumbRenderState, } from '../../connectors/breadcrumb/connectBreadcrumb'; import defaultTemplates from './defaultTemplates'; import { @@ -14,12 +15,17 @@ import { createDocumentationMessageGenerator, } from '../../lib/utils'; import { component } from '../../lib/suit'; -import { WidgetFactory, Template } from '../../types'; +import { WidgetFactory, Template, Renderer } from '../../types'; const withUsage = createDocumentationMessageGenerator({ name: 'breadcrumb' }); const suit = component('Breadcrumb'); -const renderer = ({ containerNode, cssClasses, renderState, templates }) => ( +const renderer = ({ + containerNode, + cssClasses, + renderState, + templates, +}): Renderer> => ( { canRefine, createURL, instantSearchInstance, items, refine }, isFirstRendering ) => { @@ -125,7 +131,7 @@ const breadcrumb: BreadcrumbWidget = function breadcrumb(widgetParams) { separator, rootPath, transformItems, - templates = defaultTemplates, + templates = {}, cssClasses: userCssClasses = {}, } = widgetParams || {}; diff --git a/src/widgets/breadcrumb/defaultTemplates.ts b/src/widgets/breadcrumb/defaultTemplates.ts index ca7e11f986..bce0ce6aca 100644 --- a/src/widgets/breadcrumb/defaultTemplates.ts +++ b/src/widgets/breadcrumb/defaultTemplates.ts @@ -1,4 +1,8 @@ -export default { +import { BreadcrumbComponentTemplates } from '../../components/Breadcrumb/Breadcrumb'; + +const defaultTemplates: BreadcrumbComponentTemplates = { home: 'Home', separator: '>', }; + +export default defaultTemplates; diff --git a/src/widgets/clear-refinements/clear-refinements.tsx b/src/widgets/clear-refinements/clear-refinements.tsx index 292ee1de86..83de9e8ddf 100644 --- a/src/widgets/clear-refinements/clear-refinements.tsx +++ b/src/widgets/clear-refinements/clear-refinements.tsx @@ -95,7 +95,7 @@ export type ClearRefinementsWidget = WidgetFactory< const clearRefinements: ClearRefinementsWidget = widgetParams => { const { container, - templates = defaultTemplates, + templates = {}, includedAttributes, excludedAttributes, transformItems, diff --git a/src/widgets/clear-refinements/defaultTemplates.ts b/src/widgets/clear-refinements/defaultTemplates.ts index 0191ef7dc5..f009ad88b8 100644 --- a/src/widgets/clear-refinements/defaultTemplates.ts +++ b/src/widgets/clear-refinements/defaultTemplates.ts @@ -1,3 +1,7 @@ -export default { +import { ClearRefinementsComponentTemplates } from '../../components/ClearRefinements/ClearRefinements'; + +const defaultTemplates: ClearRefinementsComponentTemplates = { resetLabel: 'Clear refinements', }; + +export default defaultTemplates; diff --git a/src/widgets/geo-search/defaultTemplates.ts b/src/widgets/geo-search/defaultTemplates.ts index 73b9777c50..63a986f7dd 100644 --- a/src/widgets/geo-search/defaultTemplates.ts +++ b/src/widgets/geo-search/defaultTemplates.ts @@ -1,6 +1,10 @@ -export default { +import { GeoSearchComponentTemplates } from './geo-search'; + +const defaultTemplates: GeoSearchComponentTemplates = { HTMLMarker: '

Your custom HTML Marker

', reset: 'Clear the map refinement', toggle: 'Search as I move the map', redo: 'Redo search here', }; + +export default defaultTemplates; diff --git a/src/widgets/geo-search/geo-search.ts b/src/widgets/geo-search/geo-search.ts index 01e778901d..a070526ef7 100644 --- a/src/widgets/geo-search/geo-search.ts +++ b/src/widgets/geo-search/geo-search.ts @@ -23,15 +23,17 @@ const suit = component('GeoSearch'); export type GeoSearchTemplates = { /** Template to use for the marker. */ - HTMLMarker: Template; + HTMLMarker?: Template; /** Template for the reset button. */ - reset: Template; + reset?: Template; /** Template for the toggle label. */ - toggle: Template; + toggle?: Template; /** Template for the redo button. */ - redo: Template; + redo?: Template; }; +export type GeoSearchComponentTemplates = Required; + export type GeoSearchCSSClasses = { /** The root div of the widget. */ root?: string | string[]; @@ -92,7 +94,7 @@ export type GeoSearchWidgetParams = { */ initialPosition?: GeoLoc; /** Templates to use for the widget. */ - templates?: Partial; + templates?: GeoSearchTemplates; /** CSS classes to add to the wrapping elements. */ cssClasses?: GeoSearchCSSClasses; /** diff --git a/src/widgets/hierarchical-menu/defaultTemplates.ts b/src/widgets/hierarchical-menu/defaultTemplates.ts index d9078ca1c8..187db5b496 100644 --- a/src/widgets/hierarchical-menu/defaultTemplates.ts +++ b/src/widgets/hierarchical-menu/defaultTemplates.ts @@ -1,4 +1,5 @@ -export default { +import { HierarchicalMenuComponentTemplates } from './hierarchical-menu'; +const defaultTemplates: HierarchicalMenuComponentTemplates = { item: '' + '{{label}}' + @@ -13,3 +14,5 @@ export default { {{/isShowingMore}} `, }; + +export default defaultTemplates; diff --git a/src/widgets/hierarchical-menu/hierarchical-menu.tsx b/src/widgets/hierarchical-menu/hierarchical-menu.tsx index a3bd0d5081..68715fd459 100644 --- a/src/widgets/hierarchical-menu/hierarchical-menu.tsx +++ b/src/widgets/hierarchical-menu/hierarchical-menu.tsx @@ -35,7 +35,7 @@ type HierarchicalMenuTemplates = { /** * Item template, provided with `name`, `count`, `isRefined`, `url` data properties. */ - item: Template<{ + item?: Template<{ name: string; count: number; isRefined: boolean; @@ -44,7 +44,7 @@ type HierarchicalMenuTemplates = { /** * Template used for the show more text, provided with `isShowingMore` data property. */ - showMoreText: Template<{ isShowingMore: boolean }>; + showMoreText?: Template<{ isShowingMore: boolean }>; }; export type HierarchicalMenuCSSClasses = { @@ -102,6 +102,10 @@ export type HierarchicalMenuComponentCSSClasses = ComponentCSSClasses< HierarchicalMenuCSSClasses >; +export type HierarchicalMenuComponentTemplates = Required< + HierarchicalMenuTemplates +>; + export type HierarchicalMenuWidgetParams = { /** * CSS Selector or HTMLElement to insert the widget. @@ -166,7 +170,7 @@ export type HierarchicalMenuWidgetParams = { /** * Templates to use for the widget. */ - templates?: Partial; + templates?: HierarchicalMenuTemplates; /** * CSS classes to add to the wrapping elements. */ @@ -183,9 +187,9 @@ const renderer = ({ cssClasses: HierarchicalMenuComponentCSSClasses; containerNode: HTMLElement; showMore: boolean; - templates: Partial; + templates: HierarchicalMenuTemplates; renderState: { - templateProps?: PreparedTemplateProps; + templateProps?: PreparedTemplateProps; }; }) => ( { @@ -214,7 +218,7 @@ const renderer = ({ createURL={createURL} cssClasses={cssClasses} facetValues={items} - templateProps={renderState.templateProps} + templateProps={renderState.templateProps!} toggleRefinement={refine} showMore={showMore} toggleShowMore={toggleShowMore} @@ -296,7 +300,7 @@ const hierarchicalMenu: HierarchicalMenuWidget = function hierarchicalMenu( showMoreLimit, sortBy, transformItems, - templates = defaultTemplates, + templates = {}, cssClasses: userCssClasses = {}, } = widgetParams || {}; diff --git a/src/widgets/hits/__tests__/defaultTemplates-test.ts b/src/widgets/hits/__tests__/defaultTemplates-test.ts index 5d0916bf11..d09fbe2be4 100644 --- a/src/widgets/hits/__tests__/defaultTemplates-test.ts +++ b/src/widgets/hits/__tests__/defaultTemplates-test.ts @@ -7,6 +7,9 @@ describe('hits defaultTemplates', () => { it('has a `item` default template', () => { const item = { + __position: 0, + __hitIndex: 1, + objectID: '2', hello: 'there,', how: { are: 'you?', @@ -14,12 +17,18 @@ describe('hits defaultTemplates', () => { }; const expected = `{ + "__position": 0, + "__hitIndex": 1, + "objectID": "2", "hello": "there,", "how": { "are": "you?" } }`; - expect(defaultTemplates.item(item)).toBe(expected); + expect( + typeof defaultTemplates.item === 'function' && + defaultTemplates.item(item, () => '') + ).toBe(expected); }); }); diff --git a/src/widgets/hits/defaultTemplates.ts b/src/widgets/hits/defaultTemplates.ts index 41953b4d43..53fa70815d 100644 --- a/src/widgets/hits/defaultTemplates.ts +++ b/src/widgets/hits/defaultTemplates.ts @@ -1,6 +1,10 @@ -export default { +import { HitsComponentTemplates } from '../../components/Hits/Hits'; + +const defaultTemplates: HitsComponentTemplates = { empty: 'No results', item(data) { return JSON.stringify(data, null, 2); }, }; + +export default defaultTemplates; diff --git a/src/widgets/hits/hits.tsx b/src/widgets/hits/hits.tsx index 4c3fed3c3b..3cdaa5faa8 100644 --- a/src/widgets/hits/hits.tsx +++ b/src/widgets/hits/hits.tsx @@ -135,7 +135,7 @@ const hits: HitsWidget = function hits(widgetParams) { container, escapeHTML, transformItems, - templates = defaultTemplates, + templates = {}, cssClasses: userCssClasses = {}, } = widgetParams || {}; diff --git a/src/widgets/infinite-hits/__tests__/defaultTemplates-test.ts b/src/widgets/infinite-hits/__tests__/defaultTemplates-test.ts index 7db192eeb7..27514cd34e 100644 --- a/src/widgets/infinite-hits/__tests__/defaultTemplates-test.ts +++ b/src/widgets/infinite-hits/__tests__/defaultTemplates-test.ts @@ -7,6 +7,9 @@ describe('hits defaultTemplates', () => { it('has a `item` default template', () => { const item = { + __position: 0, + __hitIndex: 1, + objectID: '2', hello: 'there,', how: { are: 'you?', @@ -14,13 +17,19 @@ describe('hits defaultTemplates', () => { }; const expected = `{ + "__position": 0, + "__hitIndex": 1, + "objectID": "2", "hello": "there,", "how": { "are": "you?" } }`; - expect(defaultTemplates.item(item)).toBe(expected); + expect( + typeof defaultTemplates.item === 'function' && + defaultTemplates.item(item, () => '') + ).toBe(expected); }); it('has a `showPreviousText` default template', () => { diff --git a/src/widgets/infinite-hits/defaultTemplates.ts b/src/widgets/infinite-hits/defaultTemplates.ts index 79bc7270c8..46972a53a3 100644 --- a/src/widgets/infinite-hits/defaultTemplates.ts +++ b/src/widgets/infinite-hits/defaultTemplates.ts @@ -1,4 +1,6 @@ -export default { +import { InfiniteHitsComponentTemplates } from '../../components/InfiniteHits/InfiniteHits'; + +const defaultTemplates: InfiniteHitsComponentTemplates = { empty: 'No results', showPreviousText: 'Show previous results', showMoreText: 'Show more results', @@ -6,3 +8,5 @@ export default { return JSON.stringify(data, null, 2); }, }; + +export default defaultTemplates; diff --git a/src/widgets/infinite-hits/infinite-hits.tsx b/src/widgets/infinite-hits/infinite-hits.tsx index 251776ecaa..f5a205145f 100644 --- a/src/widgets/infinite-hits/infinite-hits.tsx +++ b/src/widgets/infinite-hits/infinite-hits.tsx @@ -188,7 +188,7 @@ const infiniteHits: InfiniteHitsWidget = widgetParams => { container, escapeHTML, transformItems, - templates = defaultTemplates, + templates = {}, cssClasses: userCssClasses = {}, showPrevious, cache, diff --git a/src/widgets/menu-select/defaultTemplates.ts b/src/widgets/menu-select/defaultTemplates.ts index bbad8d4cc8..b6fc805cc1 100644 --- a/src/widgets/menu-select/defaultTemplates.ts +++ b/src/widgets/menu-select/defaultTemplates.ts @@ -1,5 +1,9 @@ -export default { +import { MenuSelectComponentTemplates } from '../../components/MenuSelect/MenuSelect'; + +const defaultTemplates: MenuSelectComponentTemplates = { item: '{{label}} ({{#helpers.formatNumber}}{{count}}{{/helpers.formatNumber}})', defaultOption: 'See all', }; + +export default defaultTemplates; diff --git a/src/widgets/menu-select/menu-select.tsx b/src/widgets/menu-select/menu-select.tsx index 7e8d62f36f..a854fada1b 100644 --- a/src/widgets/menu-select/menu-select.tsx +++ b/src/widgets/menu-select/menu-select.tsx @@ -9,6 +9,7 @@ import connectMenu, { } from '../../connectors/menu/connectMenu'; import MenuSelect, { MenuSelectComponentCSSClasses, + MenuSelectComponentTemplates, } from '../../components/MenuSelect/MenuSelect'; import defaultTemplates from './defaultTemplates'; import { @@ -46,7 +47,7 @@ export type MenuSelectTemplates = { /** * Item template, provided with `label`, `count`, `isRefined` and `value` data properties. */ - item: Template<{ + item?: Template<{ label: string; value: string; count: number; @@ -55,7 +56,7 @@ export type MenuSelectTemplates = { /** * Label of the "see all" option in the select. */ - defaultOption: Template; + defaultOption?: Template; }; export type MenuSelectWidgetParams = { @@ -66,7 +67,7 @@ export type MenuSelectWidgetParams = { /** * Customize the output through templating. */ - templates?: Partial; + templates?: MenuSelectTemplates; /** * CSS classes to add to the wrapping elements. */ @@ -81,8 +82,10 @@ const renderer = ({ }: { containerNode: HTMLElement; cssClasses: MenuSelectComponentCSSClasses; - renderState: { templateProps?: PreparedTemplateProps }; - templates: Partial; + renderState: { + templateProps?: PreparedTemplateProps; + }; + templates: MenuSelectTemplates; }) => ( { refine, @@ -124,7 +127,7 @@ const menuSelect: MenuSelectWidget = function menuSelect(widgetParams) { sortBy = ['name:asc'], limit = 10, cssClasses: userCssClasses = {}, - templates = defaultTemplates, + templates = {}, transformItems, } = widgetParams || {}; diff --git a/src/widgets/menu/defaultTemplates.ts b/src/widgets/menu/defaultTemplates.ts index d9078ca1c8..6791bd1c90 100644 --- a/src/widgets/menu/defaultTemplates.ts +++ b/src/widgets/menu/defaultTemplates.ts @@ -1,4 +1,6 @@ -export default { +import { MenuComponentTemplates } from './menu'; + +const defaultTemplates: MenuComponentTemplates = { item: '' + '{{label}}' + @@ -13,3 +15,5 @@ export default { {{/isShowingMore}} `, }; + +export default defaultTemplates; diff --git a/src/widgets/menu/menu.tsx b/src/widgets/menu/menu.tsx index 6fcae72c8a..070691190e 100644 --- a/src/widgets/menu/menu.tsx +++ b/src/widgets/menu/menu.tsx @@ -73,7 +73,7 @@ export type MenuTemplates = { /** * Item template. The string template gets the same values as the function. */ - item: Template<{ + item?: Template<{ count: number; cssClasses: MenuCSSClasses; isRefined: boolean; @@ -84,13 +84,15 @@ export type MenuTemplates = { /** * Template used for the show more text, provided with `isShowingMore` data property. */ - showMoreText: Template<{ + showMoreText?: Template<{ isShowingMore: boolean; }>; }; export type MenuComponentCSSClasses = ComponentCSSClasses; +export type MenuComponentTemplates = Required; + export type MenuWidgetParams = { /** * CSS Selector or HTMLElement to insert the widget. @@ -99,7 +101,7 @@ export type MenuWidgetParams = { /** * Customize the output through templating. */ - templates?: Partial; + templates?: MenuTemplates; /** * CSS classes to add to the wrapping elements. */ @@ -115,8 +117,10 @@ const renderer = ({ }: { containerNode: HTMLElement; cssClasses: MenuComponentCSSClasses; - renderState: { templateProps?: PreparedTemplateProps }; - templates: Partial; + renderState: { + templateProps?: PreparedTemplateProps; + }; + templates: MenuTemplates; showMore?: boolean; }) => ( { @@ -150,7 +154,7 @@ const renderer = ({ cssClasses={cssClasses} facetValues={facetValues} showMore={showMore} - templateProps={renderState.templateProps} + templateProps={renderState.templateProps!} toggleRefinement={refine} toggleShowMore={toggleShowMore} isShowingMore={isShowingMore} @@ -175,7 +179,7 @@ const menu: MenuWidget = function menu(widgetParams) { showMore, showMoreLimit, cssClasses: userCssClasses = {}, - templates = defaultTemplates, + templates = {}, transformItems, } = widgetParams || {}; diff --git a/src/widgets/numeric-menu/defaultTemplates.ts b/src/widgets/numeric-menu/defaultTemplates.ts index 3e3a038194..3b8d887832 100644 --- a/src/widgets/numeric-menu/defaultTemplates.ts +++ b/src/widgets/numeric-menu/defaultTemplates.ts @@ -1,6 +1,10 @@ -export default { +import { NumericMenuComponentTemplates } from './numeric-menu'; + +const defaultTemplates: NumericMenuComponentTemplates = { item: ``, }; + +export default defaultTemplates; diff --git a/src/widgets/numeric-menu/numeric-menu.tsx b/src/widgets/numeric-menu/numeric-menu.tsx index 8e86ea5412..8867b225a5 100644 --- a/src/widgets/numeric-menu/numeric-menu.tsx +++ b/src/widgets/numeric-menu/numeric-menu.tsx @@ -137,6 +137,8 @@ export type NumericMenuTemplates = { }>; }; +export type NumericMenuComponentTemplates = Required; + export type NumericMenuWidgetParams = { /** * CSS Selector or HTMLElement to insert the widget. @@ -166,7 +168,7 @@ const numericMenu: NumericMenuWidget = function numericMenu(widgetParams) { attribute, items, cssClasses: userCssClasses = {}, - templates = defaultTemplates, + templates = {}, transformItems, } = widgetParams || {}; diff --git a/src/widgets/pagination/pagination.tsx b/src/widgets/pagination/pagination.tsx index 75d19ef136..c452b5cb67 100644 --- a/src/widgets/pagination/pagination.tsx +++ b/src/widgets/pagination/pagination.tsx @@ -2,7 +2,9 @@ import { h, render } from 'preact'; import cx from 'classnames'; -import Pagination from '../../components/Pagination/Pagination'; +import Pagination, { + PaginationComponentTemplates, +} from '../../components/Pagination/Pagination'; import connectPagination, { PaginationConnectorParams, PaginationRenderState, @@ -18,7 +20,7 @@ import { Renderer, WidgetFactory } from '../../types'; const suit = component('Pagination'); const withUsage = createDocumentationMessageGenerator({ name: 'pagination' }); -const defaultTemplates: PaginationTemplates = { +const defaultTemplates: PaginationComponentTemplates = { previous: '‹', next: '›', first: '«', @@ -142,22 +144,22 @@ export type PaginationTemplates = { /** * Label for the Previous link. */ - previous: string; + previous?: string; /** * Label for the Next link. */ - next: string; + next?: string; /** * Label for the First link. */ - first: string; + first?: string; /** * Label for the Last link. */ - last: string; + last?: string; }; export type PaginationWidgetParams = { @@ -210,7 +212,7 @@ export type PaginationWidgetParams = { /** * Text to display in the links. */ - templates?: Partial; + templates?: PaginationTemplates; /** * CSS classes to be added. @@ -286,7 +288,7 @@ const pagination: PaginationWidget = function pagination(widgetParams) { link: cx(suit({ descendantName: 'link' }), userCssClasses.link), }; - const templates: PaginationTemplates = { + const templates = { ...defaultTemplates, ...userTemplates, }; diff --git a/src/widgets/query-rule-custom-data/query-rule-custom-data.tsx b/src/widgets/query-rule-custom-data/query-rule-custom-data.tsx index 74f3ca2b29..8eb6405adb 100644 --- a/src/widgets/query-rule-custom-data/query-rule-custom-data.tsx +++ b/src/widgets/query-rule-custom-data/query-rule-custom-data.tsx @@ -15,6 +15,7 @@ import connectQueryRules, { } from '../../connectors/query-rules/connectQueryRules'; import CustomData, { QueryRuleCustomDataComponentCSSClasses, + QueryRuleCustomDataComponentTemplates, } from '../../components/QueryRuleCustomData/QueryRuleCustomData'; import { PreparedTemplateProps } from '../../lib/utils/prepareTemplateProps'; @@ -23,7 +24,7 @@ export type QueryRuleCustomDataCSSClasses = { }; export type QueryRuleCustomDataTemplates = { - default: Template<{ items: any[] }>; + default?: Template<{ items: any[] }>; }; type QueryRuleCustomDataWidgetParams = { @@ -38,6 +39,10 @@ type QueryRuleCustomDataWidget = WidgetFactory< QueryRuleCustomDataWidgetParams >; +export const defaultTemplates: QueryRuleCustomDataComponentTemplates = { + default: ({ items }) => JSON.stringify(items, null, 2), +}; + const withUsage = createDocumentationMessageGenerator({ name: 'query-rule-custom-data', }); @@ -52,9 +57,11 @@ const renderer = ({ containerNode: HTMLElement; cssClasses: QueryRuleCustomDataComponentCSSClasses; renderState: { - templateProps?: PreparedTemplateProps; + templateProps?: PreparedTemplateProps< + QueryRuleCustomDataComponentTemplates + >; }; - templates: QueryRuleCustomDataTemplates; + templates: QueryRuleCustomDataComponentTemplates; }) => ({ items }: QueryRulesRenderState) => { render( { const { container, - cssClasses: userCssClasses = {} as QueryRuleCustomDataCSSClasses, + cssClasses: userCssClasses = {}, templates: userTemplates = {}, transformItems = (items => items) as QueryRulesConnectorParams['transformItems'], @@ -84,10 +91,8 @@ const queryRuleCustomData: QueryRuleCustomDataWidget = widgetParams => { }; const containerNode = getContainerNode(container); - const defaultTemplates = { - default: ({ items }) => JSON.stringify(items, null, 2), - }; - const templates: QueryRuleCustomDataTemplates = { + + const templates = { ...defaultTemplates, ...userTemplates, }; diff --git a/src/widgets/range-input/range-input.tsx b/src/widgets/range-input/range-input.tsx index c97300e1a0..ee11189e71 100644 --- a/src/widgets/range-input/range-input.tsx +++ b/src/widgets/range-input/range-input.tsx @@ -29,12 +29,12 @@ export type RangeInputTemplates = { * The label of the separator, between min and max. * @default "to" */ - separatorText: Template; + separatorText?: Template; /** * The label of the submit button * @default "Go" */ - submitText: Template; + submitText?: Template; }; export type RangeInputCSSClasses = { @@ -101,7 +101,7 @@ export type RangeInputWidgetParams = { /** * Labels to use for the widget. */ - templates?: Partial; + templates?: RangeInputTemplates; /** * CSS classes to add. */ @@ -167,7 +167,7 @@ const rangeInput: RangeInputWidget = function rangeInput(widgetParams) { max, precision = 0, cssClasses: userCssClasses = {}, - templates: userTemplates = {}, + templates = {}, } = widgetParams || {}; if (!container) { @@ -176,11 +176,6 @@ const rangeInput: RangeInputWidget = function rangeInput(widgetParams) { const containerNode = getContainerNode(container); - const templates = { - ...defaultTemplates, - ...userTemplates, - }; - const cssClasses = { root: cx(suit(), userCssClasses.root), noRefinement: cx(suit({ modifierName: 'noRefinement' })), diff --git a/src/widgets/rating-menu/defaultTemplates.ts b/src/widgets/rating-menu/defaultTemplates.ts index d0d5a17c41..ffc36aa5c6 100644 --- a/src/widgets/rating-menu/defaultTemplates.ts +++ b/src/widgets/rating-menu/defaultTemplates.ts @@ -1,4 +1,6 @@ -export default { +import { RatingMenuComponentTemplates } from './rating-menu'; + +const defaultTemplates: RatingMenuComponentTemplates = { item: `{{#count}}{{/count}}{{^count}}{{/count}}`, }; + +export default defaultTemplates; diff --git a/src/widgets/rating-menu/rating-menu.tsx b/src/widgets/rating-menu/rating-menu.tsx index 24fd7fb496..88f844f4a3 100644 --- a/src/widgets/rating-menu/rating-menu.tsx +++ b/src/widgets/rating-menu/rating-menu.tsx @@ -18,6 +18,7 @@ import { component } from '../../lib/suit'; import { ComponentCSSClasses, RendererOptions, + Template, WidgetFactory, } from '../../types'; import { PreparedTemplateProps } from '../../lib/utils/prepareTemplateProps'; @@ -29,7 +30,12 @@ export type RatingMenuTemplates = { /** * Item template, provided with `name`, `count`, `isRefined`, `url` data properties. */ - item: string | ((data: any) => string); + item?: Template<{ + name: string; + count: number; + isRefined: boolean; + url: string; + }>; }; export type RatingMenuCSSClasses = { @@ -87,6 +93,8 @@ export type RatingMenuComponentCSSClasses = ComponentCSSClasses< RatingMenuCSSClasses >; +export type RatingMenuComponentTemplates = Required; + export type RatingMenuWidgetParams = { /** * Place where to insert the widget in your webpage. @@ -103,7 +111,7 @@ export type RatingMenuWidgetParams = { /** * Templates to use for the widget. */ - templates?: Partial; + templates?: RatingMenuTemplates; /** * CSS classes to add. */ @@ -118,8 +126,10 @@ const renderer = ({ }: { containerNode: HTMLElement; cssClasses: RatingMenuComponentCSSClasses; - templates: Partial; - renderState: { templateProps?: PreparedTemplateProps }; + templates: RatingMenuTemplates; + renderState: { + templateProps?: PreparedTemplateProps; + }; }) => ( { refine, @@ -144,7 +154,7 @@ const renderer = ({ createURL={createURL} cssClasses={cssClasses} facetValues={items} - templateProps={renderState.templateProps} + templateProps={renderState.templateProps!} toggleRefinement={refine} > @@ -201,7 +211,7 @@ const ratingMenu: RatingMenuWidget = function ratingMenu(widgetParams) { attribute, max = 5, cssClasses: userCssClasses = {}, - templates = defaultTemplates, + templates = {}, } = widgetParams || {}; if (!container) { throw new Error(withUsage('The `container` option is required.')); diff --git a/src/widgets/refinement-list/refinement-list.tsx b/src/widgets/refinement-list/refinement-list.tsx index 206a5cb019..67c27b4b1c 100644 --- a/src/widgets/refinement-list/refinement-list.tsx +++ b/src/widgets/refinement-list/refinement-list.tsx @@ -4,6 +4,7 @@ import { h, render } from 'preact'; import cx from 'classnames'; import RefinementList, { RefinementListComponentCSSClasses, + RefinementListComponentTemplates, } from '../../components/RefinementList/RefinementList'; import connectRefinementList, { RefinementListRenderState, @@ -20,6 +21,7 @@ import { Template, WidgetFactory, RendererOptions } from '../../types'; import { PreparedTemplateProps } from '../../lib/utils/prepareTemplateProps'; import searchBoxDefaultTemplates from '../search-box/defaultTemplates'; import { SearchBoxTemplates } from '../search-box/search-box'; +import { SearchBoxComponentTemplates } from '../../components/SearchBox/SearchBox'; const withUsage = createDocumentationMessageGenerator({ name: 'refinement-list', @@ -27,70 +29,6 @@ const withUsage = createDocumentationMessageGenerator({ const suit = component('RefinementList'); const searchBoxSuit = component('SearchBox'); -type RefinementListOwnTemplates = { - /** - * Item template, provided with `label`, `highlighted`, `value`, `count`, `isRefined`, `url` data properties. - */ - item: Template; - /** - * Template used for the show more text, provided with `isShowingMore` data property. - */ - showMoreText: Template; - /** - * Templates to use for search for facet values when there are no results. - */ - searchableNoResults: Template; -}; - -type RefinementListSearchableTemplates = { - /** - * Templates to use for search for facet values submit button. - */ - searchableSubmit: SearchBoxTemplates['submit']; - /** - * Templates to use for search for facet values reset button. - */ - searchableReset: SearchBoxTemplates['reset']; - /** - * Templates to use for the search for facet values loading indicator. - */ - searchableLoadingIndicator: SearchBoxTemplates['loadingIndicator']; -}; - -export type RefinementListTemplates = RefinementListSearchableTemplates & - RefinementListOwnTemplates; - -export type RefinementListItemData = { - /** - * The number of occurrences of the facet in the result set. - */ - count: number; - /** - * True if the value is selected. - */ - isRefined: boolean; - /** - * The label to display. - */ - label: string; - /** - * The value used for refining. - */ - value: string; - /** - * The label highlighted (when using search for facet values). This value is displayed in the default template. - */ - highlighted: string; - /** - * The url with this refinement selected. - */ - url: string; - /** - * Object containing all the classes computed for the item. - */ - cssClasses: RefinementListCSSClasses; -}; - export type RefinementListOwnCSSClasses = { /** * CSS class to add to the root element. @@ -161,6 +99,70 @@ type RefinementListSearchableCSSClasses = { export type RefinementListCSSClasses = RefinementListOwnCSSClasses & RefinementListSearchableCSSClasses; +export type RefinementListItemData = { + /** + * The number of occurrences of the facet in the result set. + */ + count: number; + /** + * True if the value is selected. + */ + isRefined: boolean; + /** + * The label to display. + */ + label: string; + /** + * The value used for refining. + */ + value: string; + /** + * The label highlighted (when using search for facet values). This value is displayed in the default template. + */ + highlighted: string; + /** + * The url with this refinement selected. + */ + url: string; + /** + * Object containing all the classes computed for the item. + */ + cssClasses: RefinementListCSSClasses; +}; + +export type RefinementListOwnTemplates = { + /** + * Item template, provided with `label`, `highlighted`, `value`, `count`, `isRefined`, `url` data properties. + */ + item?: Template; + /** + * Template used for the show more text, provided with `isShowingMore` data property. + */ + showMoreText?: Template; + /** + * Templates to use for search for facet values when there are no results. + */ + searchableNoResults?: Template; +}; + +type RefinementListSearchableTemplates = { + /** + * Templates to use for search for facet values submit button. + */ + searchableSubmit?: SearchBoxTemplates['submit']; + /** + * Templates to use for search for facet values reset button. + */ + searchableReset?: SearchBoxTemplates['reset']; + /** + * Templates to use for the search for facet values loading indicator. + */ + searchableLoadingIndicator?: SearchBoxTemplates['loadingIndicator']; +}; + +export type RefinementListTemplates = RefinementListOwnTemplates & + RefinementListSearchableTemplates; + export type RefinementListWidgetParams = { /** * CSS Selector or HTMLElement to insert the widget. @@ -190,14 +192,14 @@ export type RefinementListWidgetParams = { /** * Templates to use for the widget. */ - templates?: Partial; + templates?: RefinementListTemplates; /** * CSS classes to add to the wrapping elements. */ cssClasses?: RefinementListCSSClasses; }; -export const defaultTemplates: RefinementListOwnTemplates = { +export const defaultTemplates: RefinementListComponentTemplates = { item: `
`. */ - root: string | string[]; + root?: string | string[]; /** * CSS classes added to the parent `