From 59dc31bec1b4ba0f199359bfaddb2d37074ae8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chalifour?= Date: Wed, 2 Dec 2020 19:21:04 +0100 Subject: [PATCH] feat(js): add loading indicator --- packages/autocomplete-js/src/autocomplete.ts | 3 +++ .../src/components/LoadingIcon.ts | 2 +- .../src/components/LoadingIndicator.ts | 23 +++++++++++++++++++ .../src/components/ResetIcon.ts | 1 + .../src/components/SearchIcon.ts | 1 + .../autocomplete-js/src/components/index.ts | 2 ++ .../src/createAutocompleteDom.ts | 4 ++++ packages/autocomplete-js/src/render.ts | 14 +++++------ packages/autocomplete-js/src/types/index.ts | 2 ++ .../autocomplete-theme-classic/src/theme.scss | 18 +++++++++++++-- packages/website/docs/autocomplete-js.md | 2 ++ 11 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 packages/autocomplete-js/src/components/LoadingIndicator.ts diff --git a/packages/autocomplete-js/src/autocomplete.ts b/packages/autocomplete-js/src/autocomplete.ts index 67b61b03c..ccd2fd100 100644 --- a/packages/autocomplete-js/src/autocomplete.ts +++ b/packages/autocomplete-js/src/autocomplete.ts @@ -49,6 +49,7 @@ export function autocomplete({ input, submitButton, resetButton, + loadingIndicator, root, panel, } = createAutocompleteDom({ @@ -114,6 +115,7 @@ export function autocomplete({ panel, submitButton, resetButton, + loadingIndicator, }); return () => {}; @@ -145,6 +147,7 @@ export function autocomplete({ panel, submitButton, resetButton, + loadingIndicator, }); }, 0); diff --git a/packages/autocomplete-js/src/components/LoadingIcon.ts b/packages/autocomplete-js/src/components/LoadingIcon.ts index 00f18387a..40d86cde4 100644 --- a/packages/autocomplete-js/src/components/LoadingIcon.ts +++ b/packages/autocomplete-js/src/components/LoadingIcon.ts @@ -14,7 +14,7 @@ export const LoadingIcon: Component<{}, SVGSVGElement> = () => { r="35" stroke="currentColor" stroke-dasharray="164.93361431346415 56.97787143782138" - stroke-width="4" + stroke-width="6" > ; + +export const LoadingIndicator: Component< + LoadingIndicatorProps, + HTMLDivElement +> = ({ classNames }) => { + const element = document.createElement('div'); + setProperties(element, { + class: concatClassNames([ + 'aa-LoadingIndicator', + classNames.loadingIndicator, + ]), + }); + + element.appendChild(LoadingIcon({})); + + return element; +}; diff --git a/packages/autocomplete-js/src/components/ResetIcon.ts b/packages/autocomplete-js/src/components/ResetIcon.ts index 22d64ed4c..ad688609a 100644 --- a/packages/autocomplete-js/src/components/ResetIcon.ts +++ b/packages/autocomplete-js/src/components/ResetIcon.ts @@ -2,6 +2,7 @@ import { Component } from '../types/Component'; export const ResetIcon: Component<{}, SVGSVGElement> = () => { const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + element.setAttribute('class', 'aa-ResetIcon'); element.setAttribute('viewBox', '0 0 20 20'); element.setAttribute('width', '20'); element.setAttribute('height', '20'); diff --git a/packages/autocomplete-js/src/components/SearchIcon.ts b/packages/autocomplete-js/src/components/SearchIcon.ts index ca6fec2b8..210685522 100644 --- a/packages/autocomplete-js/src/components/SearchIcon.ts +++ b/packages/autocomplete-js/src/components/SearchIcon.ts @@ -2,6 +2,7 @@ import { Component } from '../types/Component'; export const SearchIcon: Component<{}, SVGSVGElement> = () => { const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + element.setAttribute('class', 'aa-SubmitIcon'); element.setAttribute('viewBox', '0 0 20 20'); element.setAttribute('width', '20'); element.setAttribute('height', '20'); diff --git a/packages/autocomplete-js/src/components/index.ts b/packages/autocomplete-js/src/components/index.ts index 05c195456..07d955c31 100644 --- a/packages/autocomplete-js/src/components/index.ts +++ b/packages/autocomplete-js/src/components/index.ts @@ -2,6 +2,8 @@ export * from './Form'; export * from './Input'; export * from './InputWrapper'; export * from './Label'; +export * from './LoadingIcon'; +export * from './LoadingIndicator'; export * from './Panel'; export * from './PanelLayout'; export * from './ResetButton'; diff --git a/packages/autocomplete-js/src/createAutocompleteDom.ts b/packages/autocomplete-js/src/createAutocompleteDom.ts index 1bfc28573..e4ca987f5 100644 --- a/packages/autocomplete-js/src/createAutocompleteDom.ts +++ b/packages/autocomplete-js/src/createAutocompleteDom.ts @@ -8,6 +8,7 @@ import { Input, InputWrapper, Label, + LoadingIndicator, Panel, ResetButton, Root, @@ -33,6 +34,7 @@ export function createAutocompleteDom({ const input = Input({ classNames, getInputProps }); const submitButton = SubmitButton({ classNames }); const resetButton = ResetButton({ classNames }); + const loadingIndicator = LoadingIndicator({ classNames }); const form = Form({ classNames, ...getFormProps({ inputElement: input }) }); const panel = Panel({ classNames, ...getPanelProps({}) }); @@ -40,6 +42,7 @@ export function createAutocompleteDom({ inputWrapper.appendChild(input); inputWrapper.appendChild(label); inputWrapper.appendChild(resetButton); + inputWrapper.appendChild(loadingIndicator); form.appendChild(inputWrapper); root.appendChild(form); @@ -51,6 +54,7 @@ export function createAutocompleteDom({ label, submitButton, resetButton, + loadingIndicator, panel, }; } diff --git a/packages/autocomplete-js/src/render.ts b/packages/autocomplete-js/src/render.ts index f4c68497e..7c4eb2a8e 100644 --- a/packages/autocomplete-js/src/render.ts +++ b/packages/autocomplete-js/src/render.ts @@ -16,7 +16,7 @@ import { AutocompleteRenderer, AutocompleteState, } from './types'; -import { setPropertiesWithoutEvents } from './utils'; +import { setProperties, setPropertiesWithoutEvents } from './utils'; type RenderProps = { state: AutocompleteState; @@ -38,12 +38,16 @@ export function render( root, input, resetButton, + submitButton, + loadingIndicator, panel, }: RenderProps ): () => void { setPropertiesWithoutEvents(root, getRootProps({})); - setPropertiesWithoutEvents(resetButton, { hidden: !state.query }); setPropertiesWithoutEvents(input, getInputProps({ inputElement: input })); + setPropertiesWithoutEvents(resetButton, { hidden: !state.query }); + setProperties(submitButton, { hidden: state.status === 'stalled' }); + setProperties(loadingIndicator, { hidden: state.status !== 'stalled' }); panel.innerHTML = ''; @@ -59,11 +63,7 @@ export function render( panelRoot.appendChild(panel); } - if (state.status === 'stalled') { - panel.classList.add('aa-Panel--stalled'); - } else { - panel.classList.remove('aa-Panel--stalled'); - } + panel.classList.toggle('aa-Panel--stalled', state.status === 'stalled'); const sections = state.collections.map(({ source, items }) => { const sectionElement = SourceContainer({ classNames }); diff --git a/packages/autocomplete-js/src/types/index.ts b/packages/autocomplete-js/src/types/index.ts index bbaa3635a..3feb9ef70 100644 --- a/packages/autocomplete-js/src/types/index.ts +++ b/packages/autocomplete-js/src/types/index.ts @@ -78,6 +78,7 @@ export type AutocompleteClassNames = Partial<{ input: string; submitButton: string; resetButton: string; + loadingIndicator: string; panel: string; panelLayout: string; source: string; @@ -95,6 +96,7 @@ export type AutocompleteDom = { label: HTMLLabelElement; submitButton: HTMLButtonElement; resetButton: HTMLButtonElement; + loadingIndicator: HTMLDivElement; panel: HTMLDivElement; }; diff --git a/packages/autocomplete-theme-classic/src/theme.scss b/packages/autocomplete-theme-classic/src/theme.scss index 2928a8b99..981c85edf 100644 --- a/packages/autocomplete-theme-classic/src/theme.scss +++ b/packages/autocomplete-theme-classic/src/theme.scss @@ -53,13 +53,18 @@ } } +.aa-SubmitButton, +.aa-ResetButton, +.aa-LoadingIndicator { + height: 100%; + padding: 0 0.5rem; +} + .aa-SubmitButton, .aa-ResetButton { background: none; border: 0; cursor: pointer; - height: 100%; - padding: 0 0.5rem; } .aa-ResetButton { @@ -68,6 +73,15 @@ z-index: 2; } +.aa-LoadingIndicator { + position: absolute; + z-index: 2; +} + +.aa-LoadingIcon { + height: 100%; +} + .aa-Panel { max-width: 480px; position: absolute; diff --git a/packages/website/docs/autocomplete-js.md b/packages/website/docs/autocomplete-js.md index f0eb114c1..b8c830432 100644 --- a/packages/website/docs/autocomplete-js.md +++ b/packages/website/docs/autocomplete-js.md @@ -101,6 +101,8 @@ type ClassNames = Partial<{ inputWrapper: string; input: string; resetButton: string; + submitButton: string; + loadingIndicator: string; panel: string; panelLayout: string; source: string;