RikaidoDeveloper

@rikaido/react

Les composants React

Headless, composables, prêts à servir. Chaque exemple ci-dessous tourne pour vrai, dans cette page, sans clé.

Installer

npm
npm install @rikaido/react @rikaido/sdk

Du TypeScript compilé, React 18 ou plus, rien d’autre. Chaque composant est headless : il expose des attributs data-rikaido="…" et des render props, et ne porte aucun style. @rikaido/react/atelier.css est une façon de les dessiner — c’est celle des exemples ici — et la tienne en est une autre.

la racine
import { RikaidoProvider } from "@rikaido/react";
import "@rikaido/react/atelier.css";

<RikaidoProvider apiKey={import.meta.env.RIKAIDO_KEY} locale="fr">
  {/* tout ce qui suit */}
</RikaidoProvider>

Le verdict

Le harnais rend un verdict ; Verdict le montre comme une relecture — huit lignes dans l’ordre du validateur, chacune propre, notée, en erreur, refusée ou pas pour ce plat. Ici, une allergie à l’arachide et un satay au beurre d’arachide.

Verdict.Root · Rows · Locken direct
L’exemple charge…

useVerdict(recipe, constraints) appelle l’API et met la réponse en cache par corps de requête. Verdict.Rows dessine les huit lignes ; Verdict.Lock dit le verrou en un mot : « Non servie. », « Servie. », « Servie, avec ses notes. » Les phrases viennent de la spec publiée, en français ou en anglais.

Verdict.Root{ verdict, locale?, attribution?, children }
Le contexte. children peut être une fonction ({ rows, safe, ok }) => … pour tout dessiner toi-même.
Verdict.Rows{ showSkipped?, children? }
Les huit lignes. children(row, i) pour dessiner chaque ligne ; showSkipped={false} pour cacher celles qui n’ont pas tourné.
Verdict.Row{ row }
Une ligne : la marque, le nom du contrôle, les trouvailles.
Verdict.Issue{ issue }
Une trouvaille : la phrase du cuisinier, le sujet, le code.
Verdict.Lock{}
Le verrou, en un mot.
useVerdict(recipe, constraints?)Async<Verdict>
{ status: 'idle' | 'loading' | 'ready' | 'error', data?, error? }.
verdictRows(verdict, locale)VerdictRow[]
La même chose, en pur, pour ton propre rendu.

Avec un render prop, tu dessines tout toi-même et la structure reste la sienne :

Verdict.Root avec un render propen direct
L’exemple charge…

Attributs exposés : data-rikaido="verdict" (data-safe, data-ok), verdict-rows, verdict-row (data-check, data-state), verdict-mark, verdict-check, verdict-findings, verdict-issue (data-code, data-severity : error, warn, safety), verdict-text, verdict-subject, verdict-code, verdict-lock.

Le cast

Deux portraits par ingrédient : le dessin kawaii, un SVG de 64 × 64 rendu en ligne, et le jouet 3D, un WebP servi par adresse et chargé par le composant parce qu’il voyage avec ta clé.

IngredientPortraiten direct
L’exemple charge…
IngredientPortrait{ name, form?, size?, alt?, fallback?, attribution?, children? }
form : kawaii (défaut) ou toy. children({ portrait, toyUrl, status }) pour tout dessiner toi-même. Un nom que le cast n’a pas montre fallback, ou l’initiale.
useIngredientPortrait(name)Async<Portrait>
{ slug, kawaiiSvg, kawaiiUrl, toyUrl }.
useToyUrl(name)Async<string>
Le jouet en blob: URL, révoquée quand le composant part.

Attributs exposés : data-rikaido="portrait" (data-form, data-status), portrait-kawaii, portrait-toy, portrait-fallback.

Le graphe

Ce que le graphe sait d’un ingrédient : de quoi il est fait, ce qui le remplace. AllergenBadges fait l’union sur toute une liste et dit quand un ingrédient lui est inconnu — une rangée vide parce que le graphe n’a jamais vu l’aliment ne doit jamais se lire comme « sans allergène ».

AllergenBadges · Substitutionsen direct
L’exemple charge…
AllergenBadges{ names, locale?, attribution?, children? }
Un nom ou une liste. children({ allergens, unknown, status }) pour dessiner toi-même.
Substitutions{ name, locale?, attribution?, children? }
Les remplacements que la table tient, avec le ratio et le rôle préservé. Vide pour la longue traîne — jamais inventé.
useIngredient(name, { neighbours? })Async<GraphIngredient>
{ canonical, known, facts, substitutions, art, neighbourhood? }.
allergenLabel(code, locale)string
« arachide », "peanut" — les neuf allergènes dans la langue du cuisinier.

Attributs exposés : data-rikaido="allergens" (data-status, data-unknown), allergen (data-allergen), allergen-none, allergen-unknown, substitutions, substitution (data-role), substitution-swap, substitution-ratio, substitution-why, substitution-caveat.

Lire une source

Une adresse, un markdown ou un texte collé ; la recette qu’il contient, dans la forme que le harnais lit.

RecipeReaderen direct
L’exemple charge…
RecipeReader{ onRead?, locale?, placeholder?, submitLabel?, children? }
Un formulaire avec les bons rôles. children(state) pour dessiner l’état sous le champ.
useRecipeRead(){ state, read(source, locale?), reset }
Le hook, sans le formulaire.

Les petites choses

Pures, sans réseau, sans clé — ce que chaque app de cuisine réécrit.

Mettre à l’échelle

« 1 ½ », « 2-3 », « 3/4 » lus en nombres, multipliés, réécrits en jolies fractions. Ce qui ne se lit pas — « une pincée » — reste écrit tel quel.

useScaledRecipeen direct
L’exemple charge…
useScaledRecipe(recipe, servings, baseServings, locale?)Recipe
Mémoïsé sur ses arguments.
scaleRecipe(recipe, factor, locale?)Recipe
La fonction pure. Chaque ingrédient gagne scaled (nombre ou null) et display.
parseQuantity(text) · formatQuantity(n, locale?)number | null · string
Les deux moitiés, séparément.

Les unités

Métrique et impérial, dans les deux sens : g ↔ oz et lb, ml ↔ c. à thé, c. à soupe et tasses, °C ↔ °F. Une unité inconnue revient telle quelle.

useUnitsen direct
L’exemple charge…

La minuterie

Un réducteur, un intervalle, et les deux choses qu’un cuisinier veut savoir : combien il reste, et si ça a sonné. Elle ne dérive pas : le temps restant se calcule sur l’horloge, pas sur les ticks.

useTimeren direct
L’exemple charge…
useTimer(totalMs, { onDone?, tickMs? }){ clock, remainingMs, progress, running, done, start, pause, reset, add }
clock est « 1:30 » ou « 1:00:00 ».
timerReducer · remainingOf · formatClockpur
Pour ton propre état, sans le hook.

Les étapes, une à la fois

Le pager du mode cuisson : il tient l’index, tu dessines l’étape. Les touches du clavier sont déjà branchées sur props.

useCookStepsen direct
L’exemple charge…
useCookSteps(steps, initial?){ step, index, count, isFirst, isLast, next, prev, go, props, tempC }
Étale props sur le conteneur : role="group", l’étiquette « 2 / 4 », tabIndex, et onKeyDown pour ←, →, Espace, Entrée, Début, Fin.

La marque

Chaque composant qui montre une donnée de Rikaido — le verdict, un portrait, les faits du graphe — porte « Propulsé par Rikaido », un lien discret avec le sceau. C’est la contrepartie du palier gratuit : le code est Apache-2.0, la marque reste. attribution="mark" garde seulement le sceau ; attribution="none" est pour un compte avec carte au dossier.

PoweredByRikaido
import { PoweredByRikaido, RikaidoSeal } from "@rikaido/react";

<PoweredByRikaido />                 // le sceau et les mots, dans la langue du provider
<PoweredByRikaido variant="mark" />  // le sceau seul, les mots pour les lecteurs d’écran
<RikaidoSeal size={24} />            // le sceau, pour ton propre lien

Sans styles, ou avec les tiens

Rien ici n’impose une apparence. Chaque pièce porte un attribut data-rikaido et, quand il y a un état, un data-* qui le nomme. Une feuille de style qui cible ces attributs habille tout d’un coup :

ta feuille
[data-rikaido="verdict-row"][data-state="refused"] { color: crimson; }
[data-rikaido="allergen"] { border-radius: 999px; padding: 2px 10px; background: #fee; }
[data-rikaido="attribution"] { font-size: 12px; opacity: 0.7; }

@rikaido/react/atelier.css fait exactement ça, dans la finition de l’atelier. Lis-la comme un point de départ.