├── .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 | You need to enable JavaScript to run this app.
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 | {totalResults.toLocaleString("en-US")}
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 | 
12 | [](https://www.npmjs.com/package/react-searchkit)
13 | [](https://github.com/inveniosoftware/react-searchkit/blob/master/LICENSE)
14 | [](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 | 
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