├── .prettierrc ├── src ├── lib │ ├── components │ │ ├── HOC │ │ │ ├── index.js │ │ │ ├── withState.js │ │ │ └── withState.test.js │ │ ├── ReactSearchKit │ │ │ ├── AppContext.js │ │ │ ├── index.js │ │ │ └── ReactSearchKit.js │ │ ├── ShouldRender │ │ │ ├── index.js │ │ │ └── ShouldRender.js │ │ ├── Error │ │ │ ├── index.js │ │ │ └── Error.js │ │ ├── ResultsLoader │ │ │ ├── index.js │ │ │ └── ResultsLoader.js │ │ ├── Count │ │ │ ├── index.js │ │ │ └── Count.js │ │ ├── ResultsGrid │ │ │ ├── index.js │ │ │ └── ResultsGrid.js │ │ ├── ResultsList │ │ │ ├── index.js │ │ │ └── ResultsList.js │ │ ├── ResultsMultiLayout │ │ │ ├── index.js │ │ │ └── ResultsMultiLayout.js │ │ ├── Toggle │ │ │ ├── index.js │ │ │ └── Toggle.js │ │ ├── SearchBar │ │ │ └── index.js │ │ ├── ActiveFilters │ │ │ ├── index.js │ │ │ └── ActiveFilters.js │ │ ├── SortBy │ │ │ ├── index.js │ │ │ └── SortBy.js │ │ ├── LayoutSwitcher │ │ │ ├── index.js │ │ │ └── LayoutSwitcher.js │ │ ├── BucketAggregation │ │ │ └── index.js │ │ ├── ResultsPerPage │ │ │ ├── index.js │ │ │ └── ResultsPerPage.js │ │ ├── SortOrder │ │ │ ├── index.js │ │ │ └── SortOrder.js │ │ ├── Pagination │ │ │ └── index.js │ │ ├── Sort │ │ │ └── index.js │ │ ├── EmptyResults │ │ │ ├── index.js │ │ │ └── EmptyResults.js │ │ ├── Bootstrap │ │ │ ├── index.js │ │ │ ├── Bootstrap.js │ │ │ └── Bootstrap.test.js │ │ ├── AutocompleteSearchBar │ │ │ ├── AutocompleteSearchBar.scss │ │ │ └── index.js │ │ └── index.js │ ├── events.js │ ├── state │ │ ├── actions │ │ │ └── index.js │ │ ├── selectors │ │ │ └── index.js │ │ ├── reducers │ │ │ ├── index.js │ │ │ ├── app.js │ │ │ ├── results.js │ │ │ └── query.js │ │ └── types │ │ │ └── index.js │ ├── api │ │ ├── contrib │ │ │ ├── index.js │ │ │ ├── opensearch │ │ │ │ ├── index.js │ │ │ │ ├── OSResponseSerializer.js │ │ │ │ ├── OSRequestSerializer.js │ │ │ │ ├── OSRequestSerializer.test.js │ │ │ │ ├── OSSearchApi.test.js │ │ │ │ └── OSSearchApi.js │ │ │ └── invenio │ │ │ │ ├── index.js │ │ │ │ ├── InvenioResponseSerializer.js │ │ │ │ ├── InvenioSearchApi.test.js │ │ │ │ ├── InvenioSuggestionApi.js │ │ │ │ ├── InvenioRequestSerializer.js │ │ │ │ └── InvenioRecordsResourcesRequestSerializer.js │ │ ├── errors.js │ │ ├── index.js │ │ └── UrlParamValidator.js │ ├── index.js │ ├── util.js │ ├── storeConfig.js │ └── store.js ├── demos │ ├── opensearch │ │ ├── docker │ │ │ ├── nginx │ │ │ │ ├── Dockerfile │ │ │ │ └── site.conf │ │ │ ├── docker-compose.yml │ │ │ └── os2-mappings.json │ │ ├── index.js │ │ ├── Results.js │ │ └── DemoOSRequestSerializer.js │ ├── zenodo │ │ ├── index.js │ │ └── Results.js │ ├── cern-videos │ │ ├── index.js │ │ └── Results.js │ ├── cern-videos-namespaced │ │ ├── cern-videos-2 │ │ │ ├── index.js │ │ │ └── App.js │ │ ├── cern-videos-3 │ │ │ ├── index.js │ │ │ └── App.js │ │ ├── Results.js │ │ └── app.js │ └── App.js ├── polyfill.js ├── setupTests.js └── index.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── docs ├── docs │ ├── assets │ │ ├── url_params.gif │ │ ├── getting_started_search.png │ │ └── getting_started_resultslist.png │ ├── create_your_component.md │ ├── components │ │ ├── results_loader.md │ │ ├── error.md │ │ ├── with_state.md │ │ ├── count.md │ │ ├── empty_results.md │ │ ├── active_filters.md │ │ ├── results_multi_layout.md │ │ ├── layout_switcher.md │ │ ├── results_list.md │ │ ├── results_grid.md │ │ ├── toggle.md │ │ ├── search_bar.md │ │ ├── sort_by.md │ │ ├── sort_order.md │ │ ├── results_per_page.md │ │ ├── sort.md │ │ ├── pagination.md │ │ ├── bucket_aggregation.md │ │ └── react_search_kit.md │ ├── ui_customisation.md │ └── filters_aggregations.md └── website │ ├── static │ ├── img │ │ ├── favicon.png │ │ ├── logo-cern.png │ │ ├── oss_logo.png │ │ ├── screenshot.png │ │ └── favicon │ │ │ └── favicon.ico │ ├── css │ │ ├── custom.css │ │ └── code-blocks-buttons.css │ └── js │ │ └── code-blocks-buttons.js │ ├── package.json │ ├── sidebars.json │ ├── core │ └── Footer.js │ ├── pages │ └── en │ │ ├── help.js │ │ └── index.js │ └── siteConfig.js ├── .eslintrc.yml ├── deploy_docs.sh ├── .github └── workflows │ ├── npm-publish.yml │ └── js-tests.yml ├── .gitignore ├── rollup.config.js ├── LICENSE ├── README.md └── package.json /.prettierrc: -------------------------------------------------------------------------------- 1 | "@inveniosoftware/eslint-config-invenio/prettier-config" 2 | -------------------------------------------------------------------------------- /src/lib/components/HOC/index.js: -------------------------------------------------------------------------------- 1 | export { withState } from "./withState"; 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/demos/opensearch/docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable 2 | 3 | COPY site.conf /etc/nginx/conf.d/ 4 | -------------------------------------------------------------------------------- /docs/docs/assets/url_params.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/docs/assets/url_params.gif -------------------------------------------------------------------------------- /docs/website/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/website/static/img/favicon.png -------------------------------------------------------------------------------- /src/lib/components/ReactSearchKit/AppContext.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const AppContext = React.createContext({}); 4 | -------------------------------------------------------------------------------- /docs/website/static/img/logo-cern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/website/static/img/logo-cern.png -------------------------------------------------------------------------------- /docs/website/static/img/oss_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/website/static/img/oss_logo.png -------------------------------------------------------------------------------- /docs/website/static/img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/website/static/img/screenshot.png -------------------------------------------------------------------------------- /docs/docs/assets/getting_started_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/docs/assets/getting_started_search.png -------------------------------------------------------------------------------- /docs/website/static/img/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/website/static/img/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/docs/assets/getting_started_resultslist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveniosoftware/react-searchkit/HEAD/docs/docs/assets/getting_started_resultslist.png -------------------------------------------------------------------------------- /src/polyfill.js: -------------------------------------------------------------------------------- 1 | import { TextEncoder, TextDecoder, ReadableStream } from "util"; 2 | 3 | Object.assign(global, { TextDecoder, TextEncoder, ReadableStream }); 4 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - '@inveniosoftware/invenio' 3 | - '@inveniosoftware/invenio/prettier' 4 | 5 | env: 6 | browser: true 7 | es6: true 8 | jest: true 9 | -------------------------------------------------------------------------------- /src/lib/events.js: -------------------------------------------------------------------------------- 1 | export const onQueryChanged = (payload) => { 2 | var evt = new CustomEvent("queryChanged", { 3 | detail: payload, 4 | }); 5 | window.dispatchEvent(evt); 6 | }; 7 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT: this files should be imported first to apply some global variables 2 | import "./polyfill.js"; 3 | import { configure } from "enzyme"; 4 | import Adapter from "enzyme-adapter-react-16"; 5 | 6 | configure({ adapter: new Adapter() }); 7 | -------------------------------------------------------------------------------- /deploy_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git config --global user.name "${GH_NAME}" 4 | git config --global user.email "${GH_EMAIL}" 5 | echo "machine github.com login ${GH_NAME} password ${GH_TOKEN}" > ~/.netrc 6 | cd docs/website && npm install && GIT_USER="${GH_NAME}" npm run publish-gh-pages 7 | -------------------------------------------------------------------------------- /src/lib/state/actions/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export * from "./query"; 10 | -------------------------------------------------------------------------------- /src/lib/state/selectors/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export * from "./query"; 10 | -------------------------------------------------------------------------------- /src/demos/opensearch/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { App as OSReactSearchKit } from "./App"; 10 | -------------------------------------------------------------------------------- /src/demos/zenodo/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { App as ZenodoReactSearchKit } from "./App"; 10 | -------------------------------------------------------------------------------- /src/demos/cern-videos/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { App as CERNVideosReactSearchKit } from "./App"; 10 | -------------------------------------------------------------------------------- /src/lib/api/contrib/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export * from "./opensearch"; 10 | export * from "./invenio"; 11 | -------------------------------------------------------------------------------- /src/lib/components/ShouldRender/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { default as ShouldRender } from "./ShouldRender"; 10 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/cern-videos-2/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { App as CERNVideosReactSearchKit2 } from "./App"; 10 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/cern-videos-3/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { App as CERNVideosReactSearchKit3 } from "./App"; 10 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/components/ReactSearchKit/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { AppContext } from "./AppContext"; 10 | export { default as ReactSearchKit } from "./ReactSearchKit"; 11 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export * from "./api"; 10 | export * from "./components"; 11 | export * from "./store"; 12 | export * from "./events"; 13 | export { buildUID } from "./util"; 14 | -------------------------------------------------------------------------------- /docs/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "examples": "docusaurus-examples", 4 | "start": "docusaurus-start", 5 | "build": "docusaurus-build", 6 | "publish-gh-pages": "docusaurus-publish", 7 | "write-translations": "docusaurus-write-translations", 8 | "version": "docusaurus-version", 9 | "rename-version": "docusaurus-rename-version" 10 | }, 11 | "devDependencies": { 12 | "docusaurus": "^1.14.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/api/errors.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | /** 10 | * Custom errors to raise specific expcetions 11 | */ 12 | 13 | export function RequestCancelledError() {} 14 | 15 | RequestCancelledError.prototype = new Error(); 16 | -------------------------------------------------------------------------------- /src/lib/api/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export * from "./contrib"; 10 | export * from "./errors"; 11 | export { UrlHandlerApi } from "./UrlHandlerApi"; 12 | export { UrlParamValidator } from "./UrlParamValidator"; 13 | -------------------------------------------------------------------------------- /src/lib/api/contrib/opensearch/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { OSRequestSerializer } from "./OSRequestSerializer"; 10 | export { OSResponseSerializer } from "./OSResponseSerializer"; 11 | export { OSSearchApi } from "./OSSearchApi"; 12 | -------------------------------------------------------------------------------- /docs/docs/create_your_component.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: create-your-component 3 | title: Create Your Component 4 | --- 5 | 6 | You can create your own component by taking advantage of the [withState](components/with_state.md) component. The `withState` component will inject the current query state, the results state and the function to update the query state and allows you to set new user inputs, trigger a search or display results in a custom way. See the component's documentation for more information. 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import React from "react"; 10 | import ReactDOM from "react-dom"; 11 | import App from "./demos/App"; 12 | import "semantic-ui-css/semantic.min.css"; 13 | 14 | ReactDOM.render(, document.getElementById("root")); 15 | -------------------------------------------------------------------------------- /src/lib/components/Error/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import ErrorComponent from "./Error"; 11 | 12 | export const Error = connect((state) => ({ 13 | loading: state.results.loading, 14 | error: state.results.error, 15 | }))(ErrorComponent); 16 | -------------------------------------------------------------------------------- /docs/website/static/css/custom.css: -------------------------------------------------------------------------------- 1 | /* your custom css */ 2 | 3 | @media only screen and (min-device-width: 360px) and (max-device-width: 736px) { 4 | } 5 | 6 | @media only screen and (min-width: 1024px) { 7 | .sitemap div { 8 | padding-left: 140px; 9 | } 10 | } 11 | 12 | @media only screen and (max-width: 1023px) { 13 | } 14 | 15 | @media only screen and (min-width: 1400px) { 16 | } 17 | 18 | @media only screen and (min-width: 1500px) { 19 | } 20 | 21 | .sitemap div p { 22 | color: rgba(255, 255, 255, 0.6) 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/components/ResultsLoader/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import ResultsLoaderComponent from "./ResultsLoader"; 11 | 12 | export const ResultsLoader = connect((state) => ({ 13 | loading: state.results.loading, 14 | }))(ResultsLoaderComponent); 15 | -------------------------------------------------------------------------------- /src/lib/components/Count/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import CountComponent from "./Count"; 11 | 12 | export const Count = connect((state) => ({ 13 | loading: state.results.loading, 14 | totalResults: state.results.data.total, 15 | }))(CountComponent); 16 | -------------------------------------------------------------------------------- /src/lib/state/reducers/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { combineReducers } from "redux"; 10 | import appReducer from "./app"; 11 | import queryReducer from "./query"; 12 | import resultsReducer from "./results"; 13 | 14 | export default combineReducers({ 15 | app: appReducer, 16 | query: queryReducer, 17 | results: resultsReducer, 18 | }); 19 | -------------------------------------------------------------------------------- /src/lib/components/ResultsGrid/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import ResultsGridComponent from "./ResultsGrid"; 11 | 12 | export const ResultsGrid = connect((state) => ({ 13 | loading: state.results.loading, 14 | totalResults: state.results.data.total, 15 | results: state.results.data.hits, 16 | }))(ResultsGridComponent); 17 | -------------------------------------------------------------------------------- /src/lib/components/ResultsList/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import ResultsListComponent from "./ResultsList"; 11 | 12 | export const ResultsList = connect((state) => ({ 13 | loading: state.results.loading, 14 | totalResults: state.results.data.total, 15 | results: state.results.data.hits, 16 | }))(ResultsListComponent); 17 | -------------------------------------------------------------------------------- /docs/docs/components/results_loader.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: results-loader 3 | title: ResultsLoader 4 | --- 5 | 6 | `ResultsLoader` renders a loading indicator while performing a REST API request and refreshing the results. 7 | 8 | ## Usage 9 | 10 | ```jsx 11 | 12 | ``` 13 | 14 | ## Props 15 | 16 | * **overridableId** `String` *optional* 17 | 18 | An optional string to define a specific overridable id. 19 | 20 | ## Usage when overriding 21 | 22 | ```jsx 23 | const MyResultsLoader = () => { 24 | ... 25 | } 26 | 27 | const overriddenComponents = { 28 | "ResultsLoader.element": MyResultsLoader 29 | }; 30 | ``` 31 | -------------------------------------------------------------------------------- /src/lib/components/ResultsMultiLayout/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import ResultsMultiLayoutComponent from "./ResultsMultiLayout"; 11 | 12 | export const ResultsMultiLayout = connect((state) => ({ 13 | loading: state.results.loading, 14 | totalResults: state.results.data.total, 15 | currentLayout: state.query.layout, 16 | }))(ResultsMultiLayoutComponent); 17 | -------------------------------------------------------------------------------- /src/lib/api/contrib/invenio/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { InvenioRequestSerializer } from "./InvenioRequestSerializer"; 10 | export { InvenioResponseSerializer } from "./InvenioResponseSerializer"; 11 | export { InvenioSearchApi } from "./InvenioSearchApi"; 12 | export { InvenioSuggestionApi } from "./InvenioSuggestionApi"; 13 | export { InvenioRecordsResourcesRequestSerializer } from "./InvenioRecordsResourcesRequestSerializer"; 14 | -------------------------------------------------------------------------------- /docs/docs/components/error.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: error 3 | title: Error 4 | --- 5 | 6 | `Error` renders the errors returned by the REST API, e.g. 4xx or 5xx. 7 | 8 | The component is **not** displayed while executing the search query or if there is no error. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 14 | ``` 15 | 16 | ## Usage when overriding 17 | 18 | ```jsx 19 | const MyError = ({ error }) => { 20 | ... 21 | } 22 | 23 | const overriddenComponents = { 24 | "Error.element": MyError 25 | }; 26 | ``` 27 | 28 | ### Parameters 29 | 30 | * **error** `Object` 31 | 32 | The current value of the `error` `results` state, containing the error returned by the search API connector. 33 | -------------------------------------------------------------------------------- /docs/website/static/css/code-blocks-buttons.css: -------------------------------------------------------------------------------- 1 | /* "Copy" code block button */ 2 | pre { 3 | position: relative; 4 | } 5 | 6 | pre .btnIcon { 7 | position: absolute; 8 | z-index: 2; 9 | cursor: pointer; 10 | border: 1px solid transparent; 11 | padding: 0.5em; 12 | color: #333; 13 | background-color: transparent; 14 | transition: all .25s ease-out; 15 | } 16 | 17 | pre .btnIcon:hover { 18 | text-decoration: none; 19 | } 20 | 21 | .btnIcon__body { 22 | align-items: center; 23 | display: flex; 24 | } 25 | 26 | .btnIcon svg { 27 | fill: currentColor; 28 | margin-right: .4em; 29 | } 30 | 31 | .btnIcon__label { 32 | font-size: 12px; 33 | } 34 | 35 | .btnClipboard { 36 | top: 0.1em; 37 | right: 0.1em; 38 | } 39 | -------------------------------------------------------------------------------- /src/lib/components/Toggle/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryFilters } from "../../state/actions"; 11 | import ToggleComponent from "./Toggle"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQueryFilters: (filter) => dispatch(updateQueryFilters(filter)), 15 | }); 16 | 17 | export const Toggle = connect( 18 | (state) => ({ 19 | userSelectionFilters: state.query.filters, 20 | }), 21 | mapDispatchToProps 22 | )(ToggleComponent); 23 | -------------------------------------------------------------------------------- /src/lib/components/SearchBar/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryString } from "../../state/actions"; 11 | import SearchBarComponent from "./SearchBar"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQueryString: (query) => dispatch(updateQueryString(query)), 15 | }); 16 | 17 | export const SearchBar = connect( 18 | (state) => ({ 19 | queryString: state.query.queryString, 20 | }), 21 | mapDispatchToProps 22 | )(SearchBarComponent); 23 | -------------------------------------------------------------------------------- /src/demos/opensearch/docker/nginx/site.conf: -------------------------------------------------------------------------------- 1 | upstream opensearch { 2 | server os:9200; 3 | } 4 | 5 | server { 6 | listen 5000; 7 | server_name _; 8 | 9 | client_max_body_size 4m; 10 | 11 | error_log /var/log/nginx/opensearch-proxy-errors.log error; 12 | access_log /var/log/nginx/opensearch-proxy-access.log; 13 | 14 | location / { 15 | proxy_redirect off; 16 | 17 | proxy_set_header X-Real-IP $remote_addr; 18 | proxy_set_header X-Forwarded-For $remote_addr; 19 | proxy_set_header Host $host; 20 | proxy_set_header Connection "Keep-Alive"; 21 | proxy_set_header Proxy-Connection "Keep-Alive"; 22 | 23 | proxy_pass http://opensearch; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/components/ActiveFilters/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryFilters } from "../../state/actions"; 11 | import ActiveFiltersComponent from "./ActiveFilters"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQueryFilters: (filter) => dispatch(updateQueryFilters(filter)), 15 | }); 16 | 17 | export const ActiveFilters = connect( 18 | (state) => ({ 19 | filters: state.query.filters, 20 | }), 21 | mapDispatchToProps 22 | )(ActiveFiltersComponent); 23 | -------------------------------------------------------------------------------- /src/lib/components/SortBy/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQuerySortBy } from "../../state/actions"; 11 | import SortByComponent from "./SortBy"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQuerySortBy: (sortByValue) => dispatch(updateQuerySortBy(sortByValue)), 15 | }); 16 | 17 | export const SortBy = connect( 18 | (state) => ({ 19 | loading: state.results.loading, 20 | totalResults: state.results.data.total, 21 | currentSortBy: state.query.sortBy, 22 | }), 23 | mapDispatchToProps 24 | )(SortByComponent); 25 | -------------------------------------------------------------------------------- /src/lib/api/contrib/opensearch/OSResponseSerializer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export class OSResponseSerializer { 10 | constructor() { 11 | this.serialize = this.serialize.bind(this); 12 | } 13 | 14 | /** 15 | * Return a serialized version of the API backend response for the app state `results`. 16 | * @param {object} payload the backend response payload 17 | */ 18 | serialize(payload) { 19 | const { aggregations, hits } = payload; 20 | return { 21 | aggregations: aggregations || {}, 22 | hits: hits.hits.map((hit) => hit._source), 23 | total: hits.total.value, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/components/LayoutSwitcher/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateResultsLayout } from "../../state/actions"; 11 | import LayoutSwitcherComponent from "./LayoutSwitcher"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateLayout: (layout) => dispatch(updateResultsLayout(layout)), 15 | }); 16 | export const LayoutSwitcher = connect( 17 | (state) => ({ 18 | loading: state.results.loading, 19 | currentLayout: state.query.layout, 20 | totalResults: state.results.data.total, 21 | }), 22 | mapDispatchToProps 23 | )(LayoutSwitcherComponent); 24 | -------------------------------------------------------------------------------- /src/lib/components/BucketAggregation/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryFilters } from "../../state/actions"; 11 | import BucketAggregationComponent from "./BucketAggregation"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQueryFilters: (filter) => dispatch(updateQueryFilters(filter)), 15 | }); 16 | 17 | export const BucketAggregation = connect( 18 | (state) => ({ 19 | userSelectionFilters: state.query.filters, 20 | resultsAggregations: state.results.data.aggregations, 21 | }), 22 | mapDispatchToProps 23 | )(BucketAggregationComponent); 24 | -------------------------------------------------------------------------------- /src/lib/components/ResultsPerPage/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryPaginationSize } from "../../state/actions"; 11 | import ResultsPerPageComponent from "./ResultsPerPage"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQuerySize: (size) => dispatch(updateQueryPaginationSize(size)), 15 | }); 16 | 17 | export const ResultsPerPage = connect( 18 | (state) => ({ 19 | loading: state.results.loading, 20 | currentSize: state.query.size, 21 | totalResults: state.results.data.total, 22 | }), 23 | mapDispatchToProps 24 | )(ResultsPerPageComponent); 25 | -------------------------------------------------------------------------------- /src/lib/components/ShouldRender/ShouldRender.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import { Component } from "react"; 11 | import Overridable from "react-overridable"; 12 | 13 | class ShouldRender extends Component { 14 | render() { 15 | const { children, condition } = this.props; 16 | return condition ? children : null; 17 | } 18 | } 19 | 20 | ShouldRender.propTypes = { 21 | condition: PropTypes.bool, 22 | children: PropTypes.node.isRequired, 23 | }; 24 | 25 | ShouldRender.defaultProps = { 26 | condition: true, 27 | }; 28 | 29 | export default Overridable.component("ShouldRender", ShouldRender); 30 | -------------------------------------------------------------------------------- /src/lib/components/SortOrder/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQuerySortOrder } from "../../state/actions"; 11 | import SortOrderComponent from "./SortOrder"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQuerySortOrder: (sortOrderValue) => 15 | dispatch(updateQuerySortOrder(sortOrderValue)), 16 | }); 17 | 18 | export const SortOrder = connect( 19 | (state) => ({ 20 | loading: state.results.loading, 21 | totalResults: state.results.data.total, 22 | currentSortOrder: state.query.sortOrder, 23 | }), 24 | mapDispatchToProps 25 | )(SortOrderComponent); 26 | -------------------------------------------------------------------------------- /src/lib/components/Pagination/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQueryPaginationPage } from "../../state/actions"; 11 | import PaginationComponent from "./Pagination"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQueryPage: (page) => dispatch(updateQueryPaginationPage(page)), 15 | }); 16 | 17 | export const Pagination = connect( 18 | (state) => ({ 19 | currentPage: state.query.page, 20 | currentSize: state.query.size, 21 | loading: state.results.loading, 22 | totalResults: state.results.data.total, 23 | }), 24 | mapDispatchToProps 25 | )(PaginationComponent); 26 | -------------------------------------------------------------------------------- /src/lib/util.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | /** 10 | * Build namespaced unique identifier. 11 | * @param {string} elementName component element name 12 | * @param {string} overridableId unique identifier passed as prop to overridable component 13 | * @param {string} appName the app name 14 | * @return {string} the unique id string with the format 'appName.elementName.overridableId' 15 | */ 16 | export function buildUID(elementName, overridableId = "", appName = "") { 17 | const _overridableId = overridableId ? `.${overridableId}` : ""; 18 | const _appName = appName ? `${appName}.` : ""; 19 | 20 | return `${_appName}${elementName}${_overridableId}`; 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/components/Sort/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { updateQuerySorting } from "../../state/actions"; 11 | import SortComponent from "./Sort"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | updateQuerySorting: (sortBy, sortOrder) => 15 | dispatch(updateQuerySorting(sortBy, sortOrder)), 16 | }); 17 | 18 | export const Sort = connect( 19 | (state) => ({ 20 | currentSortBy: state.query.sortBy, 21 | currentSortOrder: state.query.sortOrder, 22 | loading: state.results.loading, 23 | totalResults: state.results.data.total, 24 | }), 25 | mapDispatchToProps 26 | )(SortComponent); 27 | -------------------------------------------------------------------------------- /src/lib/components/EmptyResults/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { resetQuery } from "../../state/actions"; 11 | import EmptyResultsComponent from "./EmptyResults"; 12 | 13 | const mapDispatchToProps = (dispatch) => ({ 14 | resetQuery: () => dispatch(resetQuery()), 15 | }); 16 | export const EmptyResults = connect( 17 | (state) => ({ 18 | loading: state.results.loading, 19 | totalResults: state.results.data.total, 20 | error: state.results.error, 21 | queryString: state.query.queryString, 22 | userSelectionFilters: state.query.filters, 23 | }), 24 | mapDispatchToProps 25 | )(EmptyResultsComponent); 26 | -------------------------------------------------------------------------------- /src/lib/components/HOC/withState.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import React from "react"; 10 | import { connect } from "react-redux"; 11 | import { updateQueryState } from "../../state/actions"; 12 | 13 | export function withState(Component) { 14 | const WrappedComponent = (props) => ; 15 | const mapStateToProps = (state) => ({ 16 | currentQueryState: state.query, 17 | currentResultsState: state.results, 18 | }); 19 | 20 | const mapDispatchToProps = (dispatch) => ({ 21 | updateQueryState: (queryState) => dispatch(updateQueryState(queryState)), 22 | }); 23 | 24 | return connect(mapStateToProps, mapDispatchToProps)(WrappedComponent); 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/api/contrib/invenio/InvenioResponseSerializer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | /** Default backend response serializer */ 10 | export class InvenioResponseSerializer { 11 | constructor() { 12 | this.serialize = this.serialize.bind(this); 13 | } 14 | 15 | /** 16 | * Return a serialized version of the API backend response for the app state `results`. 17 | * @param {object} payload the backend response payload 18 | */ 19 | serialize(payload) { 20 | const { aggregations, hits, ...extras } = payload; 21 | return { 22 | aggregations: aggregations || {}, 23 | hits: hits.hits, 24 | total: hits.total, 25 | extras: extras, 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/lib/components/Bootstrap/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { 11 | onAppInitialized as _onAppInitialized, 12 | updateQueryState, 13 | updateQueryStateFromUrl, 14 | } from "../../state/actions"; 15 | import BootstrapComponent from "./Bootstrap"; 16 | 17 | const mapDispatchToProps = (dispatch) => ({ 18 | onAppInitialized: (searchOnInit) => dispatch(_onAppInitialized(searchOnInit)), 19 | updateQueryState: (queryState) => dispatch(updateQueryState(queryState)), 20 | searchOnUrlQueryStringChanged: () => dispatch(updateQueryStateFromUrl()), 21 | }); 22 | 23 | export const Bootstrap = connect(null, mapDispatchToProps)(BootstrapComponent); 24 | -------------------------------------------------------------------------------- /src/lib/storeConfig.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export const INITIAL_QUERY_STATE = { 10 | queryString: "", 11 | suggestions: [], 12 | sortBy: null, 13 | sortOrder: null, 14 | page: -1, 15 | size: -1, 16 | filters: [], 17 | hiddenParams: [], 18 | layout: null, 19 | }; 20 | 21 | export const INITIAL_QUERY_STATE_KEYS = Object.keys(INITIAL_QUERY_STATE); 22 | 23 | export const INITIAL_RESULTS_STATE = { 24 | loading: false, 25 | data: { 26 | hits: [], 27 | total: 0, 28 | aggregations: {}, 29 | }, 30 | error: {}, 31 | }; 32 | 33 | export const INITIAL_APP_STATE = { 34 | hasUserChangedSorting: false, 35 | initialSortBy: null, 36 | initialSortOrder: null, 37 | }; 38 | -------------------------------------------------------------------------------- /src/lib/state/reducers/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { SET_QUERY_SORTING, SET_QUERY_SORT_BY, SET_QUERY_SORT_ORDER } from "../types"; 10 | 11 | const appReducer = (state = {}, action) => { 12 | switch (action.type) { 13 | case SET_QUERY_SORTING: 14 | return { 15 | ...state, 16 | hasUserChangedSorting: true, 17 | }; 18 | case SET_QUERY_SORT_BY: 19 | return { 20 | ...state, 21 | hasUserChangedSorting: true, 22 | }; 23 | case SET_QUERY_SORT_ORDER: 24 | return { 25 | ...state, 26 | hasUserChangedSorting: true, 27 | }; 28 | default: 29 | return state; 30 | } 31 | }; 32 | 33 | export default appReducer; 34 | -------------------------------------------------------------------------------- /src/lib/components/AutocompleteSearchBar/AutocompleteSearchBar.scss: -------------------------------------------------------------------------------- 1 | .AutoCompleteText { 2 | position: relative; 3 | z-index: 100; 4 | } 5 | 6 | .AutoCompleteText .input input { 7 | border: none; 8 | border-radius: 0; 9 | } 10 | 11 | .AutoCompleteText .input button { 12 | border: none; 13 | border-radius: 0; 14 | } 15 | 16 | .AutoCompleteText ul { 17 | width: 100%; 18 | position: absolute; 19 | list-style-type: none; 20 | text-align: left; 21 | color: black; 22 | background-color: white; 23 | margin: 0; 24 | padding: 0; 25 | border: 1px solid rgb(224, 225, 226); 26 | border-radius: 0 0 0.3rem 0.3rem; 27 | } 28 | 29 | .AutoCompleteText ul::before { 30 | content: ''; 31 | } 32 | 33 | .AutoCompleteText li { 34 | padding: 0.3em 1em; 35 | cursor: pointer; 36 | } 37 | 38 | .AutoCompleteText li:hover { 39 | text-decoration: underline; 40 | background-color: rgb(224, 225, 226); 41 | border-radius: 0.3rem; 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | permissions: 9 | id-token: write 10 | contents: read 11 | 12 | jobs: 13 | Publish: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v5 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v6 22 | with: 23 | node-version: "20" 24 | registry-url: "https://registry.npmjs.org" 25 | 26 | - name: Update npm 27 | run: | 28 | npm install -g npm@latest 29 | 30 | - name: Install and build 31 | run: | 32 | npm ci 33 | npm run build 34 | 35 | - name: Deploy docs 36 | run: bash deploy_docs.sh 37 | env: 38 | GH_EMAIL: info@inveniosoftware.org 39 | GH_NAME: inveniobot 40 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 41 | 42 | - name: Publish on npmjs 43 | run: npm publish 44 | -------------------------------------------------------------------------------- /docs/docs/components/with_state.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: with-state 3 | title: withState 4 | --- 5 | 6 | `withState` is a high order component, which is used to expose the redux state and 7 | actions to external components. 8 | 9 | The component receives the up-to-date state every time something is changed and 10 | through its props it gains access to 11 | 12 | - `currentResultsState` 13 | - `currentQueryState` 14 | - `updateQueryState` 15 | 16 | > Do **not** mutate directly the state inside your wrapped component. Instead, use the function `updateQueryState` to pass your new query. 17 | 18 | ## Usage 19 | 20 | ```jsx 21 | class _StateLogger extends Component { 22 | render() { 23 | return ( 24 |
25 | Current query state
{JSON.stringify(this.props.currentQueryState, null, 2)}
26 |
27 |
28 | Current results state
{JSON.stringify(this.props.currentResultsState, null, 2)}
29 |
30 | ); 31 | } 32 | } 33 | 34 | const StateLogger = withState(_StateLogger); 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/website/sidebars.json: -------------------------------------------------------------------------------- 1 | { 2 | "*": { 3 | "Guide": [ 4 | "getting-started", 5 | "main-concepts", 6 | "connect-your-rest-apis", 7 | "using-url-parameters", 8 | "filters-aggregations", 9 | "ui-customisation" 10 | ], 11 | "Components": [ 12 | "components/react-searchkit", 13 | "components/active-filters", 14 | "components/bucket-aggregation", 15 | "components/count", 16 | "components/empty-results", 17 | "components/error", 18 | "components/layout-switcher", 19 | "components/pagination", 20 | "components/results-grid", 21 | "components/results-list", 22 | "components/results-loader", 23 | "components/results-multi-layout", 24 | "components/results-per-page", 25 | "components/search-bar", 26 | "components/sort", 27 | "components/sort-by", 28 | "components/sort-order", 29 | "components/toggle", 30 | "components/with-state" 31 | ], 32 | "Extending": ["create-your-component"] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Subset of: https://github.com/github/gitignore/blob/master/Node.gitignore 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | *.lcov 18 | 19 | # Dist folder 20 | dist 21 | 22 | # Dependency directories 23 | node_modules/ 24 | jspm_packages/ 25 | 26 | # Optional npm cache directory 27 | .npm 28 | 29 | # Optional eslint cache 30 | .eslintcache 31 | 32 | # Output of 'npm pack' 33 | *.tgz 34 | 35 | # Yarn Integrity file 36 | .yarn-integrity 37 | 38 | # dotenv environment variables file 39 | .env 40 | .env.test 41 | 42 | # yarn v2 43 | .yarn/cache 44 | .yarn/unplugged 45 | .yarn/build-state.yml 46 | .pnp.* 47 | 48 | # Documentation 49 | /docs/website/build 50 | /docs/website/node_modules 51 | /docs/website/i18n 52 | 53 | # VSCode 54 | .history 55 | 56 | **.DS_Store -------------------------------------------------------------------------------- /docs/docs/components/count.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: count 3 | title: Count 4 | --- 5 | 6 | `Count` renders the number of search results. 7 | 8 | Useful to display the total number of results after a search. 9 | 10 | The component is **not** displayed while executing the search query or if there are no results. 11 | 12 | ## Usage 13 | 14 | ```jsx 15 | 16 | ``` 17 | 18 | ## Props 19 | 20 | - **label** `Function` _optional_ 21 | 22 | An optional function to wrap the component with a prefix and suffix string.
23 | E.g. `label={(cmp) => <> Found {cmp} results} />` 24 | 25 | * **overridableId** `String` *optional* 26 | 27 | An optional string to define a specific overridable id. 28 | 29 | ## Usage when overriding 30 | 31 | ```jsx 32 | const MyCount = ({ totalResults }) => { 33 | return
Found {totalResults} results.
; 34 | } 35 | 36 | const overriddenComponents = { 37 | "Count.element": MyCount 38 | }; 39 | ``` 40 | 41 | ### Parameters 42 | 43 | * **totalResults** `Number` 44 | 45 | The current value of the `total` `results` state representing the number of results. 46 | -------------------------------------------------------------------------------- /.github/workflows/js-tests.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | schedule: 11 | # * is a special character in YAML so you have to quote this string 12 | - cron: '0 2 * * 5' 13 | workflow_dispatch: 14 | inputs: 15 | reason: 16 | description: 'Reason' 17 | required: false 18 | default: 'Manual trigger' 19 | 20 | jobs: 21 | Tests: 22 | runs-on: ubuntu-latest 23 | 24 | strategy: 25 | matrix: 26 | node-version: [22.x, 18.x, 16.x] 27 | 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | 37 | - name: Install & Build 38 | run: npm ci 39 | 40 | - name: Lint 41 | run: npm run lint 42 | 43 | - name: Test 44 | run: npm test 45 | 46 | - name: Coverage 47 | run: npm test -- --coverage 48 | -------------------------------------------------------------------------------- /src/lib/components/AutocompleteSearchBar/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { connect } from "react-redux"; 10 | import { 11 | clearSuggestions, 12 | updateQueryString, 13 | updateSuggestions, 14 | } from "../../state/actions"; 15 | import AutocompleteSearchBarComponent from "../AutocompleteSearchBar/AutocompleteSearchBar"; 16 | 17 | const mapDispatchToProps = (dispatch) => ({ 18 | updateQueryString: (query) => dispatch(updateQueryString(query)), 19 | updateSuggestions: (query) => dispatch(updateSuggestions(query)), 20 | clearSuggestions: () => dispatch(clearSuggestions()), 21 | }); 22 | 23 | const mapStateToProps = (state) => ({ 24 | queryString: state.query.queryString, 25 | suggestions: state.query.suggestions, 26 | }); 27 | 28 | export const AutocompleteSearchBar = connect( 29 | mapStateToProps, 30 | mapDispatchToProps 31 | )(AutocompleteSearchBarComponent); 32 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import localResolve from 'rollup-plugin-local-resolve'; 5 | import peerDepsExternal from 'rollup-plugin-peer-deps-external'; 6 | import postcss from 'rollup-plugin-postcss'; 7 | 8 | import pkg from './package.json'; 9 | 10 | export default { 11 | input: 'src/lib/index.js', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | exports: 'named', 17 | sourcemap: true, 18 | strict: false, 19 | }, 20 | { 21 | file: pkg.module, 22 | format: 'esm', 23 | exports: 'named', 24 | sourcemap: true, 25 | }, 26 | ], 27 | plugins: [ 28 | peerDepsExternal(), 29 | postcss({ 30 | plugins: [], 31 | minimize: true, 32 | sourceMap: 'inline', 33 | }), 34 | localResolve(), 35 | resolve(), 36 | babel({ 37 | presets: ['react-app'], 38 | babelHelpers: 'runtime', 39 | exclude: 'node_modules/**', 40 | }), 41 | commonjs(), 42 | ], 43 | }; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2015-2019 CERN. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/components/HOC/withState.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { shallow } from "enzyme"; 10 | import React from "react"; 11 | import configureMockStore from "redux-mock-store"; 12 | import { withState } from "./withState"; 13 | 14 | const mockStore = configureMockStore(); 15 | 16 | describe("withState tests", () => { 17 | let WithStateComponent; 18 | let store; 19 | beforeEach(() => { 20 | store = mockStore({}); 21 | store.clearActions(); 22 | const mockedComponent = jest.fn(); 23 | WithStateComponent = withState(mockedComponent); 24 | }); 25 | 26 | it("should find the props exposed by withState", async () => { 27 | const wrapper = shallow(); 28 | const props = wrapper.children(0).props(); 29 | expect("currentResultsState" in props).toBe(true); 30 | expect("currentQueryState" in props).toBe(true); 31 | expect("updateQueryState" in props).toBe(true); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /docs/docs/components/empty_results.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: empty-results 3 | title: EmptyResults 4 | --- 5 | 6 | `EmptyResults` is a component that renders in case of 0 results. 7 | 8 | The component is **not** displayed while executing the search query, when there is no error or when the number of 9 | results is greater than 0. 10 | 11 | ## Usage 12 | 13 | ```jsx 14 | 15 | ``` 16 | 17 | ## Props 18 | 19 | * **overridableId** `String` *optional* 20 | 21 | An optional string to define a specific overridable id. 22 | 23 | ## Usage when overriding 24 | 25 | ```jsx 26 | const MyEmptyResults = ({ queryString, resetQuery, extraContent }) => { 27 | ... 28 | } 29 | 30 | const overriddenComponents = { 31 | "EmptyResults.element": MyEmptyResults 32 | }; 33 | ``` 34 | 35 | ### Parameters 36 | 37 | * **queryString** `String` 38 | 39 | The current value of the `queryString` `query` state. 40 | 41 | * **resetQuery** `Function` 42 | 43 | A function to call to reset the current search query. 44 | 45 | * **extraContent** `React component` 46 | 47 | Any extra React component to be rendered. 48 | 49 | * **userSelectionFilters** `Array` 50 | 51 | List of the currently selected filters. 52 | -------------------------------------------------------------------------------- /src/demos/opensearch/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | proxy: 3 | build: ./nginx 4 | container_name: react-searchkit-nginx 5 | links: 6 | - os 7 | ports: 8 | - "5000:5000" 9 | os: 10 | image: opensearchproject/opensearch:2.18.0 11 | container_name: react-searchkit-os 12 | restart: "always" 13 | volumes: 14 | - osdata01:/usr/share/opensearch/data 15 | environment: 16 | - bootstrap.memory_lock=true 17 | - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m 18 | - OPENSEARCH_INITIAL_ADMIN_PASSWORD=123456789 19 | - DISABLE_INSTALL_DEMO_CONFIG=true 20 | - DISABLE_SECURITY_PLUGIN=true 21 | - discovery.type=single-node 22 | - http.cors.enabled=true 23 | - http.cors.allow-origin=* 24 | - http.cors.allow-credentials=false 25 | - http.cors.allow-methods=OPTIONS,HEAD,GET,POST,PUT,DELETE 26 | - http.cors.allow-headers=X-Requested-With,X-Auth-Token,Content-Type,Content-Length 27 | ulimits: 28 | memlock: 29 | soft: -1 30 | hard: -1 31 | nofile: 32 | soft: 65536 33 | hard: 65536 34 | mem_limit: 2g 35 | ports: 36 | - "9200:9200" 37 | - "9600:9600" 38 | 39 | volumes: 40 | osdata01: 41 | 42 | -------------------------------------------------------------------------------- /src/lib/components/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export { ActiveFilters } from "./ActiveFilters"; 10 | export { AutocompleteSearchBar } from "./AutocompleteSearchBar"; 11 | export { BucketAggregation } from "./BucketAggregation"; 12 | export { Count } from "./Count"; 13 | export { EmptyResults } from "./EmptyResults"; 14 | export { Error } from "./Error"; 15 | export * from "./HOC"; 16 | export { LayoutSwitcher } from "./LayoutSwitcher"; 17 | export { Pagination } from "./Pagination"; 18 | export { AppContext, ReactSearchKit } from "./ReactSearchKit"; 19 | export { ResultsGrid } from "./ResultsGrid"; 20 | export { ResultsList } from "./ResultsList"; 21 | export { ResultsLoader } from "./ResultsLoader"; 22 | export { ResultsMultiLayout } from "./ResultsMultiLayout"; 23 | export { ResultsPerPage } from "./ResultsPerPage"; 24 | export { SearchBar } from "./SearchBar"; 25 | export { Sort } from "./Sort"; 26 | export { SortBy } from "./SortBy"; 27 | export { SortOrder } from "./SortOrder"; 28 | export { Toggle } from "./Toggle"; 29 | -------------------------------------------------------------------------------- /docs/docs/components/active_filters.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: active-filters 3 | title: ActiveFilters 4 | --- 5 | 6 | `ActiveFilters` renders the current selected filters by the user as a list of labels. 7 | 8 | Each label has a `close` icon which can be clicked to remove the selected filter. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 14 | ``` 15 | 16 | ## Props 17 | 18 | * **overridableId** `String` *optional* 19 | 20 | An optional string to define a specific overridable id. 21 | 22 | ## Usage when overriding 23 | 24 | ```jsx 25 | const MyActiveFilters = ({ filters, removeActiveFilter, getLabel }) => { 26 | ... 27 | } 28 | 29 | const overriddenComponents = { 30 | "ActiveFilters.element": MyActiveFilters 31 | }; 32 | ``` 33 | 34 | ### Parameters 35 | 36 | * **filters** `Array` 37 | 38 | The `filters` `query` state. It contains the list of active filters selected by the user. Each element is a list `[ "", "" ]`. 39 | 40 | * **removeActiveFilter** `Function` 41 | 42 | Function to be called with the active filter list as parameter if you want to remove one of the active filters `removeActiveFilter()`. 43 | 44 | * **getLabel** `Function` 45 | 46 | Function to be called to get a display label for the given active filter `getLabel(filter)`. 47 | -------------------------------------------------------------------------------- /src/demos/opensearch/docker/os2-mappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "mappings": { 3 | "properties": { 4 | "id": { 5 | "type": "keyword" 6 | }, 7 | "index": { 8 | "type": "short" 9 | }, 10 | "guid": { 11 | "type": "keyword" 12 | }, 13 | "picture": { 14 | "type": "keyword" 15 | }, 16 | "age": { 17 | "type": "short" 18 | }, 19 | "first_name": { 20 | "type": "text" 21 | }, 22 | "last_name": { 23 | "type": "text" 24 | }, 25 | "phone": { 26 | "type": "text" 27 | }, 28 | "address": { 29 | "type": "text" 30 | }, 31 | "about": { 32 | "type": "text" 33 | }, 34 | "registered": { 35 | "type": "text" 36 | }, 37 | "location": { 38 | "type": "geo_point" 39 | }, 40 | "date": { 41 | "type": "date" 42 | }, 43 | "tags": { 44 | "type": "keyword" 45 | }, 46 | "employee_type": { 47 | "type": "object", 48 | "properties": { 49 | "type": { 50 | "type": "keyword" 51 | }, 52 | "subtype": { 53 | "type": "keyword" 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/docs/components/results_multi_layout.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: results-multi-layout 3 | title: ResultsMultiLayout 4 | --- 5 | 6 | `ResultsMultiLayout` is an uncontrolled component that listens to the application's `layout` state and 7 | renders results in a `list` ([ResultsList](components/results_list.md)) or `grid` ([ResultsGrid](components/results_grid.md)) 8 | respectively. Can be used in combination with the `LayoutSwitcher` component to change the results layout in controllable way. 9 | By default it renders results as a list. 10 | 11 | ## Usage 12 | 13 | ```jsx 14 | 15 | ``` 16 | 17 | ## Props 18 | 19 | * **overridableId** `String` *optional* 20 | 21 | An optional string to define a specific overridable id. 22 | 23 | * **onResultsRendered** `func` *optional* 24 | 25 | An optional function to define set of actions to be performed after the component is rendered. For example: render MathJax to display mathematical equations. 26 | 27 | ## Usage when overriding 28 | 29 | ```jsx 30 | const MyResultsMultiLayout = ({ layout }) => { 31 | ... 32 | } 33 | 34 | const overriddenComponents = { 35 | "ResultsMultiLayout.element": MyResultsMultiLayout 36 | }; 37 | ``` 38 | 39 | ### Parameters 40 | 41 | * **layout** `String` 42 | 43 | The current selected layout. Possible values: `list` or `grid`. 44 | -------------------------------------------------------------------------------- /src/lib/state/reducers/results.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { RESULTS_FETCH_ERROR, RESULTS_FETCH_SUCCESS, RESULTS_LOADING } from "../types"; 10 | 11 | const resultsReducer = (state = {}, action) => { 12 | switch (action.type) { 13 | case RESULTS_LOADING: 14 | return { 15 | ...state, 16 | loading: true, 17 | data: { 18 | ...state.data, 19 | }, 20 | }; 21 | case RESULTS_FETCH_SUCCESS: 22 | return { 23 | loading: false, 24 | data: { 25 | ...state.data, 26 | aggregations: action.payload.aggregations, 27 | hits: action.payload.hits, 28 | total: action.payload.total, 29 | }, 30 | error: {}, 31 | }; 32 | case RESULTS_FETCH_ERROR: 33 | return { 34 | loading: false, 35 | data: { 36 | ...state.data, 37 | aggregations: {}, 38 | hits: [], 39 | total: 0, 40 | }, 41 | error: action.payload.error, 42 | }; 43 | default: 44 | return state; 45 | } 46 | }; 47 | 48 | export default resultsReducer; 49 | -------------------------------------------------------------------------------- /docs/docs/components/layout_switcher.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: layout-switcher 3 | title: LayoutSwitcher 4 | --- 5 | 6 | `LayoutSwitcher` renders a pair of buttons that allows the user to change results layout between `list` and `grid`. 7 | 8 | It is normally used in combination with `ResultMultiLayout`, which wraps `ResultsList` and `ResultsGrid`. 9 | 10 | The component is **not** displayed while executing the search query, if the current layout is not set or if 11 | there are no results. 12 | 13 | ## Usage 14 | 15 | ```jsx 16 | 17 | ``` 18 | 19 | ## Props 20 | 21 | * **defaultLayout** `String` *optional* 22 | 23 | The default layout, one of `list` or `grid`. Default value: `list`. 24 | 25 | * **overridableId** `String` *optional* 26 | 27 | An optional string to define a specific overridable id. 28 | 29 | ## Usage when overriding 30 | 31 | ```jsx 32 | const MyLayoutSwitcher = ({ currentLayout, onLayoutChange }) => { 33 | ... 34 | } 35 | 36 | const overriddenComponents = { 37 | "LayoutSwitcher.element": MyLayoutSwitcher 38 | }; 39 | ``` 40 | 41 | ### Parameters 42 | 43 | * **currentLayout** `String` 44 | 45 | The current value of the `layout` `query` state. 46 | 47 | * **onLayoutChange** `function` 48 | 49 | The function to call when the user wants to change the current layout to change the `query` state. `onLayoutChange(newValue)` 50 | -------------------------------------------------------------------------------- /docs/docs/components/results_list.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: results-list 3 | title: ResultsList 4 | --- 5 | 6 | `ResultsList` renders the list of results as a simple list. 7 | 8 | ## Usage 9 | 10 | ```jsx 11 | 12 | ``` 13 | 14 | ## Props 15 | 16 | * **overridableId** `String` *optional* 17 | 18 | An optional string to define a specific overridable id. 19 | 20 | * **onResultsRendered** `func` *optional* 21 | 22 | An optional function to define set of actions to be performed after the component is rendered. For example: render MathJax to display mathematical equations. 23 | 24 | ## Usage when overriding 25 | 26 | ```jsx 27 | const MyResultsListContainer = ({ results, resultsPerRow }) => { 28 | ... 29 | } 30 | 31 | const MyResultsListItem = ({ results, resultsPerRow }) => { 32 | ... 33 | } 34 | 35 | const overriddenComponents = { 36 | "ResultsList.container": MyResultsListContainer 37 | "ResultsList.item": MyResultsListItem 38 | }; 39 | ``` 40 | 41 | ### ResultsListContainer parameters 42 | 43 | Component that wraps the list of result's items. 44 | 45 | * **results** `Array` 46 | 47 | The list of results to display to the user. 48 | 49 | ### ResultsListItem parameters 50 | 51 | Component that will render a specicif result item. 52 | 53 | * **result** `Object` 54 | 55 | The result object to render. 56 | 57 | * **index** `Number` 58 | 59 | The index number of the result object. 60 | 61 | -------------------------------------------------------------------------------- /src/lib/api/contrib/opensearch/OSRequestSerializer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import _isEmpty from "lodash/isEmpty"; 10 | 11 | export class OSRequestSerializer { 12 | constructor() { 13 | this.serialize = this.serialize.bind(this); 14 | } 15 | 16 | /** 17 | * Return a serialized version of the app state `query` for the API backend. 18 | * @param {object} stateQuery the `query` state to serialize 19 | */ 20 | serialize(stateQuery) { 21 | const { queryString, sortBy, sortOrder, page, size } = stateQuery; 22 | 23 | const bodyParams = {}; 24 | if (!_isEmpty(queryString)) { 25 | bodyParams["query"] = { 26 | query_string: { 27 | query: queryString, 28 | }, 29 | }; 30 | } 31 | if (sortBy) { 32 | const sortObj = {}; 33 | sortObj[sortBy] = sortOrder && sortOrder === "desc" ? "desc" : "asc"; 34 | bodyParams["sort"] = sortObj; 35 | } 36 | 37 | if (size > 0) { 38 | bodyParams["size"] = size; 39 | } 40 | 41 | if (page > 0) { 42 | const s = size > 0 ? size : 0; 43 | const from = (page - 1) * s; 44 | bodyParams["from"] = from; 45 | } 46 | 47 | return bodyParams; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/lib/state/types/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | export const SET_QUERY_COMPONENT_INITIAL_STATE = "SET_QUERY_COMPONENT_INITIAL_STATE"; 10 | export const SET_QUERY_STRING = "SET_QUERY_STRING"; 11 | export const SET_QUERY_SORTING = "SET_QUERY_SORTING"; 12 | export const SET_QUERY_SORT_BY = "SET_QUERY_SORT_BY"; 13 | export const SET_QUERY_SORT_ORDER = "SET_QUERY_SORT_ORDER"; 14 | export const SET_QUERY_STATE = "SET_QUERY_STATE"; 15 | export const SET_QUERY_PAGINATION_PAGE = "SET_QUERY_PAGINATION_PAGE"; 16 | export const SET_QUERY_PAGINATION_SIZE = "SET_QUERY_PAGINATION_SIZE"; 17 | export const SET_QUERY_FILTERS = "SET_QUERY_FILTERS"; 18 | export const SET_QUERY_SUGGESTIONS = "SET_QUERY_SUGGESTIONS"; 19 | export const SET_SUGGESTION_STRING = "SET_SUGGESTION_STRING"; 20 | export const CLEAR_QUERY_SUGGESTIONS = "CLEAR_QUERY_SUGGESTIONS"; 21 | 22 | export const RESULTS_LOADING = "RESULTS_LOADING"; 23 | export const RESULTS_FETCH_SUCCESS = "RESULTS_FETCH_SUCCESS"; 24 | export const RESULTS_FETCH_ERROR = "RESULTS_FETCH_ERROR"; 25 | export const RESULTS_UPDATE_LAYOUT = "RESULTS_UPDATE_LAYOUT"; 26 | export const SET_RESULTS_COMPONENT_INITIAL_STATE = 27 | "SET_RESULTS_COMPONENT_INITIAL_STATE"; 28 | export const RESET_QUERY = "RESET_QUERY"; 29 | -------------------------------------------------------------------------------- /src/lib/components/ResultsLoader/ResultsLoader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { useContext } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { Loader } from "semantic-ui-react"; 13 | import { AppContext } from "../ReactSearchKit"; 14 | 15 | function ResultsLoader({ children, loading, overridableId }) { 16 | return loading ? : children; 17 | } 18 | 19 | ResultsLoader.propTypes = { 20 | children: PropTypes.node.isRequired, 21 | overridableId: PropTypes.string, 22 | /* REDUX */ 23 | loading: PropTypes.bool.isRequired, 24 | }; 25 | 26 | ResultsLoader.defaultProps = { 27 | overridableId: "", 28 | }; 29 | 30 | const Element = ({ overridableId }) => { 31 | const { buildUID } = useContext(AppContext); 32 | 33 | return ( 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | Element.propTypes = { 41 | overridableId: PropTypes.string, 42 | }; 43 | 44 | Element.defaultProps = { 45 | overridableId: "", 46 | }; 47 | 48 | export default Overridable.component("ResultsLoader", ResultsLoader); 49 | -------------------------------------------------------------------------------- /docs/docs/components/results_grid.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: results-grid 3 | title: ResultsGrid 4 | --- 5 | 6 | `ResultsGrid` renders the list of results as a grid. 7 | 8 | ## Usage 9 | 10 | ```jsx 11 | 12 | ``` 13 | 14 | ## Props 15 | 16 | * **resultsPerRow** `int` *optional* 17 | 18 | The number of results to display in each row. Default value: `3`. 19 | 20 | * **overridableId** `String` *optional* 21 | 22 | An optional string to define a specific overridable id. 23 | 24 | * **onResultsRendered** `func` *optional* 25 | 26 | An optional function to define set of actions to be performed after the component is rendered. For example: render MathJax to display mathematical equations. 27 | 28 | ## Usage when overriding 29 | 30 | ```jsx 31 | const MyResultsGridContainer = ({ results, resultsPerRow }) => { 32 | ... 33 | } 34 | 35 | const MyResultsGridItem = ({ results, resultsPerRow }) => { 36 | ... 37 | } 38 | 39 | const overriddenComponents = { 40 | "ResultsGrid.container": MyResultsGridContainer 41 | "ResultsGrid.item": MyResultsGridItem 42 | }; 43 | ``` 44 | 45 | ### ResultsGridContainer parameters 46 | 47 | Component that wraps the grid of result's items. 48 | 49 | * **results** `Array` 50 | 51 | The list of results to display to the user. 52 | 53 | * **resultsPerRow** `Number` 54 | 55 | The prop `resultsPerRow` defined when using the component. 56 | 57 | 58 | ### ResultsGridItem parameters 59 | 60 | Component that will render a specicif result item. 61 | 62 | * **result** `Object` 63 | 64 | The result object to render. 65 | 66 | * **index** `Number` 67 | 68 | The index number of the result object. 69 | -------------------------------------------------------------------------------- /src/lib/components/Error/Error.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import _isEmpty from "lodash/isEmpty"; 10 | import PropTypes from "prop-types"; 11 | import React, { useContext } from "react"; 12 | import Overridable from "react-overridable"; 13 | import { AppContext } from "../ReactSearchKit"; 14 | import { ShouldRender } from "../ShouldRender"; 15 | 16 | function Error({ loading, error, overridableId }) { 17 | return ( 18 | 19 | 20 | 21 | ); 22 | } 23 | 24 | Error.propTypes = { 25 | overridableId: PropTypes.string, 26 | /* REDUX */ 27 | loading: PropTypes.bool.isRequired, 28 | error: PropTypes.object.isRequired, 29 | }; 30 | 31 | Error.defaultProps = { 32 | overridableId: "", 33 | }; 34 | 35 | const Element = ({ error, overridableId }) => { 36 | const { buildUID } = useContext(AppContext); 37 | 38 | return ( 39 | 40 |
Oops! Something went wrong while fetching results.
41 |
42 | ); 43 | }; 44 | 45 | Element.propTypes = { 46 | overridableId: PropTypes.string, 47 | /* REDUX */ 48 | error: PropTypes.object.isRequired, 49 | }; 50 | 51 | Element.defaultProps = { 52 | overridableId: "", 53 | }; 54 | 55 | export default Overridable.component("Error", Error); 56 | -------------------------------------------------------------------------------- /docs/docs/components/toggle.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: toggle 3 | title: Toggle 4 | --- 5 | 6 | `Toggle` renders a Toggle Checkbox in a Card element providing a filter for the performed search. 7 | 8 | ## Usage 9 | 10 | ```jsx 11 | 16 | ``` 17 | 18 | ## Props 19 | 20 | * **title** `String` *optional* 21 | 22 | The optional title for the Card element. 23 | 24 | * **label** `label` *optional* 25 | 26 | An optional label to for the Checkbox element. 27 | 28 | * **filterValue** `Array` 29 | 30 | An array containing the filter to be applied to the search query when active. 31 | 32 | * **overridableId** `String` *optional* 33 | 34 | An optional string to define a specific overridable id. 35 | 36 | ## Usage when overriding 37 | 38 | ```jsx 39 | const MyCount = ({ totalResults }) => { 40 | return
Found {totalResults} results.
; 41 | } 42 | 43 | const overriddenComponents = { 44 | "SearchFilters.ToggleComponent.element": MyCount 45 | }; 46 | ``` 47 | 48 | ### Parameters 49 | 50 | * **title** `String` *optional* 51 | 52 | The optional title for the Card element. 53 | 54 | * **label** `label` *optional* 55 | 56 | An optional label to for the Checkbox element. 57 | 58 | * **filterValue** `Array` 59 | 60 | An array containing the filter to be applied to the search query when active. 61 | 62 | * **userSelectionFilters** `Array` 63 | 64 | The list of currently selected filters by the user. 65 | 66 | * **updateQueryFilters** `Function` 67 | 68 | The function to call to add or remove a filter from the list of selected ones `updateQueryFilters(filter)`. 69 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/lib/api/UrlParamValidator.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import _isArray from "lodash/isArray"; 10 | import _isNumber from "lodash/isNumber"; 11 | 12 | /** Default implementation for a param validator class */ 13 | export class UrlParamValidator { 14 | /** 15 | * Return true if the param value is valid, false otherwise 16 | * @param {object} urlHandler the url handler 17 | * @param {string} key the parameter key 18 | * @param {string} value the parameter value 19 | */ 20 | isValid = (urlHandler, key, value) => { 21 | switch (key) { 22 | case "queryString": 23 | case "sortBy": 24 | return true; 25 | case "sortOrder": 26 | return ["asc", "desc"].includes(value); 27 | case "page": 28 | case "size": 29 | return _isNumber(value) && value > 0; 30 | case "layout": 31 | return ["grid", "list"].includes(value); 32 | case "filters": 33 | case "hiddenParams": { 34 | const array = _isArray(value) ? value : [value]; 35 | const cKvSep = ":", 36 | cChildSep = urlHandler.urlFilterSeparator; 37 | const pLiteral = `[^\\${cKvSep}\\${cChildSep}]*`, 38 | pKeyValue = `${pLiteral}\\${cKvSep}${pLiteral}`, 39 | pAll = `${pKeyValue}(\\${cChildSep}${pKeyValue})*`; 40 | const regex = new RegExp(`^${pAll}$`); 41 | return array.every((filter) => String(filter).match(regex)); 42 | } 43 | default: 44 | return false; 45 | } 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /docs/docs/components/search_bar.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: search-bar 3 | title: SearchBar 4 | --- 5 | 6 | `SearchBar` renders an input box for queries and a Search button. 7 | 8 | As default behavior, the search can be triggered clicking on the button or pressing the `enter` keystroke. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 14 | ``` 15 | 16 | ## Props 17 | 18 | * **placeholder** `String` *optional* 19 | 20 | The placeholder value of the search box. Default value: `Type something`. 21 | 22 | * **overridableId** `String` *optional* 23 | 24 | An optional string to define a specific overridable id. 25 | 26 | ## Usage when overriding 27 | 28 | ```jsx 29 | const MySearchBar = ({ queryString, onBtnSearchClick, onInputChange, onKeyPress, placeholder, actionProps, uiProps }) => { 30 | ... 31 | } 32 | 33 | const overriddenComponents = { 34 | "SearchBar.element": MySearchBar 35 | }; 36 | ``` 37 | 38 | ### Parameters 39 | 40 | * **placeholder** `String` 41 | 42 | The prop `placeholder` defined when using the component. 43 | 44 | * **queryString** `String` 45 | 46 | The current value of the `queryString` `query` state. 47 | 48 | * **onInputChange** `Function` 49 | 50 | A function to be called every time the user changes the query string to change the `query` state. `onInputChange(queryString)` 51 | 52 | * **onBtnSearchClick** `Function` 53 | 54 | A function to be called when the user clicks on the the search button. 55 | 56 | * **onKeyPress** `Function` 57 | 58 | A function to be called on key press to handle the Enter button pressed. 59 | 60 | * **actionProps** `Object` 61 | 62 | Semantic-UI props for the action button. 63 | 64 | * **uiProps** `Object` 65 | 66 | Semantic-UI props for the search bar. 67 | -------------------------------------------------------------------------------- /src/demos/opensearch/Results.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component } from "react"; 11 | import { Grid } from "semantic-ui-react"; 12 | import { 13 | ActiveFilters, 14 | Count, 15 | LayoutSwitcher, 16 | Pagination, 17 | ResultsMultiLayout, 18 | } from "../../lib/components"; 19 | 20 | export class Results extends Component { 21 | render() { 22 | const { currentResultsState } = this.props; 23 | const { data } = currentResultsState; 24 | const { total } = data; 25 | return total ? ( 26 | <> 27 | 28 | 29 | 30 | 31 | 32 | 33 | <>Found {cmp}} /> 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | ) : null; 48 | } 49 | } 50 | 51 | Results.propTypes = { 52 | currentResultsState: PropTypes.array.isRequired, 53 | }; 54 | 55 | Results.defaultProps = {}; 56 | -------------------------------------------------------------------------------- /docs/docs/components/sort_by.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: sort-by 3 | title: SortBy 4 | --- 5 | 6 | `SortBy` renders a list of possible sort options. 7 | 8 | The component is **not** displayed while executing the search query or if there are no results. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 16 | ``` 17 | 18 | ## Props 19 | 20 | * **values** `Array` 21 | 22 | A list of possible values, where each value has the format `{ text: "Creation Date", value: "created" }`. 23 | 24 | - **label** `function` _optional_ 25 | 26 | An optional function to wrap the component with a prefix and suffix string.
27 | E.g. `label={(cmp) => <> sorted by {cmp}}` 28 | 29 | * **overridableId** `String` *optional* 30 | 31 | An optional string to define a specific overridable id. 32 | 33 | ## Usage when overriding 34 | 35 | ```jsx 36 | const MySortBy = ({ currentSortBy, options, onValueChange, ariaLabel, selectOnNavigation }) => { 37 | ... 38 | } 39 | 40 | const overriddenComponents = { 41 | "SortBy.element": MySortBy 42 | }; 43 | ``` 44 | 45 | ### Parameters 46 | 47 | * **currentSortBy** `String` 48 | 49 | The current value of the `sortBy` `query` state. 50 | 51 | * **options** `Array` 52 | 53 | The options passed as prop to the component. 54 | 55 | * **onValueChange** `function` 56 | 57 | The function to call when the user changes the sort by field value to change the `query` state. `onValueChange(newValue)` 58 | 59 | * **ariaLabel** `String` 60 | 61 | The ARIA (Accessibility) label to add to the component. 62 | 63 | * **selectOnNavigation** `Boolean` 64 | 65 | When using a dropdown, set if the `onValueChange` should be called when the new dropdown item is selected with arrow keys, or only on click or on enter. 66 | 67 | -------------------------------------------------------------------------------- /docs/docs/components/sort_order.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: sort-order 3 | title: SortOrder 4 | --- 5 | 6 | `SortOrder` renders a list of the possible sort order values, i.e. ascending/descending. 7 | 8 | The component is **not** displayed while executing the search query or if there are no results. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 16 | ``` 17 | 18 | ## Props 19 | 20 | * **values** `Array` 21 | 22 | A list of possible values, where each value has the format `{ text: "Asc", value: "asc" }`. 23 | 24 | - **label** `function` _optional_ 25 | 26 | An optional function to wrap the component with a prefix and suffix string.
27 | E.g. `label={(cmp) => <> sorted by {cmp}}` 28 | 29 | * **overridableId** `String` *optional* 30 | 31 | An optional string to define a specific overridable id. 32 | 33 | ## Usage when overriding 34 | 35 | ```jsx 36 | const MySortOrder = ({ currentSortOrder, options, onValueChange, ariaLabel, selectOnNavigation }) => { 37 | ... 38 | } 39 | 40 | const overriddenComponents = { 41 | "SortOrder.element": MySortOrder 42 | }; 43 | ``` 44 | 45 | ### Parameters 46 | 47 | * **currentSortOrder** `String` 48 | 49 | The current value of the `sortOrder` `query` state. 50 | 51 | * **options** `Array` 52 | 53 | The options passed as prop to the component. 54 | 55 | * **onValueChange** `function` 56 | 57 | The function to call when the user changes the sort order field value to change the `query` state. `onValueChange(newValue)` 58 | 59 | * **ariaLabel** `String` 60 | 61 | The ARIA (Accessibility) label to add to the component. 62 | 63 | * **selectOnNavigation** `Boolean` 64 | 65 | When using a dropdown, set if the `onValueChange` should be called when the new dropdown item is selected with arrow keys, or only on click or on enter. 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/lib/components/Count/Count.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component, useContext } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { Label } from "semantic-ui-react"; 13 | import { AppContext } from "../ReactSearchKit"; 14 | import { ShouldRender } from "../ShouldRender"; 15 | 16 | class Count extends Component { 17 | render() { 18 | const { loading, totalResults, label, overridableId } = this.props; 19 | return ( 20 | 0}> 21 | {label()} 22 | 23 | ); 24 | } 25 | } 26 | 27 | Count.propTypes = { 28 | label: PropTypes.func, 29 | overridableId: PropTypes.string, 30 | /* REDUX */ 31 | loading: PropTypes.bool.isRequired, 32 | totalResults: PropTypes.number.isRequired, 33 | }; 34 | 35 | Count.defaultProps = { 36 | label: (cmp) => cmp, 37 | overridableId: "", 38 | }; 39 | 40 | const Element = ({ totalResults, overridableId }) => { 41 | const { buildUID } = useContext(AppContext); 42 | const _overridableId = buildUID("Count.element", overridableId); 43 | 44 | return ( 45 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | Element.propTypes = { 52 | totalResults: PropTypes.number.isRequired, 53 | overridableId: PropTypes.string, 54 | }; 55 | 56 | Element.defaultProps = { 57 | overridableId: "", 58 | }; 59 | 60 | export default Overridable.component("Count", Count); 61 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/cern-videos-2/App.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import React from "react"; 10 | import { InvenioSearchApi } from "../../../lib/api/contrib/invenio"; 11 | import { 12 | EmptyResults, 13 | Error, 14 | ReactSearchKit, 15 | ResultsLoader, 16 | withState, 17 | } from "../../../lib/components"; 18 | import { Results } from "../Results"; 19 | 20 | const OnResults = withState(Results); 21 | 22 | const sortValues = [ 23 | { 24 | text: "Newest", 25 | sortBy: "mostrecent", 26 | sortOrder: "asc", 27 | }, 28 | { 29 | text: "Oldest", 30 | sortBy: "oldest", 31 | sortOrder: "asc", 32 | }, 33 | { 34 | text: "Best match", 35 | sortBy: "bestmatch", 36 | sortOrder: "asc", 37 | }, 38 | ]; 39 | 40 | const resultsPerPageValues = [ 41 | { 42 | text: "10", 43 | value: 10, 44 | }, 45 | { 46 | text: "20", 47 | value: 20, 48 | }, 49 | ]; 50 | 51 | const initialState = { 52 | sortBy: "bestmatch", 53 | sortOrder: "asc", 54 | layout: "list", 55 | page: 1, 56 | size: 10, 57 | }; 58 | 59 | const searchApi = new InvenioSearchApi({ 60 | axios: { 61 | url: "https://videos.cern.ch/api/records/", 62 | timeout: 5000, 63 | }, 64 | }); 65 | 66 | export const App = () => ( 67 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ); 84 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/cern-videos-3/App.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import React from "react"; 10 | import { InvenioSearchApi } from "../../../lib/api/contrib/invenio"; 11 | import { 12 | EmptyResults, 13 | Error, 14 | ReactSearchKit, 15 | ResultsLoader, 16 | withState, 17 | } from "../../../lib/components"; 18 | import { Results } from "../Results"; 19 | 20 | const OnResults = withState(Results); 21 | 22 | const sortValues = [ 23 | { 24 | text: "Newest", 25 | sortBy: "mostrecent", 26 | sortOrder: "asc", 27 | }, 28 | { 29 | text: "Oldest", 30 | sortBy: "oldest", 31 | sortOrder: "asc", 32 | }, 33 | { 34 | text: "Best match", 35 | sortBy: "bestmatch", 36 | sortOrder: "asc", 37 | }, 38 | ]; 39 | 40 | const resultsPerPageValues = [ 41 | { 42 | text: "10", 43 | value: 10, 44 | }, 45 | { 46 | text: "20", 47 | value: 20, 48 | }, 49 | ]; 50 | 51 | const initialState = { 52 | sortBy: "bestmatch", 53 | sortOrder: "asc", 54 | layout: "list", 55 | page: 1, 56 | size: 10, 57 | }; 58 | 59 | const searchApi = new InvenioSearchApi({ 60 | axios: { 61 | url: "https://videos.cern.ch/api/records/", 62 | timeout: 5000, 63 | }, 64 | }); 65 | 66 | export const App = () => ( 67 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ); 84 | -------------------------------------------------------------------------------- /docs/website/core/Footer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2023 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | const React = require("react"); 10 | 11 | const siteConfig = require(process.cwd() + "/siteConfig.js"); 12 | 13 | class Footer extends React.Component { 14 | render() { 15 | return ( 16 | 55 | ); 56 | } 57 | } 58 | 59 | module.exports = Footer; 60 | -------------------------------------------------------------------------------- /docs/docs/components/results_per_page.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: results-per-page 3 | title: ResultsPerPage 4 | --- 5 | 6 | `ResultsPerPage` renders a list of the possible number of results per page. 7 | 8 | The component is **not** displayed while executing the search query or if there are no results. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 16 | ``` 17 | 18 | ## Props 19 | 20 | * **values** `Array` 21 | 22 | A list of possible values, where each value has the format `{ text: "Fifty", value: 50 }`. 23 | 24 | - **label** `function` _optional_ 25 | 26 | An optional function to wrap the component with a prefix and suffix string.
27 | E.g. `label={(cmp) => <> Show {cmp} results per page}` 28 | 29 | * **overridableId** `String` *optional* 30 | 31 | An optional string to define a specific overridable id. 32 | 33 | ## Usage when overriding 34 | 35 | ```jsx 36 | const MyResultsPerPage = ({ currentSize, options, onValueChange, ariaLabel, selectOnNavigation }) => { 37 | ... 38 | } 39 | 40 | const overriddenComponents = { 41 | "ResultsPerPage.element": MyResultsPerPage 42 | }; 43 | ``` 44 | 45 | ### Parameters 46 | 47 | * **currentSize** `String` 48 | 49 | The current value of the `size` `query` state. 50 | 51 | * **options** `Array` 52 | 53 | The options passed as prop to the component. 54 | 55 | * **onValueChange** `Gunction` 56 | 57 | The function to call when the user changes the number of results per page to change the `query` state. `onValueChange(newValue)` 58 | 59 | * **ariaLabel** `String` 60 | 61 | The ARIA (Accessibility) label to add to the component. 62 | 63 | * **selectOnNavigation** `Boolean` 64 | 65 | When using a dropdown, set if the `onValueChange` should be called when the new dropdown item is selected with arrow keys, or only on click or on enter. 66 | 67 | * **showWhenOnlyOnePage** `Boolean` 68 | 69 | Allows to configure whether or not the component will render when there is only one page of results available. Default value: `true`. -------------------------------------------------------------------------------- /docs/docs/components/sort.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: sort 3 | title: Sort 4 | --- 5 | 6 | `Sort` renders a list of possible sort by and sort order options in one single component. 7 | 8 | The component is **not** displayed while executing the search query or if there are no results. 9 | 10 | ## Usage 11 | 12 | ```jsx 13 | 27 | ``` 28 | 29 | ## Props 30 | 31 | * **values** `Array` 32 | 33 | A list of possible values, where each value has the format `{ text: "Newest", sortBy: "", sortOrder: "" }`. 34 | 35 | - **label** `function` _optional_ 36 | 37 | An optional function to wrap the component with a prefix and suffix string.
38 | E.g. `label={(cmp) => <> sorted by {cmp}}` 39 | 40 | * **overridableId** `String` *optional* 41 | 42 | An optional string to define a specific overridable id. 43 | 44 | ## Usage when overriding 45 | 46 | ```jsx 47 | const MySort = ({ currentSortBy, options, onValueChange, ariaLabel, selectOnNavigation }) => { 48 | ... 49 | } 50 | 51 | const overriddenComponents = { 52 | "Sort.element": MySort 53 | }; 54 | ``` 55 | 56 | ### Parameters 57 | 58 | * **currentSortBy** `String` 59 | 60 | The current value of the `sortBy` `query` state. 61 | 62 | * **currentSortOrder** `String` 63 | 64 | The current value of the `sortOrder` `query` state. 65 | 66 | * **options** `Array` 67 | 68 | The options passed as prop to the component. 69 | 70 | * **onValueChange** `function` 71 | 72 | The function to call when the user changes the sort by field value to change the `query` state. `onValueChange(newValue)` 73 | 74 | * **ariaLabel** `String` 75 | 76 | The ARIA (Accessibility) label to add to the component. 77 | 78 | * **selectOnNavigation** `Boolean` 79 | 80 | When using a dropdown, set if the `onValueChange` should be called when the new dropdown item is selected with arrow keys, or only on click or on enter. 81 | -------------------------------------------------------------------------------- /src/lib/components/Toggle/Toggle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2020-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { useContext } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { Card, Checkbox } from "semantic-ui-react"; 13 | import { AppContext } from "../ReactSearchKit"; 14 | 15 | const ToggleComponent = ({ 16 | overridableId, 17 | userSelectionFilters, 18 | title, 19 | label, 20 | filterValue, 21 | updateQueryFilters, 22 | }) => { 23 | const _isChecked = (userSelectionFilters) => { 24 | const isFilterActive = 25 | userSelectionFilters.filter((filter) => filter[0] === filterValue[0]).length > 0; 26 | return isFilterActive; 27 | }; 28 | const onClick = () => { 29 | updateQueryFilters(filterValue); 30 | }; 31 | const { buildUID } = useContext(AppContext); 32 | const isChecked = _isChecked(userSelectionFilters); 33 | 34 | return ( 35 | 43 | 44 | 45 | {title} 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | }; 54 | 55 | ToggleComponent.propTypes = { 56 | title: PropTypes.string.isRequired, 57 | label: PropTypes.string.isRequired, 58 | filterValue: PropTypes.array.isRequired, 59 | overridableId: PropTypes.string, 60 | /* REDUX */ 61 | userSelectionFilters: PropTypes.array.isRequired, 62 | updateQueryFilters: PropTypes.func.isRequired, 63 | }; 64 | 65 | ToggleComponent.defaultProps = { 66 | overridableId: "", 67 | }; 68 | 69 | export default Overridable.component("SearchFilters.Toggle", ToggleComponent); 70 | -------------------------------------------------------------------------------- /docs/docs/ui_customisation.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: ui-customisation 3 | title: Customise The Look And Feel 4 | --- 5 | 6 | React-SearchKit uses [Semantic UI React](https://react.semantic-ui.com/) as UI framework. 7 | 8 | The best way to style each available component is to follow the recommended way documented in Semantic UI React [Theming section](https://react.semantic-ui.com/theming). 9 | 10 | Asides from styling, RSK components can be overridden completely (using [react-overridable](https://github.com/indico/react-overridable) internally). 11 | 12 | By passing a map with IDs and components we can override the default components with our own custom components. 13 | To allow for this functionality you should wrap your RSK app with the react-overridable "OverridableContext" and 14 | pass it a map of components you have defined. 15 | 16 | In the following example you can see a simplified setup. 17 | ```jsx 18 | const CustomResultsListItem = (overriddenComponentProps) => ( 19 | 20 | 21 | {overriddenComponentProps.title} 22 | 23 | 24 | ) 25 | 26 | const overriddenComponents = { 27 | 'ResultsList.item': CustomResultsListItem 28 | }; 29 | 30 | 31 | 32 | ... 33 | 34 | 35 | ``` 36 | 37 | The ID used for overriding a component can be found by searching the component in the RSK [library](https://github.com/inveniosoftware/react-searchkit/tree/master/src/lib/components) 38 | and looking at the ID passed to the `Overridable` component. The ID is built using a function called `buildUID` which allows us to namespace our IDs if needed. 39 | 40 | ```jsx 41 | //If there is no `appName` prop passed to the main RSK component` 42 | const id = buildUID('Count.Element'); // outputs 'Count.Element' 43 | const id2 = buildUID('Count.Element', 'ExampleOverridenId'); // outputs 'Count.Element.ExampleOverridenId' 44 | // If there is an `appName` prop passed with value 'exampleAppName' (namespacing) 45 | const id3 = buildUID('Count.Element'); // outputs 'exampleAppName.Count.Element' 46 | 47 | 48 | ``` 49 | 50 | For elaborated examples please have a look at our [code demos](https://github.com/inveniosoftware/react-searchkit/tree/master/src/demos). 51 | -------------------------------------------------------------------------------- /docs/website/static/js/code-blocks-buttons.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | // Turn off ESLint for this file because it's sent down to users as-is. 10 | /* eslint-disable */ 11 | window.addEventListener('load', function() { 12 | function button(label, ariaLabel, icon, className) { 13 | const btn = document.createElement('button'); 14 | btn.classList.add('btnIcon', className); 15 | btn.setAttribute('type', 'button'); 16 | btn.setAttribute('aria-label', ariaLabel); 17 | btn.innerHTML = 18 | '
' + 19 | icon + 20 | '' + 21 | label + 22 | '' + 23 | '
'; 24 | return btn; 25 | } 26 | 27 | function addButtons(codeBlockSelector, btn) { 28 | document.querySelectorAll(codeBlockSelector).forEach(function(code) { 29 | code.parentNode.appendChild(btn.cloneNode(true)); 30 | }); 31 | } 32 | 33 | const copyIcon = 34 | ''; 35 | 36 | addButtons( 37 | '.hljs', 38 | button('Copy', 'Copy code to clipboard', copyIcon, 'btnClipboard') 39 | ); 40 | 41 | const clipboard = new ClipboardJS('.btnClipboard', { 42 | target: function(trigger) { 43 | return trigger.parentNode.querySelector('code'); 44 | }, 45 | }); 46 | 47 | clipboard.on('success', function(event) { 48 | event.clearSelection(); 49 | const textEl = event.trigger.querySelector('.btnIcon__label'); 50 | textEl.textContent = 'Copied'; 51 | setTimeout(function() { 52 | textEl.textContent = 'Copy'; 53 | }, 2000); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/Results.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component } from "react"; 11 | import { Grid } from "semantic-ui-react"; 12 | import { 13 | ActiveFilters, 14 | Count, 15 | LayoutSwitcher, 16 | Pagination, 17 | ResultsMultiLayout, 18 | ResultsPerPage, 19 | Sort, 20 | } from "../../lib/components"; 21 | 22 | export class Results extends Component { 23 | constructor(props) { 24 | super(props); 25 | 26 | const { sortValues, resultsPerPageValues } = this.props; 27 | 28 | this.sortValues = sortValues; 29 | this.resultsPerPageValues = resultsPerPageValues; 30 | } 31 | 32 | render() { 33 | const { currentResultsState } = this.props; 34 | const { data } = currentResultsState; 35 | const { total } = data; 36 | return total ? ( 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | <> Found {cmp} results} /> 45 | <> sorted by {cmp}} /> 46 | 47 | 48 | 49 | 50 | <> Show {cmp} results per page} 53 | /> 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | ) : null; 66 | } 67 | } 68 | 69 | Results.propTypes = { 70 | currentResultsState: PropTypes.array.isRequired, 71 | sortValues: PropTypes.array.isRequired, 72 | resultsPerPageValues: PropTypes.array.isRequired, 73 | }; 74 | 75 | Results.defaultProps = {}; 76 | -------------------------------------------------------------------------------- /src/demos/zenodo/Results.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component } from "react"; 11 | import { Grid } from "semantic-ui-react"; 12 | import { 13 | ActiveFilters, 14 | Count, 15 | LayoutSwitcher, 16 | Pagination, 17 | ResultsMultiLayout, 18 | ResultsPerPage, 19 | Sort, 20 | } from "../../lib/components"; 21 | 22 | export class Results extends Component { 23 | constructor(props) { 24 | super(props); 25 | 26 | const { sortValues, resultsPerPageValues } = this.props; 27 | 28 | this.sortValues = sortValues; 29 | this.resultsPerPageValues = resultsPerPageValues; 30 | } 31 | 32 | render() { 33 | const { currentResultsState } = this.props; 34 | const { data } = currentResultsState; 35 | const { total } = data; 36 | return total ? ( 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | <>Found {cmp} results} /> 45 | <> sorted by {cmp}} /> 46 | 47 | 48 | 49 | 50 | <>Show {cmp} results per page} 53 | /> 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | ) : null; 66 | } 67 | } 68 | 69 | Results.propTypes = { 70 | currentResultsState: PropTypes.array.isRequired, 71 | sortValues: PropTypes.array.isRequired, 72 | resultsPerPageValues: PropTypes.array.isRequired, 73 | }; 74 | 75 | Results.defaultProps = {}; 76 | -------------------------------------------------------------------------------- /src/demos/cern-videos/Results.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component } from "react"; 11 | import { Grid } from "semantic-ui-react"; 12 | import { 13 | ActiveFilters, 14 | Count, 15 | LayoutSwitcher, 16 | Pagination, 17 | ResultsMultiLayout, 18 | ResultsPerPage, 19 | Sort, 20 | } from "../../lib/components"; 21 | 22 | export class Results extends Component { 23 | constructor(props) { 24 | super(props); 25 | 26 | const { sortValues, resultsPerPageValues } = this.props; 27 | 28 | this.sortValues = sortValues; 29 | this.resultsPerPageValues = resultsPerPageValues; 30 | } 31 | 32 | render() { 33 | const { currentResultsState } = this.props; 34 | const { data } = currentResultsState; 35 | const { total } = data; 36 | return total ? ( 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | <> Found {cmp} results} /> 45 | <> sorted by {cmp}} /> 46 | 47 | 48 | 49 | 50 | <> Show {cmp} results per page} 53 | /> 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | ) : null; 66 | } 67 | } 68 | 69 | Results.propTypes = { 70 | currentResultsState: PropTypes.array.isRequired, 71 | sortValues: PropTypes.array.isRequired, 72 | resultsPerPageValues: PropTypes.array.isRequired, 73 | }; 74 | 75 | Results.defaultProps = {}; 76 | -------------------------------------------------------------------------------- /src/lib/api/contrib/opensearch/OSRequestSerializer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { OSRequestSerializer } from "."; 10 | 11 | describe("test OSRequestSerializer serializer", () => { 12 | const serializer = new OSRequestSerializer(); 13 | 14 | it("should serialize the query field", () => { 15 | const queryState = { 16 | queryString: "test", 17 | page: 0, 18 | size: 0, 19 | }; 20 | const objState = serializer.serialize(queryState); 21 | expect(objState).toMatchObject({ 22 | query: { query_string: { query: "test" } }, 23 | }); 24 | }); 25 | 26 | it("should serialize the sort by field", () => { 27 | const queryState = { 28 | queryString: "test", 29 | sortBy: "name", 30 | page: 0, 31 | size: 0, 32 | }; 33 | const objState = serializer.serialize(queryState); 34 | expect(objState).toMatchObject({ 35 | query: { query_string: { query: "test" } }, 36 | sort: { name: "asc" }, 37 | }); 38 | }); 39 | 40 | it("should serialize the sort order field with desc value", () => { 41 | const queryState = { 42 | queryString: "test", 43 | sortBy: "name", 44 | sortOrder: "desc", 45 | page: 0, 46 | size: 0, 47 | }; 48 | const objState = serializer.serialize(queryState); 49 | expect(objState).toMatchObject({ 50 | query: { query_string: { query: "test" } }, 51 | sort: { name: "desc" }, 52 | }); 53 | }); 54 | 55 | it("should serialize the page field", () => { 56 | const queryState = { 57 | queryString: "test", 58 | sortBy: "name", 59 | page: 2, 60 | size: 0, 61 | }; 62 | const objState = serializer.serialize(queryState); 63 | expect(objState).toMatchObject({ 64 | query: { query_string: { query: "test" } }, 65 | sort: { name: "asc" }, 66 | from: 0, 67 | }); 68 | }); 69 | 70 | it("should serialize the size field", () => { 71 | const queryState = { 72 | queryString: "test", 73 | sortBy: "name", 74 | page: 2, 75 | size: 20, 76 | }; 77 | const objState = serializer.serialize(queryState); 78 | expect(objState).toMatchObject({ 79 | query: { query_string: { query: "test" } }, 80 | sort: { name: "asc" }, 81 | from: 20, 82 | }); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /src/lib/components/ResultsMultiLayout/ResultsMultiLayout.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { useContext } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { AppContext } from "../ReactSearchKit"; 13 | import { ResultsGrid } from "../ResultsGrid"; 14 | import { ResultsList } from "../ResultsList"; 15 | import { ShouldRender } from "../ShouldRender"; 16 | 17 | function ResultsMultiLayout({ 18 | loading, 19 | totalResults, 20 | currentLayout, 21 | overridableId, 22 | onResultsRendered, 23 | }) { 24 | return ( 25 | 0}> 26 | 31 | 32 | ); 33 | } 34 | 35 | ResultsMultiLayout.propTypes = { 36 | currentLayout: PropTypes.string, 37 | overridableId: PropTypes.string, 38 | onResultsRendered: PropTypes.func, 39 | /* REDUX */ 40 | loading: PropTypes.bool.isRequired, 41 | totalResults: PropTypes.number.isRequired, 42 | }; 43 | 44 | ResultsMultiLayout.defaultProps = { 45 | currentLayout: null, 46 | overridableId: "", 47 | onResultsRendered: () => {}, 48 | }; 49 | 50 | const Element = ({ layout, overridableId, onResultsRendered }) => { 51 | const { buildUID } = useContext(AppContext); 52 | return ( 53 | 58 | {layout === "list" ? ( 59 | 63 | ) : ( 64 | 68 | )} 69 | 70 | ); 71 | }; 72 | 73 | Element.propTypes = { 74 | layout: PropTypes.string, 75 | overridableId: PropTypes.string, 76 | onResultsRendered: PropTypes.func, 77 | }; 78 | 79 | Element.defaultProps = { 80 | layout: "", 81 | overridableId: "", 82 | onResultsRendered: () => {}, 83 | }; 84 | 85 | export default Overridable.component("ResultsMultiLayout", ResultsMultiLayout); 86 | -------------------------------------------------------------------------------- /docs/website/pages/en/help.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | const React = require("react"); 10 | 11 | const CompLibrary = require("../../core/CompLibrary.js"); 12 | const Container = CompLibrary.Container; 13 | const GridBlock = CompLibrary.GridBlock; 14 | const MarkdownBlock = CompLibrary.MarkdownBlock; 15 | 16 | const siteConfig = require(process.cwd() + "/siteConfig.js"); 17 | 18 | class Help extends React.Component { 19 | render() { 20 | const supportLinks = [ 21 | { 22 | content: `Have a look to the [Getting Started guide](${siteConfig.baseUrl}docs/getting-started) to better understand how React-SearchKit works and how it can help you to build your own SearchKit app.\n\nRead the [advanced guide](${siteConfig.baseUrl}docs/advanced) to know how to customize, extend and create your own components.`, 23 | title: "Browse the documentation", 24 | }, 25 | { 26 | content: 27 | "Join the [Invenio Discord channel](https://discord.gg/8qatqBC) to ask questions and get help.", 28 | title: "Join the community", 29 | }, 30 | { 31 | content: 32 | "React-SearchKit is part of the Invenio software organization.\n- Have a look to the [Invenio](https://inveniosoftware.org/) website to know more about the project.\n- Announcements and news are published in the official [Invenio blog](https://inveniosoftware.org/blog/).\n- Follow Invenio on [Twitter](https://twitter.com/inveniosoftware).", 33 | title: "Stay up to date", 34 | }, 35 | ]; 36 | 37 | return ( 38 |
39 | 40 |
41 |
42 |

43 |
Need help?
44 |

45 |
46 |

47 | 48 | React-SearchKit is born at [CERN](https://home.cern). It is under active 49 | development and used by websites built on top of 50 | [Invenio](https://inveniosoftware.org/). 51 | 52 |

53 | 54 |
55 |
56 |
57 | ); 58 | } 59 | } 60 | 61 | module.exports = Help; 62 | -------------------------------------------------------------------------------- /docs/docs/components/pagination.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: pagination 3 | title: Pagination 4 | --- 5 | 6 | `Pagination` renders the controls for navigating the search result pages. 7 | 8 | The component is **not** displayed while executing the search query, if the current page or results per page are not set 9 | or if there are no results. 10 | 11 | ## Usage 12 | 13 | ```jsx 14 | const options = { showEllipsis: false, showLastIcon: false } 15 | 16 | ``` 17 | 18 | ## Props 19 | 20 | * **options** `object` *optional* 21 | 22 | An object that can contain: 23 | 24 | * **boundaryRangeCount** `Number`: Number of always visible pages at the beginning and end. Default value: `1`. 25 | * **siblingRangeCount** `Number`: Number of always visible pages before and after the current one. Default value: `1`. 26 | * **showEllipsis** `Boolean`: Show '...' for hidden pages. Default value: `true`. 27 | * **showFirst** `Boolean`: Show the icon to go to the first page. Default value: `true`. 28 | * **showLast** `Boolean`: Show the icon to go to the last page. Default value: `true`. 29 | * **showPrev** `Boolean`: Show the icon to go to the previous page. Default value: `true`. 30 | * **showNext** `Boolean`: Show the icon to go to the next page. Default value: `true`. 31 | * **size** `String`: Component size, one of `["mini", "tiny", "small", "large", "huge", "massive"]`. 32 | 33 | * **overridableId** `String` *optional* 34 | 35 | An optional string to define a specific overridable id. 36 | 37 | ## Usage when overriding 38 | 39 | ```jsx 40 | const MyPagination = ({ currentPage, currentSize, totalResults, onPageChange, options }) => { 41 | ... 42 | } 43 | 44 | const overriddenComponents = { 45 | "Pagination.element": MyPagination 46 | }; 47 | ``` 48 | 49 | ### Parameters 50 | 51 | * **currentPage** `Number` 52 | 53 | The current value of the `page` `query` state. 54 | 55 | * **currentSize** `Number` 56 | 57 | The current value of the `size` `query` state, to be able to calculate the total number of pages. 58 | 59 | * **totalResults** `Number` 60 | 61 | The current value of the `total` `results` state representing the number of results, to be able to calculate the total number of pages. 62 | 63 | * **onPageChange** `Number` 64 | 65 | Function to call when the user wants to change the page to change the `query` state. `onPageChange(newValue)` 66 | 67 | * **options** `object` 68 | 69 | The options prop passed to the component. 70 | 71 | * **showWhenOnlyOnePage** `Boolean` 72 | 73 | Allows to configure whether or not the component will render when there is only one page of results available. Default value: `true`. 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/lib/components/Bootstrap/Bootstrap.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import { Component } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { AppContext } from "../ReactSearchKit/AppContext"; 13 | 14 | class Bootstrap extends Component { 15 | constructor(props) { 16 | super(props); 17 | this.searchOnInit = props.searchOnInit; 18 | this.eventListenerEnabled = props.eventListenerEnabled; 19 | this.onAppInitialized = props.onAppInitialized; 20 | this.searchOnUrlQueryStringChanged = props.searchOnUrlQueryStringChanged; 21 | } 22 | 23 | componentDidMount() { 24 | if (this.eventListenerEnabled) { 25 | window.addEventListener("queryChanged", this.onQueryChanged); 26 | } 27 | window.onpopstate = () => { 28 | this.searchOnUrlQueryStringChanged(); 29 | }; 30 | this.onAppInitialized(this.searchOnInit); 31 | } 32 | 33 | componentWillUnmount() { 34 | window.onpopstate = () => {}; 35 | window.removeEventListener("queryChanged", this.onQueryChanged); 36 | } 37 | 38 | updateQueryState = (query) => { 39 | const { updateQueryState } = this.props; 40 | updateQueryState(query); 41 | }; 42 | 43 | onQueryChanged = ({ detail: payload }) => { 44 | const { appName } = this.context; 45 | 46 | const appNameNotDefined = !appName; 47 | if (appNameNotDefined) { 48 | this.updateQueryState(payload.searchQuery); 49 | } else { 50 | const eventRecipient = payload.appName; 51 | const sameName = eventRecipient === appName; 52 | if (sameName) { 53 | this.updateQueryState(payload.searchQuery); 54 | } else { 55 | console.debug( 56 | `React-SearchKit '${appName}': ignoring event sent for app '${eventRecipient}'` 57 | ); 58 | } 59 | } 60 | }; 61 | 62 | render() { 63 | const { children } = this.props; 64 | return children; 65 | } 66 | } 67 | 68 | Bootstrap.propTypes = { 69 | searchOnInit: PropTypes.bool, 70 | eventListenerEnabled: PropTypes.bool, 71 | children: PropTypes.node.isRequired, 72 | /* Redux */ 73 | onAppInitialized: PropTypes.func.isRequired, 74 | updateQueryState: PropTypes.func.isRequired, 75 | searchOnUrlQueryStringChanged: PropTypes.func.isRequired, 76 | }; 77 | 78 | Bootstrap.defaultProps = { 79 | searchOnInit: true, 80 | eventListenerEnabled: false, 81 | }; 82 | 83 | Bootstrap.contextType = AppContext; 84 | 85 | export default Overridable.component("Bootstrap", Bootstrap); 86 | -------------------------------------------------------------------------------- /src/demos/cern-videos-namespaced/app.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/display-name */ 2 | /* eslint-disable react/prop-types */ 3 | import _truncate from "lodash/truncate"; 4 | import React from "react"; 5 | import { OverridableContext } from "react-overridable"; 6 | import { Card, Grid, Image, Item } from "semantic-ui-react"; 7 | import { CERNVideosReactSearchKit2 } from "./cern-videos-2"; 8 | import { CERNVideosReactSearchKit3 } from "./cern-videos-3"; 9 | 10 | const CERNVideosResultsListItem = 11 | (imageShown) => 12 | ({ result, index }) => { 13 | const metadata = result.metadata; 14 | return ( 15 | 16 | {imageShown && ( 17 | 21 | )} 22 | 23 | {metadata.title.title} 24 | 25 | {_truncate(metadata.description, { length: 200 })} 26 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | const CERNVideosResultsGridItem = 33 | (blueTitle) => 34 | ({ result, index }) => { 35 | const metadata = result.metadata; 36 | return ( 37 | 38 | 39 | 40 | 41 | {metadata.title.title} 42 | 43 | {metadata.publication_date} 44 | 45 | {_truncate(metadata.description, { length: 200 })} 46 | 47 | 48 | 49 | ); 50 | }; 51 | 52 | const overriddenComponents = { 53 | "cernvideos2.ResultsList.item": CERNVideosResultsListItem(true), 54 | "cernvideos2.ResultsGrid.item": CERNVideosResultsGridItem(false), 55 | "cernvideos3.ResultsList.item": CERNVideosResultsListItem(false), 56 | "cernvideos3.ResultsGrid.item": CERNVideosResultsGridItem(true), 57 | }; 58 | 59 | const NamespacedExample = () => { 60 | return ( 61 | 62 | 63 | 64 |

appName = cernvideos3

65 | 66 |
67 | 68 |

appName = cernvideos2

69 | 70 |
71 |
72 |
73 | ); 74 | }; 75 | 76 | export default NamespacedExample; 77 | -------------------------------------------------------------------------------- /src/lib/api/contrib/opensearch/OSSearchApi.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import MockAdapter from "axios-mock-adapter"; 10 | import Qs from "qs"; 11 | import { OSSearchApi } from "."; 12 | 13 | class MockedRequestSerializer { 14 | serialize(params) { 15 | return Qs.stringify(params); 16 | } 17 | } 18 | 19 | class MockedResponseSerializer { 20 | serialize(payload) { 21 | return payload; 22 | } 23 | } 24 | 25 | describe("test OSSearchApi class", () => { 26 | it("should use the provided configuration", async () => { 27 | const searchApi = new OSSearchApi({ 28 | axios: { 29 | url: "https://mydomain.test.com/api/", 30 | timeout: 5000, 31 | headers: { Accept: "application/json" }, 32 | }, 33 | os: { 34 | requestSerializer: MockedRequestSerializer, 35 | responseSerializer: MockedResponseSerializer, 36 | }, 37 | }); 38 | const mockedAxios = new MockAdapter(searchApi.http); 39 | 40 | const requestPayload = { q: "test" }; 41 | const mockedRequestSerializer = new MockedRequestSerializer(); 42 | expect(searchApi.requestSerializer).toEqual(mockedRequestSerializer); 43 | expect(searchApi.responseSerializer).toEqual(new MockedResponseSerializer()); 44 | 45 | const mockedResponse = { hits: [{ result: "1" }] }; 46 | mockedAxios.onAny().reply(200, mockedResponse); 47 | const response = await searchApi.search(requestPayload); 48 | expect(mockedAxios.history.post.length).toBe(1); 49 | 50 | const request = mockedAxios.history.post[0]; 51 | expect(request.url).toBe("https://mydomain.test.com/api/"); 52 | expect(request.method).toBe("post"); 53 | expect(request.timeout).toBe(5000); 54 | expect(request.data).toEqual("q=test"); 55 | 56 | expect(response).toEqual(mockedResponse); 57 | }); 58 | 59 | it("should properly use relative URLs", async () => { 60 | const searchApi = new OSSearchApi({ 61 | axios: { 62 | url: "/api/records", 63 | }, 64 | os: { 65 | requestSerializer: MockedRequestSerializer, 66 | responseSerializer: MockedResponseSerializer, 67 | }, 68 | }); 69 | const mockedAxios = new MockAdapter(searchApi.http); 70 | 71 | const mockedResponse = { hits: [{ result: "1" }] }; 72 | mockedAxios.onAny().reply(200, mockedResponse); 73 | await searchApi.search({ q: "test" }); 74 | expect(mockedAxios.history.post.length).toBe(1); 75 | 76 | const request = mockedAxios.history.post[0]; 77 | expect(request.url).toBe("/api/records"); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /src/lib/api/contrib/invenio/InvenioSearchApi.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2019 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import MockAdapter from "axios-mock-adapter"; 10 | import Qs from "qs"; 11 | import { InvenioSearchApi } from "."; 12 | 13 | class MockedRequestSerializer { 14 | serialize(params) { 15 | return Qs.stringify(params); 16 | } 17 | } 18 | 19 | class MockedResponseSerializer { 20 | serialize(payload) { 21 | return payload; 22 | } 23 | } 24 | 25 | describe("test InvenioSearchApi class", () => { 26 | it("should use the provided configuration", async () => { 27 | const searchApi = new InvenioSearchApi({ 28 | axios: { 29 | url: "https://mydomain.test.com/api/", 30 | timeout: 5000, 31 | headers: { Accept: "application/json" }, 32 | }, 33 | invenio: { 34 | requestSerializer: MockedRequestSerializer, 35 | responseSerializer: MockedResponseSerializer, 36 | }, 37 | }); 38 | const mockedAxios = new MockAdapter(searchApi.http); 39 | 40 | const requestPayload = { q: "test" }; 41 | const mockedRequestSerializer = new MockedRequestSerializer(); 42 | expect(searchApi.requestSerializer).toEqual(mockedRequestSerializer); 43 | expect(searchApi.responseSerializer).toEqual(new MockedResponseSerializer()); 44 | 45 | const mockedResponse = { hits: [{ result: "1" }] }; 46 | mockedAxios.onAny().reply(200, mockedResponse); 47 | const response = await searchApi.search(requestPayload); 48 | expect(mockedAxios.history.get.length).toBe(1); 49 | 50 | const request = mockedAxios.history.get[0]; 51 | expect(request.url).toBe("https://mydomain.test.com/api/"); 52 | expect(request.method).toBe("get"); 53 | expect(request.timeout).toBe(5000); 54 | expect(request.headers.toJSON()).toEqual({ 55 | Accept: "application/json", 56 | }); 57 | expect(request.params).toEqual(requestPayload); 58 | expect(request.paramsSerializer.serialize).toBe(mockedRequestSerializer.serialize); 59 | 60 | expect(response).toEqual(mockedResponse); 61 | }); 62 | 63 | it("should properly use relative URLs", async () => { 64 | const searchApi = new InvenioSearchApi({ 65 | axios: { 66 | url: "/api/records", 67 | }, 68 | }); 69 | const mockedAxios = new MockAdapter(searchApi.http); 70 | 71 | const mockedResponse = { hits: [{ result: "1" }] }; 72 | mockedAxios.onAny().reply(200, mockedResponse); 73 | await searchApi.search({ q: "test" }); 74 | expect(mockedAxios.history.get.length).toBe(1); 75 | 76 | const request = mockedAxios.history.get[0]; 77 | expect(request.url).toBe("/api/records"); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /src/lib/components/LayoutSwitcher/LayoutSwitcher.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018-2022 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import PropTypes from "prop-types"; 10 | import React, { Component, useContext } from "react"; 11 | import Overridable from "react-overridable"; 12 | import { Icon, Menu } from "semantic-ui-react"; 13 | import { AppContext } from "../ReactSearchKit"; 14 | import { ShouldRender } from "../ShouldRender"; 15 | 16 | class LayoutSwitcher extends Component { 17 | constructor(props) { 18 | super(props); 19 | this.updateLayout = props.updateLayout; 20 | } 21 | 22 | onLayoutChange = (layoutName) => { 23 | this.updateLayout(layoutName); 24 | }; 25 | 26 | render() { 27 | const { currentLayout, loading, totalResults, overridableId } = this.props; 28 | return ( 29 | 0}> 30 | 35 | 36 | ); 37 | } 38 | } 39 | 40 | LayoutSwitcher.propTypes = { 41 | overridableId: PropTypes.string, 42 | /* REDUX */ 43 | updateLayout: PropTypes.func.isRequired, 44 | loading: PropTypes.bool.isRequired, 45 | currentLayout: PropTypes.string, 46 | totalResults: PropTypes.number.isRequired, 47 | }; 48 | 49 | LayoutSwitcher.defaultProps = { 50 | currentLayout: null, 51 | overridableId: "", 52 | }; 53 | 54 | const Element = ({ overridableId, currentLayout, onLayoutChange }) => { 55 | const { buildUID } = useContext(AppContext); 56 | return ( 57 | 62 | 63 | onLayoutChange(name)} 67 | > 68 | 69 | 70 | onLayoutChange(name)} 74 | > 75 | 76 | 77 | 78 | 79 | ); 80 | }; 81 | 82 | Element.propTypes = { 83 | currentLayout: PropTypes.string, 84 | onLayoutChange: PropTypes.func.isRequired, 85 | overridableId: PropTypes.string, 86 | }; 87 | 88 | Element.defaultProps = { 89 | currentLayout: null, 90 | overridableId: "", 91 | }; 92 | 93 | export default Overridable.component("LayoutSwitcher", LayoutSwitcher); 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | # React-SearchKit 10 | 11 | ![Build status](https://github.com/inveniosoftware/react-searchkit/workflows/CI/badge.svg) 12 | [![Release](https://img.shields.io/npm/v/react-searchkit)](https://www.npmjs.com/package/react-searchkit) 13 | [![License](https://img.shields.io/github/license/inveniosoftware/react-searchkit)](https://github.com/inveniosoftware/react-searchkit/blob/master/LICENSE) 14 | [![Downloads](https://img.shields.io/npm/dm/react-searchkit)](https://www.npmjs.com/package/react-searchkit) 15 | 16 | React-SearchKit is a React library that allows you to build in an easy way your search application. 17 | 18 | Main features: 19 | 20 | - ready-to-use collection of UI components 21 | - configurable REST API endpoint and serialization 22 | - configurable URL parameters handling for deep linking 23 | 24 | ![React-SearchKit screenshot](docs/website/static/img/screenshot.png) 25 | 26 | ## Examples 27 | 28 | You can find a collection of examples in the `src/demos` folder: 29 | 30 | - OpenSearch, an example on how to query OpenSearch (see below) 31 | - Zenodo.org, an example on how to query an Invenio 3 instance 32 | - CERN Videos, another Invenio 3 example 33 | 34 | Install dependencies and run the React app to try them out (see steps below). 35 | 36 | ### OpenSearch 37 | 38 | To run the OpenSearch backend for the demo, you can use Docker. A `docker-compose` file with `ES 7` and `nginx` as reverse proxy is available and ready to use. 39 | Run the services: 40 | 41 | ```bash 42 | cd src/demos/opensearch/docker 43 | docker-compose up 44 | ``` 45 | 46 | Then, init the demo data: 47 | 48 | ```bash 49 | curl -XPUT 'http://localhost:9200/random?pretty' -H 'Content-Type: application/json' -d @os2-mappings.json 50 | curl -XPOST 'http://localhost:9200/random/_bulk' -H 'Content-Type: application/json' --data-binary @os-random-data.json 51 | curl -XGET 'http://localhost:9200/random/_count?pretty' 52 | ``` 53 | 54 | Demo data have been randomly generated using . 55 | 56 | > Delete data in the cluster: `curl -X DELETE 'http://localhost:9200/_all'` 57 | 58 | ## Developer guide 59 | 60 | React-SearchKit uses [create-react-app](https://create-react-app.dev/) as development toolkit. 61 | 62 | Install the library: 63 | 64 | ```bash 65 | npm install 66 | ``` 67 | 68 | Start the demo application: 69 | 70 | ```bash 71 | npm start 72 | ``` 73 | 74 | The library uses [Jest](https://jestjs.io/) as test runner. To run the tests: 75 | 76 | ```bash 77 | npm test 78 | ``` 79 | 80 | The library uses `rollup` to build a final version inside the `/dist` folder and it will build CommonJS and ES Modules versions: 81 | 82 | ```bash 83 | npm run build 84 | ``` 85 | -------------------------------------------------------------------------------- /src/lib/components/Bootstrap/Bootstrap.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2019-2020 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | import { mount } from "enzyme"; 10 | import React from "react"; 11 | import { onQueryChanged } from "../../events"; 12 | import { AppContext } from "../ReactSearchKit/AppContext"; 13 | import Bootstrap from "./Bootstrap"; 14 | 15 | describe("test Bootstrap component", () => { 16 | it("should call updateQueryState func when a valid event is sent", () => { 17 | const mockUpdateQueryState = jest.fn(); 18 | mount( 19 | 20 | {}} 26 | > 27 |
28 | 29 | 30 | ); 31 | const expectedPayload = { 32 | searchQuery: { queryString: "test" }, 33 | appName: "MyRSK", 34 | }; 35 | onQueryChanged(expectedPayload); 36 | expect(mockUpdateQueryState).toHaveBeenCalledWith(expectedPayload.searchQuery); 37 | }); 38 | 39 | it("should not call updateQueryState func when an invalid event is sent", () => { 40 | const mockUpdateQueryState = jest.fn(); 41 | mount( 42 | 43 | {}} 49 | > 50 |
51 | 52 | 53 | ); 54 | onQueryChanged({}); 55 | expect(mockUpdateQueryState).not.toHaveBeenCalled(); 56 | }); 57 | 58 | it("should not call updateQueryState func when the appName in the event does not match", () => { 59 | const mockUpdateQueryState = jest.fn(); 60 | mount( 61 | 62 | {}} 69 | > 70 |
71 | 72 | 73 | ); 74 | 75 | const expectedPayload = { 76 | appName: "unknown_app", 77 | searchQuery: { queryString: "test" }, 78 | }; 79 | 80 | onQueryChanged(expectedPayload); 81 | expect(mockUpdateQueryState).not.toHaveBeenCalled(); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /docs/website/siteConfig.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React-SearchKit. 3 | * Copyright (C) 2018 CERN. 4 | * 5 | * React-SearchKit is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT License; see LICENSE file for more details. 7 | */ 8 | 9 | const siteConfig = { 10 | title: 'React-SearchKit', 11 | tagline: 'A simple yet powerful UI search kit built with React', 12 | url: 'https://inveniosoftware.github.io', 13 | baseUrl: '/react-searchkit/', // Base URL for your project */ 14 | // For github.io type URLs, you would set the url and baseUrl like: 15 | // url: 'https://facebook.github.io', 16 | // baseUrl: '/test-site/', 17 | 18 | // Used for publishing and more 19 | projectName: 'react-searchkit', 20 | organizationName: 'inveniosoftware', 21 | // For top-level user or org sites, the organization is still the same. 22 | // e.g., for the https://JoelMarcey.github.io site, it would be set like... 23 | // organizationName: 'JoelMarcey' 24 | 25 | // For no header links in the top nav bar -> headerLinks: [], 26 | headerLinks: [ 27 | { doc: 'getting-started', label: 'Docs' }, 28 | { doc: 'components/react-searchkit', label: 'Components' }, 29 | { doc: 'create-your-component', label: 'Extending' }, 30 | { page: 'help', label: 'Help' }, 31 | ], 32 | 33 | // If you have users set above, you add it here: 34 | // users, 35 | 36 | /* path to images for header/footer */ 37 | headerIcon: '', 38 | footerIcon: '', 39 | favicon: 'img/favicon.png', 40 | 41 | /* Colors for website */ 42 | colors: { 43 | primaryColor: '#28688a', 44 | secondaryColor: 'rgba(10, 73, 105, 0.91)', 45 | }, 46 | 47 | /* Custom fonts for website */ 48 | /* 49 | fonts: { 50 | myFont: [ 51 | "Times New Roman", 52 | "Serif" 53 | ], 54 | myOtherFont: [ 55 | "-apple-system", 56 | "system-ui" 57 | ] 58 | }, 59 | */ 60 | 61 | highlight: { 62 | // Highlight.js theme to use for syntax highlighting in code blocks. 63 | theme: 'default', 64 | }, 65 | 66 | // Add custom scripts here that would be placed in