autocomplete icon indicating copy to clipboard operation
autocomplete copied to clipboard

feat(layout): introduce Layout API

Open francoischalifour opened this issue 3 years ago • 5 comments

This introduces the Layout API via a new package: @algolia/autocomplete-layout-classic. The styles are included in the Autocomplete Classic Theme, which is required for these layouts.

Goal

Layouts aim at providing minimal UI elements that are common in Autocomplete experiences.

What's included

  • Navigation command keys. Accessibility hints to use the autocomplete from the keyboard.
  • Search by Algolia logo. The official Algolia footer for free plans.

Preview

image

Usage

Basic

autocomplete({
  // ...
  render({ sections, createElement, Fragment }, root) {
    render(
      <Fragment>
        <div className="aa-PanelLayout">{sections}</div>
        <footer className="aa-PanelFooter">
          {NavigationCommandsLayout({
            createElement,
            Fragment,
          })}
          {SearchByAlgoliaLayout({
            createElement,
            Fragment,
          })}
        </footer>
      </Fragment>,
      root
    );
  },
});

With translations

autocomplete({
  // ...
  render({ sections, createElement, Fragment }, root) {
    render(
      <Fragment>
        <div className="aa-PanelLayout">{sections}</div>
        <footer className="aa-PanelFooter">
          {NavigationCommandsLayout({
            createElement,
            Fragment,
            translations: {
              toClose: 'pour fermer',
              toNavigate: 'pour naviguer',
              toSelect: 'pour sélectionner',
            },
          })}
          {SearchByAlgoliaLayout({
            createElement,
            Fragment,
            translations: {
              searchBy: 'Recherche par',
            },
          })}
        </footer>
      </Fragment>,
      root
    );
  },
});

Documentation

You can read the documentation written in this PR.

What's next

There are still a few styling issues that need to be handled:

  • Padding with and without footer
  • Detached mode styles

Feedback

I'm open to feedback about this API. If you have any suggestions on how to make this usage easier, let me know!

francoischalifour avatar Mar 25 '21 08:03 francoischalifour

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit dad554b762eba1e3fb4b109e9088368da2c4dc60:

Sandbox Source
@algolia/autocomplete-example-github-repositories-custom-plugin Configuration
@algolia/autocomplete-example-layouts Configuration
@algolia/autocomplete-example-playground Configuration
@algolia/autocomplete-example-query-suggestion-with-categories Configuration
@algolia/autocomplete-example-query-suggestions-with-hits Configuration
@algolia/autocomplete-example-query-suggestions-with-inline-categories Configuration
@algolia/autocomplete-example-query-suggestions-with-recent-searches Configuration
@algolia/autocomplete-example-query-suggestions Configuration
@algolia/autocomplete-example-react-renderer Configuration
@algolia/autocomplete-example-recently-viewed-items Configuration

codesandbox-ci[bot] avatar Mar 25 '21 08:03 codesandbox-ci[bot]

I would prefer an api where the layouts would infer the createElement based on the renderer that would also be used for autocomplete, something like:

import {
  createNavigationCommandsLayout,
  createSearchByAlgoliaLayout,
} from 'layouts';
const NavigationCommandsLayout = createNavigationCommandsLayout({
  createElement,
  Fragment,
});
const SearchByAlgoliaLayout = createSearchByAlgoliaLayout({
  createElement,
  Fragment,
});
autocomplete({
  // ...
  renderer: { createElement, Fragment },
  render({ sections }, root) {
    render(
      <Fragment>
        <div className="aa-PanelLayout">{sections}</div>
        <footer className="aa-PanelFooter">
          <NavigationCommandsLayout
            translations={{
              toClose: 'pour fermer',
              toNavigate: 'pour naviguer',
              toSelect: 'pour sélectionner',
            }}
          />
          <SearchByAlgoliaLayout />
        </footer>
      </Fragment>,
      root
    );
  },
});

The main criticism I have here & as well for the highlight functions is that passing createElement & Fragment is noisy. If we register the helpers / components somehow to the autocomplete instance, I think those could be inferred.

Alternative:

import { NavigationCommandsLayout, SearchByAlgoliaLayout } from 'layouts';

autocomplete({
  // ...
  renderer: { createElement, Fragment },
  components: { SearchByAlgoliaLayout, NavigationCommandsLayout },
  render({ sections, components }, root) {
    render(
      <Fragment>
        <div className="aa-PanelLayout">{sections}</div>
        <footer className="aa-PanelFooter">
          <components.NavigationCommandsLayout
            translations={{
              toClose: 'pour fermer',
              toNavigate: 'pour naviguer',
              toSelect: 'pour sélectionner',
            }}
          />
          <components.SearchByAlgoliaLayout />
        </footer>
      </Fragment>,
      root
    );
  },
});

(in the second option you could instantiate the component using the createElement & Fragment passed to autocomplete as well without bundling the layouts with autocomplete)

Haroenv avatar Mar 25 '21 13:03 Haroenv

Do we have other use cases in mind for the Layout API? For example, would we imagine packaging the templates from the classic theme, or providing an out-of-the-box preview panel layout?

I'm asking because the current API only exports two components and I'm trying to reason about what's the higher-level usage we imagine for it.

@sarahdayan We originally wanted to export components like ItemLayout, etc. but we think that it's too early to take this decision. Now that we document the markup for it, it wouldn't provide much value, but rather slow us down once we want to make more advanced templates.

Once we're settled on great default templates for items, preview panels, etc., it can become part of this package.

francoischalifour avatar Mar 25 '21 13:03 francoischalifour

I updated the API to use our new Component API:

/** @jsx h */
import { autocomplete } from '@algolia/autocomplete-js';
import {
  NavigationCommands,
  SearchByAlgolia,
} from '@algolia/autocomplete-layout-classic';
import { h, render } from 'preact';

import '@algolia/autocomplete-theme-classic';

autocomplete({
  // ...
  components: {
    NavigationCommands,
    SearchByAlgolia,
  },
  render({ sections, Fragment, components }, root) {
    render(
      <Fragment>
        <div className="aa-PanelLayout aa-Panel--scrollable">{sections}</div>
        <footer className="aa-PanelFooter">
          <components.NavigationCommands />
          <components.SearchByAlgolia />
        </footer>
      </Fragment>,
      root
    );
  },
});

francoischalifour avatar Apr 07 '21 14:04 francoischalifour

Putting "On Hold" because we de-prioritized the Layout API.

francoischalifour avatar Jun 11 '21 09:06 francoischalifour