GithubHelp home page GithubHelp logo

algolia / instantsearch Goto Github PK

View Code? Open in Web Editor NEW
3.6K 131.0 504.0 386.05 MB

⚡️ Libraries for building performant and instant search and recommend experiences with Algolia. Compatible with JavaScript, TypeScript, React and Vue.

Home Page: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/

License: MIT License

JavaScript 19.93% HTML 0.10% CSS 0.27% TypeScript 75.55% SCSS 1.42% Astro 0.20% Handlebars 0.71% Java 0.03% Swift 0.09% Ruby 0.01% Vue 1.45% Shell 0.03% Pug 0.20%
instantsearch vanilla search algolia widgets react vue recommend

instantsearch's Introduction

InstantSearch.js

InstantSearch is a JavaScript library for building performant and instant search experiences in vanilla JS, React, Vue and Angular with Algolia.


License Build Status

InstantSearch is a JavaScript library that lets you create an instant-search result experience using Algolia’s search API.

There are multiple wrappers for popular frameworks, such as React InstantSearch, Vue InstantSearch, and Angular InstantSearch.

It is part of the InstantSearch family which is designed for different platforms:

InstantSearch | Angular InstantSearch | InstantSearch Android | InstantSearch iOS

Table of contents

Packages

Package Version Description
algoliasearch-helper algoliasearch-helper npm version Helper for implementing advanced search features with Algolia
create-instantsearch-app create-instantsearch-app npm version Command-line utility to quickly bootstrap a project with InstantSearch
instantsearch.css instantsearch.css npm version Default CSS themes for InstantSearch
instantsearch.js instantsearch.js npm version InstantSearch.js
react-instantsearch react-instantsearch npm version React InstantSearch bundled library
react-instantsearch-core react-instantsearch-core npm version Runtime-independent React InstantSearch version
vue-instantsearch vue-instantsearch npm version Vue InstantSearch

Contributing

We welcome all contributors, from casual to regular 💙

  • Bug report. Is something not working as expected? Send a bug report.
  • Feature request. Would you like to add something to the library? Send a feature request.
  • Documentation. Did you find a typo in the doc? Open an issue and we'll take care of it.
  • Development. If you don't know where to start, you can check the open issues that are tagged easy, the bugs or chores.

To start contributing to code, you need to:

  1. Fork the project
  2. Clone the repository
  3. Install the dependencies: yarn
  4. Pick a package to work on and cd into it (e.g. cd packages/react-instantsearch)

Please read our contribution process to learn more.

License

InstantSearch is MIT licensed.

instantsearch's People

Contributors

alexkirsz avatar aymeric-giraudet avatar bobylito avatar codeharmonics avatar dependabot[bot] avatar dhayab avatar eunjae-lee avatar fabienmotte avatar francoischalifour avatar greenkeeperio-bot avatar haroenv avatar iam4x avatar instantsearch-bot avatar jerska avatar lukyvj avatar maxiloc avatar mthuret avatar pixelastic avatar rayrutjes avatar redox avatar renovate-bot avatar renovate[bot] avatar ronanlevesque avatar samouss avatar sarahdayan avatar shipow avatar shortcuts avatar tkrugg avatar vvo avatar yannickcr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

instantsearch's Issues

IE >= 8 Support

Since Babel assumes that your code will be ran in an ES5 environment it uses ES5 functions. So if you're using an environment that has limited or no support for ES5 such as lower versions of IE then using the es5-shim along with the Babel polyfill will add support for these methods.

https://babeljs.io/docs/advanced/caveats/

[switch] create widget

This widget needs to be able to render this:

2015-08-05-110722_497x143_scrot

Well not exactly since this current UI is bad: you cannot tell if you are looking for free shipping items or not.

For a first iteration I would opt for a simple checkbox. Checked means true, unchecked means no specific filter.

API

Index requirement

The targeted attribute should be a boolean.

Behavior

  • When checked, it means that we send a facetfilter with attributeName: true
  • When not checked it means we will not send any facetFilter for the attribute (true + false)

Usage

Given this html:

<div id="free-shipping"></div>

And JavaScript:

instant.addWidget(
  instantsearch.widgets.switch({
    container: '#free-shipping',
    facet: 'freeShipping',
    label: 'Free shipping'
  })
)

We default to render:

<div><label><input type="checkbox" checked />Free shipping</label></div>

Options

  • container string or DOMElement
  • facet string
  • label string
  • template string (hogan) or function
  • cssClass string (space separated css classes to apply to root element)

Available data when passing your own template

  • isRefined boolean

Two classes of widgets : rendered and headless

Maybe the name are not great but the idea is the following : when using our widget we might feel that we want to let it generates markup (because we don't have a component for that or we don't have a search page yet) or not (BOOTSTRAP EVERYTHING!). And some components make a lot of sense in those two configurations, such as :

  • searchBox (onchange event will give us the new value)
  • indexSelector (onchange)

That's all that come in mind for now. But I think this list could get longer as we go further and we have more components.

Are you ok with having those two kind of widget living as widgets but under different sub namespace?

Basic integration tests

TODO:

  • create the necessary stack to do some integration tests
  • write some integration tests
  • make them run in saucelabs on major browsers
  • provide a good dev environment to develop them (local selenium)

Ideas:

API Proposal: `onHit` callback in hits widget

We need to be able to reformat the hit before it's passed to the template. One use case is when you have your whole content being splitted in multiple parts (h1, h2, .. wordpress blog post) and you want to provide your user a clean data structure for his templates.

Example: https://github.com/algolia/algoliasearch-wordpress/blob/2e7742d7c631ac402415e7fcb1488eb6690db1bd/templates/default/template.js#L223

Then you need something like onHit to be able to reformat (map) every hit in another form.

So:

search.addWidget(
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      empty: require('./templates/no-results.html'),
      hit: require('./templates/hit.html')
    },
    onHit: function(hit) {
      return anotherObject;
    }
  })
);

Since templates can be string or functions we should be good but then what if you want to use our hogan.js along with just reformating the hit before it's passed to the

[menu] create widget

This widget needs to be able to render this:

2015-08-05-120454_484x325_scrot

We should use the hierarchicalFacet feature of the helper since a one level menu is just a one level hierarchicalFacet. Everything is ready in the hierarchicalFacet to handle this use case.

API

Usage

Given this html:

<div id="categories"></div>

And this JavaScript:

instant.addWidget(
  instantsearch.widgets.menu({
    container: '#categories',
    facet: 'categories'
  })
)

Will render this:

<ul>
  <li><a href="#" class="as--menu__item--selected">Beers</a> <span>210</span></li>
  <li><a href="#">Fruits</a> <span>23</span></li>
  <li><a href="#">Drugs</a> <span></span> <span>43</span></li>
</ul>

I did not detail css classes but there should be css classes aroud elements for people to style them. Following #47?

Options

  • container string or DOMElement
  • facet string
  • template string (hogan) or function
  • sortBy array of string ['isRefined:asc', 'name:desc', 'count:asc'] mapping the hierarchical facet options
  • cssClass string (space separated list of css classes to apply to root element)

Available data when passing your own template

The template will be inserted inside <li>HERE</li>

  • name
  • count
  • selected

Default sort

By default we can sort by name only.

Rename multipleChoiceList to refinementList

Should we rename multipleChoiceList to refinementList?

One of the argument : singleRefine in multipleChoiceList allows you to do a list of refinements with only one possible refinement (like a list of radio buttons to select a shipping method).

So I guess multipleChoiceList is no more the best name now that we have the possibility to do a single refine.

[indexSelector] create widget

This widget needs to be able to render this:

2015-08-05-102322_312x86_scrot

API

Given this html:

<div id="sort-results"></div>

And JavaScript:

instant.addWidget(
  instant.widgets.indexSelector({
    container : "#sort-results",
    indices: [{
      name: 'index', label: 'Relevance'
    }, {
      name: 'index_priceASC', label: 'Highest price'
    }, {
      name: 'index_priceDESC', label: 'Lowest price'
    }]
  })
);

We render:

<select>
  <option value="index">Relevance</option>
  <option value="index_priceASC">Highest price</option>
  <option value="index_priceDESC">Lowest price</option>
</select>

Options

  • container string or DOMElement
  • indices array of objects
  • cssClass string (comma separated list of css classes to apply to root element)

Behavior

The selected index is the one set in the helper as the current one.

If the selected index is not one from the list, then we should throw an error.

Plurals in stats widget

Mustache templating is logicless, which means we cannot display handle plurals in the template ("1 result" vs "42 results").

A way to do it would be to pass a isPlural key to the data passed to the template but this won't cover all cases (some languages have different plurals for 1+, 2+, 3+).

Should we provide an option to include default bootstrap classes?

Since bootstrap is heavily used by the web industry. It may be a good idea to provide an option that would automatically add the bootstrap css classes that are making sense for our widgets.

For example, when dealing with #42, the default rendering would be something like this (with more BEM classes):

<div class="as--multipleChoiceList">
  <div><label><input type="checkbox" value="Sony" checked />Sony <span>302</span></label></div>
  <div><label><input type="checkbox" value="Microsoft" />Microsoft <span>120</span></label></div>
</div>

This is good because:

  • it does not tie us to any css library
  • it provides a good isolation of css classes (no conflicts)
  • it provides an easy way to style them

BUT for bootstrap users this is not so good because they would like something like this:

<div class="as--multipleChoiceList ">
  <div class="checkbox"><label><input type="checkbox" value="Sony" checked />Sony <span class="badge">302</span></label></div>
  <div class="checkbox"><label><input type="checkbox" value="Microsoft" />Microsoft <span class="badge">120</span></label></li>
</div>

(added checkbox and badge classes)

So having an option somewhere to automatically add relevant bootstrap classes would be interesting.

?

[searchBox] allow to instantiate on an <input>

Following what @redox said:

Current SearchBox instantiation API cannot work in this use case (common one):

    <div class="input-group">
      <span class="input-group-btn">
        <button class="btn btn-default" type="button">Go!</button>
      </span>
      <input type="text" class="form-control" placeholder="Search for..."> <!-- I cannot have a wrapping div here -->
    </div>

Because we always have a wrapping DIV in our current SearchBox instantiation. We render the <input> where we were asked for.

TODO:

  • reimplement the searchBox widget using vanilla JavaScript to allow enhancing an input
  • automatically detect if the container is an and bind to it, otherwise generate the DOM like right now

PS: We might be able at some point with REACT do also enhance an existing DOM node but that's not currently feasible unfortunately.

Store the major (X.x.x) instantsearch version in the url to handle url backward compat

Since we are going to have a urlSync widget that will generate URLS in some way with a defined format.

Since those urls will endup being referenced by google at some point.

We should store the major version token of the instantsearch.js library in the url so that we always now how to serialize/deserialize even when we build change the format at some point.

It will allow us to update the url serialization without breaking any existing link.

It's an edge case, yes. But storing v=1 in the url in not a big deal

0.0.1 Roadmap

We aim for a 0.0.1 release.

We have a 0.0.1 milestone. This issue was made to easily track and comment on the 0.0.1 roadmap.

Goals

Being able to reproduce the instant search demo using instantsearch.js.

Get CSE and integrators (magento, wordpress) to use and give us feedback on the instantsearch.js API.

The library should be hosted on jsDelivr. Even if we are at the prototype state where we will break the API.

Check the 0.0.1 milestone on github to get a good idea of what's required for the release.

New widgets

Here are all the widgets and related issues we need to do for 0.0.1:

See all the new widget related issues for 0.0.1.

We should also make sure that we document each widget API in the project readme (for now), like we did for the first widgets.

Bug fixes and enhancements

Check the 0.0.1 milestone to see other remaining bugs and enhancements we should do.

Components organisation

Right now we have:

2015-09-03-140553_262x457_scrot

It always feels to me too much folders, don't you think we could flatten this like:

  • BemHelper.js
  • Hits.js
  • MultipleChoiceList.js
  • Pagination.js
  • PaginationHiddenLink.js
  • PaginationLink.js
  • Paginator.js
  • Searchbox.js
  • Template.js

So that we remove lot of folders and do not have that much of index.js files.

If at some point a component needs external files, then we can make a folder for this case.

Template as React component?

What if we could directly pass React component as templates? It could make sense for people doing React already, no?

externalize all widgets

we should externalize and develop all widgets in separated modules

To ease development, we can have an npm run link-all-widgets that will clone, checkout master and npm-link every known widget.

So that we can easily develop them using the npm run dev task.

Sync the widgets state with the url

When refreshing window, the helper state should be synced with the url #17, thus all widgets should also be synced with the helper state.

The goal is to have back/next/refresh/copy paste url working

[slider] create widget

This widget needs to be able to render this:

2015-08-05-105352_471x166_scrot

API

TODO, detail the initiailization API like we do in the readme for other widgets

[pagination]: show `<<, <, >, >>` by default (even when not clickable), provide an option to hide them

One issue with the current implementation is that when we automatically hide the <<, <, >, >> if not needed.

This might be a problem in some implementations where the user do not want this behavior.

What we can do:

  • when not needed, render <<, <, >, >> without a wrapper <a></a> (so, not a link)
  • provide an option (autoHideNavigation) to automatically hide them (visibility:hidden to maintain horizontal space, we still need to render them).

[stats] create widget

This widget needs to be able to render this:

2015-08-05-105238_504x104_scrot

Even if I don't like theses stats (which user needs this kinds of information but developers?), we should have a widget for it.

API

Usage

Given this html:

<div id="stats"></div>

And JavaScript:

instant.addWidget(
  instantsearch.widgets.stats({
    container: '#stats'
  });
});

We default to render:

<div>10,000 results <small>found in 2ms</small></div>

Options

  • container string or DOMElement
  • template string (hogan) or function
  • cssClass string (space separated class names to apply to root element)

Available data when passing your own template

  • processingTime number (ms)
  • nbHits number

Potential naming conflict in `React.component`

We're currently defining our React modules with class Foobar extends React.Component {}.

As we're using pretty generic names (Stats comes to mind), we will surely have conflict with userland components. Is there a way to namespace components (InstantSearch.Stats) in React?

[urlSync] create widget

This widget should be able to keep the url in sync with the helper state.

API

// Setting some parameters
instant.addWidget(
  instantsearch.widgets.urlSync({
    // Parameters to be serialized and read from the URL
    trackedParameters : [
      // Any parameters of the SearchParameters can be chosen. Most likely to be chosen : 
      "query",
      "page",
      "hitsPerPage",
      // Also the index, as it can be changed for sorting purpose but is not in the SearchParameters
      "index",
      // Facets can be set through the usage of different widgets. But the user don't know much about that, only that it is based on an attribute
      "facet:myAttribute",
      // For simplicity sake, we can choose to track all the facets.
      "facet:*"
    ],
    // Minimum time after which we do a new serialization of the parameters into the URL
    timeout : 1000,
    useHash : false // should the url use #
  })
);

But with the use of default parameters, using the url sync is as simple as that :

instant.addWidget(instantsearch.widgets.urlSync());

Lifecycle hooks

Init

The url sync needs to override the defaults parameter set by any other components. So it should always come last in the initialisation.

Update of the URL

The update should take place each time there is an update of the SearchParameters. I'm not sure that the render would be the best time to update, and would prefer having it on the change of the helper (or any lifecycle we could implement that would mirror that event)

We could use _.debounce with the trailing and leading set to true.

Previous work

There is already an initial implementation, that could be used for bootstraping this widget.

https://github.com/algolia/algolia-ui-kit/blob/master/src/setup/url.js

[chooseOne] create widget

This widget needs to be able to render this:

2015-08-05-120454_484x325_scrot

Maybe not needed, what this widget is here is a navigation menu, thus we should expose it as so: widgets.navigation, see #26**

API

TODO, detail the initiailization API like we do in the readme for other widgets

every href should be filled with a real url and synced with the helper state (no href="#")

Every href generated by widgets should be a "real" href instead of our classical href="#".

The goal is to have this:

<a href="?p=5&query=fsaf">Next page</a>

Instead of:

<a href="#">Next page</a>

This is important to tackle this for the first release, it will save us some time. Having real links is important.

We will then see how we allow configuring this (example: #p=5 instead of query string).

What do you think?

[multipleChoiceList] create widget

This widget needs to be able to render this:

2015-08-05-111518_457x464_scrot

API

Given this html:

<div id="manufacturer"></div>

And this JavaScript:

instant.addWidget(
  instantsearch.widgets.multipleChoiceList({
    container: '#manufacturer',
    facetName: 'manufacturer'
  })
)

Default rendering output (no provided template):

<ul class="as--multipleChoiceList">
  <li><label><input type="checkbox" value="Sony" checked />Sony <span>302</span></label></li>
  <li><label><input type="checkbox" value="Microsoft" />Microsoft <span>120</span></label></li>
</ul>

<label> is important to allow clicking on the "Sony" label rather than just the checkbox. This is also the standard way bootstrap advocates writing checkboxes.

I did not detail css classes but there should be css classes aroud elements for people to style them. Following #47?

Options

  • container string or DOMElement
  • facetName string
  • template string (hogan) or function

Available data when passing your own template

Template will be inserted <li>HERE</li>

  • value string
  • count number
  • selected boolean

Default sort

By default we can sort by name.

Once we are able to sort the facet values (algolia/algoliasearch-helper-js#178) then we can provide the option here.

[hierarchicalMenu] create widget

This widget needs to be able to render this:

2015-08-05-103406_416x463_scrot

API

Reuse the menu widget and add hierarchicalFacetNames to be given:

search.addWidget(
  instantsearch.widgets.hierarchicalMenu({
    container: '#categories', 
    attributes: ['categories.lvl0', 'categories.lvl1']
  })
);

If both facetName and hierarchicalFacetNames are given, throw.

[hits]: allow configuring the hitsPerPage in the hits widget

I first allowed configuring the hitsPerPage in the pagination widget because it made sense to have pagination <=> hitsPerPage BUT after speaking with @bobylito it makes more sense to have it in the hits widget.

Mostly because you can have a hits widget without pagination and not the other way round.

So:

  • remove the hitsPerPage config from the pagination widget
  • add hitsPerPage config to the hits widget

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.