klee-contrib/focus4

Personnaliser les composants de sélection (et d'affichage) de facettes individuelles (autocomplete, sliders...)

Closed this issue · 2 comments

Exemple de composant d'autocomplete pour facette.

// Libs
import { autocompleteFor, computed, makeField, observer, React } from "focus4";
import { AutocompleteResult } from "focus4/components";
import { CustomSearchStore } from "../../../../01-core/stores/custom-search";

export interface AutocompleteFacetProps {
    store: CustomSearchStore<any>;
    facetCode: string;
    label: string;
    placeHolderLabel: string;
}

const toNormalizedLowerString = (str: string) => {
    if (!str) {
        return str;
    }
    // https://en.wikipedia.org/wiki/Combining_character#Unicode_ranges
    /*
    Combining Diacritical Marks (0300–036F), since version 1.0, with modifications in subsequent versions down to 4.1
    Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
    Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
    Combining Diacritical Marks for Symbols (20D0–20FF), since version 1.0, with modifications in subsequent versions down to 5.1
    Combining Half Marks (FE20–FE2F), versions 1.0, with modifications in subsequent versions down to 8.0
    */

    let toFilter = str.toLocaleLowerCase().normalize("NFKD");

    toFilter = Array.prototype.map
        .call(toFilter, (elt: string) => {
            const cp = elt.codePointAt(0)!;
            if (
                (cp >= 768 && cp <= 879) /* 0300–036F */ ||
                (cp >= 6832 && cp <= 6911) /* 1AB0–1AFF */ ||
                (cp >= 7616 && cp <= 7679) /* 1DC0–1DFF */ ||
                (cp >= 8400 && cp <= 8447) /* 20D0–20FF */ ||
                (cp >= 65056 && cp <= 65071) /* FE20–FE2F */
            ) {
                return "";
            }

            return elt;
        })
        .join("");

    return toFilter.normalize("NFKC");
};

@observer
class AutocompleteFacet extends React.Component<AutocompleteFacetProps> {
    @computed.struct
    get normarlizedFacet() {
        const { store, facetCode } = this.props;

        return store.facets
            .find(facet => facet.code === facetCode)!
            .values.map(facet => ({ key: facet.code, label: toNormalizedLowerString(facet.label) }));
    }

    constructor(props: AutocompleteFacetProps) {
        super(props);

        this.querySearcher = this.querySearcher.bind(this);
        this.handleOnClick = this.handleOnClick.bind(this);
    }

    querySearcher(query: string): Promise<AutocompleteResult> {
        const normalizedQuery = toNormalizedLowerString(query);

        const results = this.normarlizedFacet.filter(facet => facet.label.indexOf(normalizedQuery) !== -1);
        const totalCount = results.length;

        return Promise.resolve({ data: results.slice(0, 100), totalCount });
    }

    handleOnClick(key: string | undefined) {
        const { store, facetCode } = this.props;

        if (key) {
            if (store.selectedFacets[facetCode] === undefined) {
                store.selectedFacets = { ...store.selectedFacets, NomIntervenant: [key] };
            } else {
                store.selectedFacets[facetCode].push(key);
                store.search();
            }
        }
    }

    render() {
        return (
            <div>
                {autocompleteFor(makeField(() => "", { label: this.props.label }, this.handleOnClick, true), {
                    querySearcher: this.querySearcher,
                    disableInlineSizing: true,
                    autocompleteProps: {
                        label: this.props.placeHolderLabel,
                        isQuickSearch: true
                    }
                })}
            </div>
        );
    }
}

export { AutocompleteFacet };
JabX commented

J'ai eu une autre requête pour remplacer le composant de sélection de facettes multivaluées en un double slider pour choisir un intervalle (à la place de cases à cocher).

Le besoin est plus général que simplement supporter de l'autocomplétion, donc il faudrait réfléchir à soit permettre de remplacer des composants de rendu/sélection de facettes spécifiques, ou bien directement proposer une série d'affichages différents au sein de Focus.

JabX commented

On va proposer de pouvoir remplacer des composants d'affichage de facettes individuelles au sein du FacetBox (qui ne sera pas accessible via le composant global AdvancedSearch pour ne pas le surcharger trop). On en profitera pour ajouter des data attributes avec le code de facettes sur les titres et les chips dans le summary pour identifier les facettes (ex : couleur différente par facette)