horameus / Lupokedex

Web app Pokedex
0 stars 0 forks source link

release/0.1.0 - Input component #3

Open BenoitSafari opened 2 months ago

BenoitSafari commented 2 months ago

Input component

Créer un composant web "Input Search" ré-utilisable.

Criteres d'acceptation

Style

Les valeurs en PX sont a convertir en REM Type Value
border-color --palette-text-caption
min width 300px
min height 33px
padding top/bottom 6px
padding left/right 12px
border-radius 5px
gap 12px

Maquette

image

Assets

L'icone SVG

<svg width="16" height="17" viewBox="0 0 16 17" xmlns="http://www.w3.org/2000/svg">
    <path d="M11.7429 10.843C12.7112 9.52166 13.1449 7.88346 12.9572 6.25612C12.7695 4.62878 11.9743 3.13231 10.7307 2.0661C9.48701 0.999892 7.88665 0.442575 6.24973 0.505648C4.61282 0.568721 3.06008 1.24753 1.90217 2.40628C0.744249 3.56502 0.0665484 5.11825 0.00464653 6.75521C-0.0572553 8.39216 0.501207 9.99213 1.56831 11.235C2.6354 12.4779 4.13244 13.272 5.75992 13.4586C7.38739 13.6451 9.02528 13.2102 10.3459 12.241H10.3449C10.3742 12.281 10.4069 12.3193 10.4429 12.356L14.2929 16.206C14.4804 16.3936 14.7348 16.4991 15 16.4992C15.2653 16.4993 15.5198 16.394 15.7074 16.2065C15.895 16.019 16.0005 15.7646 16.0006 15.4993C16.0007 15.2341 15.8954 14.9796 15.7079 14.792L11.8579 10.942C11.8222 10.9058 11.7837 10.8733 11.7429 10.843ZM12.0009 6.99897C12.0009 7.72124 11.8586 8.43644 11.5822 9.10373C11.3058 9.77102 10.9007 10.3773 10.39 10.8881C9.87926 11.3988 9.27295 11.8039 8.60566 12.0803C7.93837 12.3567 7.22317 12.499 6.5009 12.499C5.77863 12.499 5.06343 12.3567 4.39614 12.0803C3.72885 11.8039 3.12253 11.3988 2.61181 10.8881C2.10109 10.3773 1.69596 9.77102 1.41956 9.10373C1.14316 8.43644 1.0009 7.72124 1.0009 6.99897C1.0009 5.54028 1.58036 4.14133 2.61181 3.10988C3.64326 2.07843 5.04221 1.49897 6.5009 1.49897C7.95959 1.49897 9.35853 2.07843 10.39 3.10988C11.4214 4.14133 12.0009 5.54028 12.0009 6.99897Z" fill="currentColor"/>
</svg>
horameus commented 1 month ago

J'ai avancé sur l'Input, j'ai juste quelques soucis avec le CSS pour le SVG, je ne suis pas trop sûr de comment faire, j'ai fait un premier push

BenoitSafari commented 1 month ago

J'ai avancé sur l'Input, j'ai juste quelques soucis avec le CSS pour le SVG, je ne suis pas trop sûr de comment faire, j'ai fait un premier push

Tu as plusieurs possibilitées, une piste assez simple est transformer ton svg en composant

function SvgIcon() {
  return(
    <svg width="16" height="17" viewBox="0 0 16 17" xmlns="http://www.w3.org/2000/svg">
      <path d="M11.7429 10.843C12.7112 9.52166 13.1449 7.88346 12.9572 6.25612C12.7695 4.62878 11.9743 3.13231 10.7307 2.0661C9.48701 0.999892 7.88665 0.442575 6.24973 0.505648C4.61282 0.568721 3.06008 1.24753 1.90217 2.40628C0.744249 3.56502 0.0665484 5.11825 0.00464653 6.75521C-0.0572553 8.39216 0.501207 9.99213 1.56831 11.235C2.6354 12.4779 4.13244 13.272 5.75992 13.4586C7.38739 13.6451 9.02528 13.2102 10.3459 12.241H10.3449C10.3742 12.281 10.4069 12.3193 10.4429 12.356L14.2929 16.206C14.4804 16.3936 14.7348 16.4991 15 16.4992C15.2653 16.4993 15.5198 16.394 15.7074 16.2065C15.895 16.019 16.0005 15.7646 16.0006 15.4993C16.0007 15.2341 15.8954 14.9796 15.7079 14.792L11.8579 10.942C11.8222 10.9058 11.7837 10.8733 11.7429 10.843ZM12.0009 6.99897C12.0009 7.72124 11.8586 8.43644 11.5822 9.10373C11.3058 9.77102 10.9007 10.3773 10.39 10.8881C9.87926 11.3988 9.27295 11.8039 8.60566 12.0803C7.93837 12.3567 7.22317 12.499 6.5009 12.499C5.77863 12.499 5.06343 12.3567 4.39614 12.0803C3.72885 11.8039 3.12253 11.3988 2.61181 10.8881C2.10109 10.3773 1.69596 9.77102 1.41956 9.10373C1.14316 8.43644 1.0009 7.72124 1.0009 6.99897C1.0009 5.54028 1.58036 4.14133 2.61181 3.10988C3.64326 2.07843 5.04221 1.49897 6.5009 1.49897C7.95959 1.49897 9.35853 2.07843 10.39 3.10988C11.4214 4.14133 12.0009 5.54028 12.0009 6.99897Z" fill="currentColor"/>
    </svg>
  )
}

Mais dans notre cas on va ré-utiliser pas mal d'assets au format SVG pour nos icones, ce qui implique de rendre ce composant plus generique. Une solution que j'aime bien dans ce cas la c'est d'assigner a mon composants des "sous-composants".

Exemple d'un projet ou je l'ai fait

// PropsMapper (donne ses props a ses childs)
export default function usePropsMapper<T extends (Partial<unknown> & React.Attributes) & PropsWithChildren>(
    { children: childFromProps, ...props }: T,
    children?: React.ReactNode | undefined,
) {
    return React.useMemo(
        () =>
            React.Children.map(children ?? childFromProps, c =>
                React.isValidElement(c) ? React.cloneElement(c, { ...convertToHtmlAttributes(props) }) : c,
            ),
        [props, children, childFromProps],
    );
}

export const convertToHtmlAttributes = (props: Record<string, unknown>) => {
    for (const key in props) if (typeof props[key] === 'boolean') props[key] = props[key].toString();
    return props;
};

// Composant de base
export default function SdBaseIcon(props: Props) {
    const resolved = useProps(props, 'SdIcon'); // Equivalent a notre useClassNames
    return usePropsMapper(resolved);
}

// Exemple d'une icone
export const SearchIcon = (props: SdIconProps) => (
    <SdBaseIcon {...props}>
        <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            fill="currentColor"
            viewBox="0 0 16 16">
            <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0" />
        </svg>
    </SdBaseIcon>
);

// index.ts
import Component from './SdBaseIcon';
import { SearchIcon } from './icons/SearchIcon';

export { type SdIconProps } from './types';
export const SdIcon = Object.assign(Component, { SearchIcon });

// Utilisation
<div>
  <SdIcon.AccountIcon />
  <SdIcon.SearchIcon />
  ect...
</div>
horameus commented 1 month ago

Pour les choses que je n'ai pas trop compris :

export default function SdBaseIcon(props: Props) {
    const resolved = useProps(props, 'SdIcon'); // Equivalent a notre useClassNames
    return usePropsMapper(resolved);
}

useProps renvoie bien une chaine de caractères ? comme useClassNames dans notre projet ?

Si c'est le cas, je ne comprends pas trop ce qu'est SdBaseIcon :

<SdBaseIcon {...props}>

est ce que c'est un véritable élément HTML ? ou bien c'est un bloc 'invisible' qui ne fait qu'envoyer ces props à la balise enfant (ici le svg) ?

Et le usePropsMapper est bien une fonction générique qui permet de transmettre les props au childs, et qu'importe le parent et le children ?

BenoitSafari commented 1 month ago

Pour les choses que je n'ai pas trop compris :

export default function SdBaseIcon(props: Props) {
    const resolved = useProps(props, 'SdIcon'); // Equivalent a notre useClassNames
    return usePropsMapper(resolved);
}

useProps renvoie bien une chaine de caractères ? comme useClassNames dans notre projet ?

Si c'est le cas, je ne comprends pas trop ce qu'est SdBaseIcon :

<SdBaseIcon {...props}>

est ce que c'est un véritable élément HTML ? ou bien c'est un bloc 'invisible' qui ne fait qu'envoyer ces props à la balise enfant (ici le svg) ?

Et le usePropsMapper est bien une fonction générique qui permet de transmettre les props au childs, et qu'importe le parent et le children ?

useProps resoud toutes les props et notament les classes et usePropsMapper transfert les props. Ce qui me permet de ne traiter mes props qu'une seule fois, mais ce n'est pas important. SdBaseIcon est bien un composant React mais il n'a aucune balise HTML, c'est comme si je faisait un composant qui rend un children dans un fragment => <>{children}</>

Ce qu'il faut retenir c'est que SdBaseIcon a sa feuille de style et resoud les props de n'importe quelle icone. On peut soit avoir un composant qui ne rend que son children et qui lui transfert ses props (comme ce que je fais dans l'exemple a l'aide du mapper), soit rendre la balise SVG et son children en resolvant les classes.

On veut traiter les props qu'une seule fois avec un composant "maitre" (ici SdBaseIcon) et ensuite appeller ce composant pour chaque icone.

horameus commented 1 month ago

Pour cette issue je vais voir avec toi quand j'aurais un peu de temps, je n'arrive pas à passer 'disabled' dans la class de la searchBar

horameus commented 1 month ago

L'input fonctionne correctement, mais je n'ai pas réussi à inclure le propsMapper dedans, Je voudrais bien regarder avec toi à l'occas pour rendre le code plus générique :) Je me lance dans l'issue 8