Skip to content

Commit

Permalink
feat(autocomplete): fix width in the header desktop + component impro…
Browse files Browse the repository at this point in the history
…vements (#1804)

* feat(autocomplete): make placeholder configurable

* fix(autocomplete): allow for nil data-algolia

this will remove the attribute on the rendered element

* feat(autocomplete): allow event handler by name

* refactor(autocomplete): configurable onStateChange

* refactor(autocomplete): extract shared CSS

* fix(autocomplete): maintain largest width in header navbar

* fixup: update tests

* move notranslate to stop name instead of entire search result
  • Loading branch information
thecristen authored Nov 29, 2023
1 parent 643b467 commit e689718
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 132 deletions.
218 changes: 110 additions & 108 deletions apps/site/assets/css/_autocomplete-theme.scss
Original file line number Diff line number Diff line change
@@ -1,137 +1,139 @@
@import '@algolia/autocomplete-theme-classic';

.aa-Autocomplete {
--aa-icon-color-rgb: 22, 92, 150; // $brand-primary;
--aa-primary-color-rgb: 22, 92, 150; // $brand-primary;
--aa-search-input-height: 2.25rem;
}
// WIP as we upgrade all of the search bars
%shared-autocomplete {
.aa-Autocomplete {
--aa-icon-color-rgb: 22, 92, 150; // $brand-primary;
--aa-primary-color-rgb: 22, 92, 150; // $brand-primary;
}

// right now #header-desktop is the only search using the new library, so it's
// the only one styled here. the #header-desktop can be removed once we migrate
// the rest over
#header-desktop {
.c-search-bar__autocomplete {
.aa-Label {
margin-bottom: unset;
}
.aa-Label {
margin-bottom: unset;
}

.aa-Input {
// stylelint-disable-next-line declaration-no-important
height: var(--aa-search-input-height) !important;
}
.aa-InputWrapperPrefix {
order: 3; // move search icon to end.
}

.aa-InputWrapperPrefix {
order: 3; // move search icon to end.
}
.aa-InputWrapper {
order: 1;
}

.aa-InputWrapper {
order: 1;
padding-left: 1rem;
}
.aa-InputWrapperSuffix {
order: 2;
}

.aa-Form {
border: 3px solid $brand-primary;

.aa-InputWrapperSuffix {
order: 2;
&:focus-within {
border-color: $brand-primary-light;
box-shadow: unset;
}
}

.aa-Form {
border: 3px solid $brand-primary;
border-radius: .5rem;
.aa-LoadingIndicator,
.aa-SubmitButton {
padding-left: var(--aa-spacing-half);
width: calc(var(--aa-spacing) * 1.25 + var(--aa-icon-size) - 1px);
}

&:focus-within {
border-color: $brand-primary-lightest;
box-shadow: unset;
}
}
.aa-ClearButton {
@include fa-icon-solid($fa-var-times-circle);
color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha));
// hide default icon
.aa-ClearIcon { display: none; }
}

.aa-LoadingIndicator,
.aa-SubmitButton {
padding-left: var(--aa-spacing-half);
width: calc(var(--aa-spacing) * 1.25 + var(--aa-icon-size) - 1px);
}
.aa-SubmitButton {
@include fa-icon-solid($fa-var-search);
color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha));
// hide default icon
.aa-SubmitIcon { display: none; }
}

.aa-ClearButton {
@include fa-icon-solid($fa-var-times-circle);
color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha));
padding-right: var(--aa-spacing-half);
// hide default icon
.aa-ClearIcon { display: none; }
}
.aa-GradientBottom,
.aa-GradientTop { all: unset; }

.aa-SubmitButton {
@include fa-icon-solid($fa-var-search);
color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha));
// hide default icon
.aa-SubmitIcon { display: none; }
.aa-ItemContent {
mark {
padding: 0;
}
> * {
margin-right: .25rem;
}
}

.aa-GradientBottom,
.aa-GradientTop { all: unset; }
.aa-ItemContentTitle {
display: unset;
margin: unset;
overflow: visible;
text-overflow: unset;
white-space: normal;
}

.c-search-bar__autocomplete-results {
.aa-ItemContent {
mark {
padding: 0;
}
> * {
margin-right: .25rem;
}
}
.aa-PanelLayout {
padding: unset;
}

.aa-Panel {
margin-top: .25rem;
z-index: var(--aa-base-z-index);
}

.aa-Item {
border-bottom: $border;
border-radius: 0;
font-weight: normal;

.aa-ItemContentTitle {
display: unset;
margin: unset;
overflow: visible;
text-overflow: unset;
white-space: normal;
&:hover {
background-color: $brand-primary-lightest;
}

.aa-PanelLayout {
padding: unset;
em {
font-style: inherit;
font-weight: bold;
}

.aa-Panel {
// stylelint-disable-next-line declaration-no-important
top: 3.25rem !important;
z-index: var(--aa-base-z-index);
> a,
> button {
color: currentColor;
display: flex;
font-weight: inherit;
gap: .25rem;
min-width: 0;
padding: calc(#{$base-spacing} / 2) $base-spacing;
}

.aa-Item {
border-bottom: $border;
border-radius: 0;
font-weight: normal;

&:hover {
background-color: $brand-primary-lightest;
}

em {
font-style: inherit;
font-weight: bold;
}

> a,
> button {
color: currentColor;
display: flex;
font-weight: inherit;
gap: .25rem;
min-width: 0;
padding: calc(#{$base-spacing} / 2) $base-spacing;
}

a:hover {
text-decoration: none;
}

[class*=c-svg__icon] {
width: 1em;
}
a:hover {
text-decoration: none;
}

.aa-ItemContent,
.aa-ItemContentBody {
display: unset;
[class*=c-svg__icon] {
width: 1em;
}
}

.aa-ItemContent,
.aa-ItemContentBody {
display: unset;
}
}

#header-desktop {
--aa-search-input-height: 2.25rem;

@extend %shared-autocomplete;

.aa-Form {
border-radius: .5rem;
}

.aa-InputWrapper {
padding-left: 1rem;
}

.aa-ClearButton {
padding-right: var(--aa-spacing-half);
}
}
12 changes: 6 additions & 6 deletions apps/site/assets/css/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,15 @@

@include media-breakpoint-up(sm) {
.search-wrapper {
align-items: center;
display: flex;
flex-grow: 1;
height: 100%;
> div { height: 100%; }
justify-content: flex-end;
}
}
}

.header-navbar.new,
.m-menu__search {
.search {
align-items: center;
Expand All @@ -82,7 +83,6 @@
}
.c-form__input-container {
border-radius: 8px;
height: 44px;
}
button.c-form__submit-btn {
background-color: unset;
Expand All @@ -98,10 +98,10 @@
}

.header-navbar.new .search {
display: block;
padding-left: 24px;
.c-form__input-container {
max-width: 350px;
}
width: 100%;

@include media-breakpoint-only(xs) {
display: none;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ exports[`Algolia v1 autocomplete matches snapshot 1`] = `
data-algolia="routes,stops,drupal"
data-geolocation=""
data-locations=""
data-placeholder="Search for routes, info, and more"
>
<div
aria-expanded="false"
Expand Down
6 changes: 4 additions & 2 deletions apps/site/assets/ts/ui/__tests__/autocomplete-helpers-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import {
getTitleAttribute,
transitNearMeURL,
onStateChange
STATE_CHANGE_HANDLERS
} from "./../autocomplete/helpers";
import * as MediaBreakpoints from "../../helpers/media-breakpoints";
import {
Expand Down Expand Up @@ -52,7 +52,9 @@ test("transitNearMeURL maps a lat/lon to a URL", () => {
);
});

describe("onStateChange", () => {
describe("onStateChange handlers - nav", () => {
const onStateChange = STATE_CHANGE_HANDLERS["nav"];

beforeEach(() => {
// reset to default state
delete document.documentElement.dataset.navOpen;
Expand Down
1 change: 1 addition & 0 deletions apps/site/assets/ts/ui/__tests__/autocomplete-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const body = `
data-geolocation
data-locations
data-algolia="routes,stops,drupal"
data-placeholder="Search for routes, info, and more"
></div>
<div class="c-search-bar__autocomplete-results"></div>
</div>
Expand Down
11 changes: 9 additions & 2 deletions apps/site/assets/ts/ui/autocomplete/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { OnStateChangeProps } from "@algolia/autocomplete-js";
import { ContentItem, Item, RouteItem, StopItem } from "./__autocomplete";
import { isLGDown } from "../../helpers/media-breakpoints";

function isStopItem(x: Item): x is StopItem {
export function isStopItem(x: Item): x is StopItem {
return Object.keys(x).includes("stop");
}

Expand Down Expand Up @@ -37,7 +37,7 @@ export function transitNearMeURL(
}`;
}

export const onStateChange: (props: OnStateChangeProps<Item>) => void = ({
const navStateChange: (props: OnStateChangeProps<Item>) => void = ({
state
}) => {
// grey out the page and disable scrolling when search is open
Expand All @@ -49,3 +49,10 @@ export const onStateChange: (props: OnStateChangeProps<Item>) => void = ({
}
}
};

export const STATE_CHANGE_HANDLERS: Record<
string,
(props: OnStateChangeProps<Item>) => void
> = {
nav: navStateChange
};
7 changes: 4 additions & 3 deletions apps/site/assets/ts/ui/autocomplete/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createElement, Fragment } from "react";
import { render } from "react-dom";
import getSources from "./sources";
import { Item } from "./__autocomplete";
import { onStateChange } from "./helpers";
import { STATE_CHANGE_HANDLERS } from "./helpers";

// replace the default Preact-based renderer used by AutocompleteJS
const reactRenderer = {
Expand Down Expand Up @@ -33,11 +33,12 @@ function setupAlgoliaAutocomplete(wrapper: HTMLElement): void {
input: "c-form__input-container"
},
openOnFocus: true,
onStateChange,
onStateChange:
STATE_CHANGE_HANDLERS[`${container.dataset.stateChangeListener}`],
onSubmit({ state }) {
window.Turbolinks.visit(`/search?query=${state.query}`);
},
placeholder: "Search for routes, info, and more",
placeholder: container.dataset.placeholder,
getSources: params => getSources(container.dataset, params),
renderer: reactRenderer
};
Expand Down
Loading

0 comments on commit e689718

Please sign in to comment.