@recipe-book/react 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -12,44 +12,111 @@ type NotAnImageComponent = 'Recipe.Image: as must be a component whose src and a
12
12
  /** `C` when its `src` and `alt` props take a string, else `NotAnImageComponent`. */
13
13
  type ImageComponent<C extends ElementType> = 'src' | 'alt' extends keyof ComponentPropsWithoutRef<C> ? ImageAttributes extends Pick<ComponentPropsWithoutRef<C>, 'src' | 'alt'> ? C : NotAnImageComponent : NotAnImageComponent;
14
14
  /**
15
- * The props of `as`, an `<img>` by default, with `src` and `alt` optional.
16
- * `RecipeImageProps<typeof NextImage>` types a wrapper around `next/image`.
15
+ * The props of `<Recipe.Image>`: those of `C` without its `ref`, with `src`
16
+ * and `alt` optional, plus `as`. `C` defaults to `'img'`. Use it to type a
17
+ * wrapper that takes what `<Recipe.Image as={C}>` takes.
18
+ *
19
+ * @example
20
+ * import NextImage from 'next/image'
21
+ *
22
+ * function Hero(props: Recipe.RecipeImageProps<typeof NextImage>) {
23
+ * return <Recipe.Image {...props} as={NextImage} className="hero" />
24
+ * }
25
+ *
26
+ * @see https://recipe-book.siraj.page/reference/react/image/#type-a-wrapper
17
27
  */
18
28
  type RecipeImageProps<C extends ElementType = 'img'> = {
19
29
  /**
20
- * The component to render instead of `<img>`, such as `next/image`. It gets
21
- * `src`, `alt`, `data-recipe-image` and the ref, and `Recipe.Image` takes
22
- * its props. Its `src` and `alt` must take strings, and its other required
23
- * props are required on `Recipe.Image`. From a Server Component, pass a
24
- * Client Component: one whose module starts with `'use client'`, as
30
+ * The component to render instead of `<img>`, such as `next/image`. It
31
+ * gets `src`, `alt`, `data-recipe-image` and the ref, and `Recipe.Image`
32
+ * takes its props. Its `src` and `alt` must take strings, and its other
33
+ * required props are required on `Recipe.Image`. From a Server Component,
34
+ * pass a Client Component: one whose module starts with `'use client'`, as
25
35
  * `next/image`'s does.
36
+ *
37
+ * @defaultValue `'img'`
38
+ *
39
+ * @see https://recipe-book.siraj.page/reference/react/image/#render-another-component
26
40
  */
27
41
  as?: ImageComponent<C> | undefined;
28
42
  } & Omit<ComponentPropsWithoutRef<C>, 'as' | 'src' | 'alt'> & {
29
- /** Replaces the recipe's `image`, such as with a CDN URL; nothing renders when the recipe has none. */
43
+ /**
44
+ * Replaces the recipe's `image`, such as with a CDN URL. Nothing renders
45
+ * when the recipe has no `image`, even with `src`. With `as`, it takes
46
+ * that component's `src` type, such as `string | StaticImport` for
47
+ * `next/image`.
48
+ *
49
+ * @defaultValue The recipe's `image`.
50
+ *
51
+ * @see https://recipe-book.siraj.page/reference/react/image/#image
52
+ */
30
53
  src?: (ComponentPropsWithoutRef<C> extends {
31
54
  src?: infer S;
32
55
  } ? S : never) | undefined;
33
- /** The alt text. Defaults to the recipe's `name`; pass `''` for a decorative image. */
56
+ /**
57
+ * The alt text. Pass `''` for a decorative image.
58
+ *
59
+ * @defaultValue The recipe's `name`.
60
+ *
61
+ * @see https://recipe-book.siraj.page/reference/react/image/#decorative-images
62
+ */
34
63
  alt?: string | undefined;
35
64
  };
36
65
  /**
37
66
  * The recipe's image, as an `<img>` or the component passed to `as`, or
38
67
  * nothing when the recipe has none. `src` defaults to the recipe's image and
39
- * `alt` to its name; pass `alt=""` when the image is decorative.
68
+ * `alt` to its name; pass `alt=""` when the image is decorative. Other props
69
+ * pass through, and it always sets `data-recipe-image`.
70
+ *
71
+ * `Recipe.Image` takes `as`, not `asChild`, so a component such as
72
+ * `next/image` gets `src` and `alt` from the recipe and still has its
73
+ * required props checked.
74
+ *
75
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
76
+ *
77
+ * @example
78
+ * import NextImage from 'next/image'
79
+ *
80
+ * function RecipeHero() {
81
+ * return <Recipe.Image as={NextImage} width={1200} height={800} />
82
+ * }
83
+ *
84
+ * @see https://recipe-book.siraj.page/reference/react/image/
40
85
  */
41
86
  declare const Image: <C extends ElementType = "img">(props: RecipeImageProps<C> & {
42
- /** Set to the `<img>`, or passed to the `as` component. Left unset when the recipe has no image. */
87
+ /**
88
+ * Set to the `<img>`, or passed to the `as` component. Left unset when the recipe has no image.
89
+ *
90
+ * @see https://recipe-book.siraj.page/reference/react/image/#image
91
+ */
43
92
  ref?: Ref<ComponentRef<C>> | undefined;
44
93
  }) => ReactNode;
45
94
 
46
- /** What `useRecipeState()` takes. The state props of `<Recipe.Root>` are the same. */
95
+ /**
96
+ * What `useRecipeState()` takes. The state props of `<Recipe.Root>` are the
97
+ * same.
98
+ *
99
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#recipestateoptions
100
+ */
47
101
  type RecipeStateOptions = {
48
- /** A parsed recipe, as returned by `parseRecipe` in `@recipe-book/core`. */
102
+ /** A parsed recipe, as returned by `parseRecipe` in `@recipe-book/react/core`. */
49
103
  recipe: Recipe;
50
- /** The number of servings to show. Passing it makes servings controlled. */
104
+ /**
105
+ * The number of servings to show. Passing it makes servings controlled. A
106
+ * number outside the servings window shows `defaultServings` instead, with a
107
+ * warning in development.
108
+ *
109
+ * @see https://recipe-book.siraj.page/reference/react/root/#controlled-and-uncontrolled-state
110
+ */
51
111
  servings?: number | undefined;
52
- /** Starting servings when uncontrolled; defaults to the recipe's servings, then its yield, then 1. */
112
+ /**
113
+ * Starting servings when uncontrolled. A number outside the servings window
114
+ * falls back to the scaling base, with a warning in development.
115
+ *
116
+ * @defaultValue The recipe's scaling base: its servings, then its yield,
117
+ * then 1.
118
+ * @see https://recipe-book.siraj.page/reference/react/root/#scaling-base
119
+ */
53
120
  defaultServings?: number | undefined;
54
121
  /**
55
122
  * Called when `setServings` accepts a number other than the current one,
@@ -81,7 +148,12 @@ type StepItem = Step$1 & {
81
148
  /** The step's position, counted from 1 across sections. */
82
149
  number: number;
83
150
  };
84
- /** A section of a recipe's ingredients or steps. Untitled sections have no `title`. */
151
+ /**
152
+ * A section of a recipe's ingredients or steps. Untitled sections have no
153
+ * `title`.
154
+ *
155
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#recipesection
156
+ */
85
157
  type RecipeSection<T> = {
86
158
  /** The section's id from the recipe. */
87
159
  id: string;
@@ -90,7 +162,11 @@ type RecipeSection<T> = {
90
162
  /** The ingredients or steps in the section. */
91
163
  items: T[];
92
164
  };
93
- /** What `useRecipe()` and `useRecipeState()` return. */
165
+ /**
166
+ * What `useRecipe()` and `useRecipeState()` return.
167
+ *
168
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#recipestate
169
+ */
94
170
  type RecipeState = {
95
171
  /** The parsed recipe. */
96
172
  recipe: Recipe;
@@ -98,9 +174,13 @@ type RecipeState = {
98
174
  servings: number;
99
175
  /**
100
176
  * Calls `onServingsChange` with a number other than the current one, and
101
- * changes the servings unless controlled; ignores one outside a millionth to
102
- * a million times the scaling base. While a controlled `servings` is outside
103
- * that range, passing the number shown calls `onServingsChange` too.
177
+ * changes the servings unless controlled. Ignores a number outside the
178
+ * servings window, from a millionth to a million times the scaling base
179
+ * including both ends, and warns about it in development. While a
180
+ * controlled `servings` is outside that window, passing the number shown
181
+ * calls `onServingsChange` too.
182
+ *
183
+ * @see https://recipe-book.siraj.page/reference/react/root/#servings-window
104
184
  */
105
185
  setServings: (servings: number) => void;
106
186
  /** From `resolveRecipe`: `servings` divided by the recipe's servings amount, else its yield amount, else 1. */
@@ -136,23 +216,61 @@ type RecipeState = {
136
216
  *
137
217
  * @throws {RecipeBookError} `invalid_argument` in development when `recipe`
138
218
  * isn't a parsed recipe.
219
+ *
220
+ * @param options - The recipe and its state.
221
+ * @returns The recipe, its servings and display system with their setters,
222
+ * its ingredients at those settings, and its numbered steps.
223
+ *
224
+ * @example
225
+ * import type { ParsedRecipe } from '@recipe-book/react/core'
226
+ * import * as Recipe from '@recipe-book/react'
227
+ *
228
+ * function ServingsSummary({ recipe }: { recipe: ParsedRecipe }) {
229
+ * const { servings, scale } = Recipe.useRecipeState({
230
+ * recipe,
231
+ * defaultServings: 8,
232
+ * })
233
+ * return <p>{`Serves ${servings}, scaled ×${scale}`}</p>
234
+ * }
235
+ *
236
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#userecipestate
139
237
  */
140
238
  declare function useRecipeState(options: RecipeStateOptions): RecipeState;
141
239
 
142
- /** Levels a section heading can take; level 1 belongs to the page. */
240
+ /**
241
+ * The heading levels `<Recipe.Ingredients>` and `<Recipe.Steps>` take as
242
+ * `headingLevel` for section titles; level 1 belongs to the page's title.
243
+ * Both default to 3, for sections under an `<h2>` such as "Ingredients". Pass
244
+ * the level below your own heading to keep the outline in order.
245
+ *
246
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#recipeheadinglevel
247
+ */
143
248
  type RecipeHeadingLevel = 2 | 3 | 4 | 5 | 6;
144
249
 
145
- /** Attributes for the wrapping `<div>`, plus `headingLevel`; `children` renders each section. */
146
- type RecipeIngredientsProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
250
+ /**
251
+ * Attributes for the wrapping `<div>` other than `dangerouslySetInnerHTML`,
252
+ * plus `headingLevel`; `children` renders each section.
253
+ *
254
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredients
255
+ */
256
+ type RecipeIngredientsProps = Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'dangerouslySetInnerHTML'> & {
147
257
  /**
148
258
  * Heading level of section titles in the default rendering. Defaults to 3,
149
259
  * for ingredients under an `<h2>` such as "Ingredients".
260
+ *
261
+ * @defaultValue `3`
262
+ * @see https://recipe-book.siraj.page/guides/make-a-recipe-accessible/#set-heading-levels
150
263
  */
151
264
  headingLevel?: RecipeHeadingLevel | undefined;
152
265
  /**
153
266
  * Renders each section instead of the default. Each result is keyed for
154
267
  * you, so return one element or a fragment; an array's items need their own
155
268
  * keys, as anywhere in React.
269
+ *
270
+ * @defaultValue A `<section>` named by the section's heading, or a `<div>`
271
+ * for an untitled section, around a `<Recipe.IngredientList>` of its
272
+ * ingredients.
273
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-sections
156
274
  */
157
275
  children?: ((section: RecipeSection<IngredientItem>) => ReactNode) | undefined;
158
276
  };
@@ -160,33 +278,82 @@ type RecipeIngredientsProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'>
160
278
  * The recipe's ingredients at the current servings and display system, one
161
279
  * block per section. A titled section renders as a `<section>` named by its
162
280
  * heading, then a `<Recipe.IngredientList>`.
281
+ *
282
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
283
+ * @throws {RecipeBookError} `invalid_argument` from the `<Recipe.Ingredient>`
284
+ * it renders for each item by default, when Root's `locale` isn't a language
285
+ * tag that `Intl` accepts, such as `'en_US'`.
286
+ *
287
+ * @example
288
+ * <Recipe.Root recipe={recipe}>
289
+ * <h2>Ingredients</h2>
290
+ * <Recipe.Ingredients />
291
+ * </Recipe.Root>
292
+ *
293
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredients
163
294
  */
164
295
  declare const Ingredients: ForwardRefExoticComponent<RecipeIngredientsProps & RefAttributes<HTMLDivElement>>;
165
- /** Attributes for the `<ul>`, plus the `section` to list; `children` renders each ingredient. */
166
- type RecipeIngredientListProps = Omit<ComponentPropsWithoutRef<'ul'>, 'children'> & {
296
+ /**
297
+ * Attributes for the `<ul>` other than `dangerouslySetInnerHTML`, plus the
298
+ * `section` to list; `children` renders each ingredient.
299
+ *
300
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientlist
301
+ */
302
+ type RecipeIngredientListProps = Omit<ComponentPropsWithoutRef<'ul'>, 'children' | 'dangerouslySetInnerHTML'> & {
167
303
  /** The section to list. Defaults to every ingredient in the recipe. */
168
304
  section?: RecipeSection<IngredientItem> | undefined;
169
305
  /**
170
306
  * Renders each ingredient instead of `<Recipe.Ingredient>`. Each result is
171
307
  * keyed for you, so return one element or a fragment; an array's items need
172
308
  * their own keys, as anywhere in React.
309
+ *
310
+ * @defaultValue `(item) => <Recipe.Ingredient item={item} />`
311
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-ingredients
173
312
  */
174
313
  children?: ((item: IngredientItem) => ReactNode) | undefined;
175
314
  };
176
- /** An unordered list of ingredients. */
315
+ /**
316
+ * An unordered list of ingredients, one `<Recipe.Ingredient>` each unless
317
+ * `children` renders them.
318
+ *
319
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
320
+ * @throws {RecipeBookError} `invalid_argument` from the `<Recipe.Ingredient>`
321
+ * it renders for each item by default, when Root's `locale` isn't a language
322
+ * tag that `Intl` accepts, such as `'en_US'`.
323
+ *
324
+ * @example
325
+ * <Recipe.IngredientList>
326
+ * {(item) => (
327
+ * <Recipe.Ingredient item={item}>
328
+ * <Recipe.IngredientName /> <Recipe.IngredientQuantity />
329
+ * </Recipe.Ingredient>
330
+ * )}
331
+ * </Recipe.IngredientList>
332
+ *
333
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientlist
334
+ */
177
335
  declare const IngredientList: ForwardRefExoticComponent<RecipeIngredientListProps & RefAttributes<HTMLUListElement>>;
178
- /** Attributes for the `<li>`, plus the `item` to render and `asChild`. */
179
- type RecipeIngredientProps = ComponentPropsWithoutRef<'li'> & {
336
+ /**
337
+ * Attributes for the `<li>` other than `dangerouslySetInnerHTML`, plus the
338
+ * `item` to render and `asChild`.
339
+ *
340
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredient
341
+ */
342
+ type RecipeIngredientProps = Omit<ComponentPropsWithoutRef<'li'>, 'dangerouslySetInnerHTML'> & {
180
343
  /** The ingredient to render, such as one that `<Recipe.IngredientList>` passes to its `children`. */
181
344
  item: IngredientItem;
182
345
  /**
183
346
  * Renders the line as its one element child, such as `<motion.li layout />`,
184
- * instead of an `<li>`. A prop on the child wins, except that the line's
347
+ * instead of an `<li>`. Render an `<li>` or a component that renders one, so
348
+ * the list keeps its items. A prop on the child wins, except that the line's
185
349
  * `tabIndex` wins, `className`s join, `style` merges key by key with the
186
350
  * child winning, both event handlers run (the child's first), and both refs
187
351
  * are set. The child's own children replace the line's, so an empty child
188
352
  * gets the default line. With anything but one element child, it renders
189
353
  * its own `<li>`, with a warning in development.
354
+ *
355
+ * @defaultValue `false`
356
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-element
190
357
  */
191
358
  asChild?: boolean | undefined;
192
359
  };
@@ -202,16 +369,27 @@ type RecipeIngredientProps = ComponentPropsWithoutRef<'li'> & {
202
369
  * or `converted` into the display system. Unquantified lines have
203
370
  * `data-unquantified` instead. Optional ingredients have `data-optional`.
204
371
  *
372
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
373
+ * @throws {RecipeBookError} `invalid_argument` when Root's `locale` isn't a
374
+ * language tag that `Intl` accepts, such as `'en_US'`; when `item` isn't
375
+ * `{ ingredient, quantity? }`, such as an authored ingredient; or when an
376
+ * `item` you build has an amount that isn't a finite number greater than 0
377
+ * or a range of them, or a range whose `min` isn't less than its `max`.
378
+ * @throws {RecipeBookError} `unknown_unit` when the item's unit isn't a unit
379
+ * ID.
380
+ *
205
381
  * @example
206
382
  * <Recipe.Ingredient item={item} className="flex gap-2">
207
383
  * <Recipe.IngredientQuantity className="w-24 tabular-nums" />
208
384
  * <Recipe.IngredientName />
209
385
  * <Recipe.IngredientNote className="text-stone-500" />
210
386
  * </Recipe.Ingredient>
387
+ *
388
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredient
211
389
  */
212
390
  declare const Ingredient: ForwardRefExoticComponent<RecipeIngredientProps & RefAttributes<HTMLLIElement>>;
213
391
  /** Attributes for an ingredient sub-part's `<span>`, plus `asChild`; `children` go before its text. */
214
- type IngredientTextProps = ComponentPropsWithoutRef<'span'> & {
392
+ type IngredientTextProps = Omit<ComponentPropsWithoutRef<'span'>, 'dangerouslySetInnerHTML'> & {
215
393
  /**
216
394
  * Renders as its one element child, such as `<a href={url} />`, instead of a
217
395
  * `<span>`, with the text after the child's own children. A prop on the
@@ -233,6 +411,10 @@ type RecipeIngredientQuantityProps = IngredientTextProps;
233
411
  * <Recipe.IngredientQuantity>
234
412
  * {item.origin === 'converted' && '≈ '}
235
413
  * </Recipe.IngredientQuantity>
414
+ *
415
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.
416
+ *
417
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientquantity
236
418
  */
237
419
  declare const IngredientQuantity: ForwardRefExoticComponent<RecipeIngredientQuantityProps & RefAttributes<HTMLSpanElement>>;
238
420
  /** Attributes for the `<span>`, plus `asChild`; `children` go before the name. */
@@ -246,6 +428,10 @@ type RecipeIngredientNameProps = IngredientTextProps;
246
428
  * <Recipe.IngredientName asChild>
247
429
  * <a href={`/glossary/${item.id}`} />
248
430
  * </Recipe.IngredientName>
431
+ *
432
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.
433
+ *
434
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientname
249
435
  */
250
436
  declare const IngredientName: ForwardRefExoticComponent<RecipeIngredientNameProps & RefAttributes<HTMLSpanElement>>;
251
437
  /** Attributes for the `<span>`, plus `asChild`; `children` go before the note. */
@@ -256,6 +442,10 @@ type RecipeIngredientNoteProps = IngredientTextProps;
256
442
  *
257
443
  * @example
258
444
  * <Recipe.IngredientNote className="text-stone-500" />
445
+ *
446
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.
447
+ *
448
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientnote
259
449
  */
260
450
  declare const IngredientNote: ForwardRefExoticComponent<RecipeIngredientNoteProps & RefAttributes<HTMLSpanElement>>;
261
451
  /** Attributes for the `<span>`, plus `asChild`; `children` go before the label. */
@@ -267,28 +457,95 @@ type RecipeIngredientOptionalProps = IngredientTextProps;
267
457
  *
268
458
  * @example
269
459
  * <Recipe.IngredientOptional className="text-stone-500" />
460
+ *
461
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.
462
+ *
463
+ * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientoptional
270
464
  */
271
465
  declare const IngredientOptional: ForwardRefExoticComponent<RecipeIngredientOptionalProps & RefAttributes<HTMLSpanElement>>;
272
466
 
273
- /** Attributes for the `<script>` but `type`, `src` and content, plus `toJsonLd`'s options. */
274
- type RecipeJsonLdProps = Pick<ToJsonLdOptions, 'servings' | 'system' | 'url' | 'extra'> & Omit<ComponentPropsWithoutRef<'script'>, 'type' | 'children' | 'dangerouslySetInnerHTML' | 'src'>;
467
+ /**
468
+ * The props of `<Recipe.JsonLd>`: `toJsonLd`'s `servings`, `system`, `url`
469
+ * and `extra`, passed to it as they are, plus the `<script>`'s attributes but
470
+ * `type`, `src` and its content, which `<Recipe.JsonLd>` sets.
471
+ *
472
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld
473
+ */
474
+ type RecipeJsonLdProps = {
475
+ /**
476
+ * Writes the recipe at this many servings, as `resolveRecipe` scales it.
477
+ * The Root's servings don't change it.
478
+ *
479
+ * @defaultValue The recipe's own servings, unscaled.
480
+ *
481
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld
482
+ */
483
+ servings?: ToJsonLdOptions['servings'];
484
+ /**
485
+ * Writes quantities in this measurement system. The Root's system doesn't
486
+ * change it.
487
+ *
488
+ * @defaultValue `recipe.system`, then `'metric'`.
489
+ *
490
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld
491
+ */
492
+ system?: ToJsonLdOptions['system'];
493
+ /**
494
+ * The recipe page's URL. Each step gets it as `url`, with the step's id,
495
+ * percent-encoded, as the fragment; without it, steps have no `url`.
496
+ * `<Recipe.Step>` renders no `id`, so pass it the step's `id` for the
497
+ * fragment to point at it.
498
+ *
499
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/#step-ids
500
+ */
501
+ url?: ToJsonLdOptions['url'];
502
+ /**
503
+ * schema.org fields the recipe doesn't model, such as `author`,
504
+ * `datePublished`, or `keywords`, written as you pass them. A field
505
+ * `toJsonLd` writes from the recipe wins; `@context` and `@type` are always
506
+ * its own. A field that is `undefined` is left out, so
507
+ * `{ image: maybeImage }` adds an image only when there is one, and an
508
+ * `image` here stops the missing-image warning. A field `toJsonLd` writes
509
+ * from a recipe takes the type `SchemaOrgRecipe` gives it here too, so an
510
+ * `image` is a URL. Pass the `extra` that `fromJsonLd` returned to write them
511
+ * back.
512
+ *
513
+ * @example
514
+ * <Recipe.JsonLd
515
+ * url="https://example.com/pancakes"
516
+ * extra={{ author: { '@type': 'Person', name: 'Ada Lovelace' } }}
517
+ * />
518
+ *
519
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld
520
+ */
521
+ extra?: ToJsonLdOptions['extra'];
522
+ } & Omit<ComponentPropsWithoutRef<'script'>, 'type' | 'children' | 'dangerouslySetInnerHTML' | 'src'>;
275
523
  /**
276
524
  * The recipe as schema.org Recipe JSON-LD, for search engines' recipe results,
277
525
  * in a `<script type="application/ld+json">` with `<` escaped as `\u003c`.
278
526
  * Writes the recipe as authored: at its own servings and in `recipe.system`,
279
527
  * else metric, unless `servings` or `system` say otherwise. Root's current
280
- * servings and system don't change it. The text is in English.
528
+ * servings and system don't change it. The text is in English. Other props
529
+ * pass to the `<script>`, and it always sets `data-recipe-json-ld`.
281
530
  *
282
531
  * In development, logs to the browser console the warnings that `toJsonLd`
283
532
  * returns, such as for a missing `image`, unless the previous render had the
284
- * same ones in the same order.
533
+ * same ones in the same order. Nothing logs where it renders only on the
534
+ * server, such as in an Astro page without a `client:` directive.
285
535
  *
286
536
  * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
287
537
  *
288
538
  * @example
289
- * <Recipe.Root recipe={recipe}>
290
- * <Recipe.JsonLd url="https://example.com/pancakes" />
291
- * </Recipe.Root>
539
+ * // app/pancakes/page.tsx, a Server Component: no 'use client' needed
540
+ * export default function Page() {
541
+ * return (
542
+ * <Recipe.Root recipe={recipe}>
543
+ * <Recipe.JsonLd url="https://example.com/pancakes" />
544
+ * </Recipe.Root>
545
+ * )
546
+ * }
547
+ *
548
+ * @see https://recipe-book.siraj.page/reference/react/json-ld/
292
549
  */
293
550
  declare const JsonLd: ForwardRefExoticComponent<RecipeJsonLdProps & RefAttributes<HTMLScriptElement>>;
294
551
 
@@ -299,80 +556,229 @@ declare const JsonLd: ForwardRefExoticComponent<RecipeJsonLdProps & RefAttribute
299
556
  * A new key is additive: labels that leave it out keep its English default,
300
557
  * and a label pack checked with `satisfies RecipeLabels` gets a compile error
301
558
  * naming the new key.
559
+ *
560
+ * @example
561
+ * const spanish = {
562
+ * servings: 'Raciones',
563
+ * servingUnit: { one: 'ración', other: 'raciones' },
564
+ * system: 'Sistema de medida',
565
+ * metric: 'Métrico',
566
+ * us: 'EE. UU.',
567
+ * fan: 'con ventilador',
568
+ * optional: '(opcional)',
569
+ * to: 'a',
570
+ * } satisfies Recipe.RecipeLabels
571
+ *
572
+ * <Recipe.RecipeBookProvider locale="es-ES" labels={spanish}>
573
+ * {children}
574
+ * </Recipe.RecipeBookProvider>
575
+ *
576
+ * @see https://recipe-book.siraj.page/reference/react/provider/
302
577
  */
303
578
  type RecipeLabels = {
304
- /** Accessible name of the servings controls. */
579
+ /**
580
+ * Accessible name of `<Recipe.ServingsSelect>` and `<Recipe.ServingsInput>`,
581
+ * unless they get an `aria-label` or `aria-labelledby`. Defaults to
582
+ * `'Servings'`.
583
+ *
584
+ * @see https://recipe-book.siraj.page/reference/react/provider/
585
+ */
305
586
  servings: string;
306
- /** Unit for the servings count: "1 serving", "4 servings". */
587
+ /**
588
+ * Unit for the servings count: "1 serving", "4 servings".
589
+ * `<Recipe.ServingsSelect>` words each option with it, for a recipe with
590
+ * `servings`. Defaults to `{ one: 'serving', other: 'servings' }`.
591
+ *
592
+ * @see https://recipe-book.siraj.page/reference/react/provider/
593
+ */
307
594
  servingUnit: {
308
595
  /** Follows 1 and a fraction below 1: "1 serving", "½ serving". */
309
596
  one: string;
310
597
  /** Follows decimals and any other number: "0.3 servings", "4 servings". */
311
598
  other: string;
312
599
  };
313
- /** Accessible name of the system toggle. */
600
+ /**
601
+ * Accessible name of `<Recipe.SystemToggle>`, unless it gets an
602
+ * `aria-label` or `aria-labelledby`. Defaults to `'Measurement system'`.
603
+ *
604
+ * @see https://recipe-book.siraj.page/reference/react/provider/
605
+ */
314
606
  system: string;
315
- /** Name of the metric system. */
607
+ /**
608
+ * Name of the metric system, shown by a `<Recipe.SystemOption>` for
609
+ * `'metric'` that has no children, or an empty `asChild` child. Defaults to
610
+ * `'Metric'`.
611
+ *
612
+ * @see https://recipe-book.siraj.page/reference/react/provider/
613
+ */
316
614
  metric: string;
317
- /** Name of the US system. */
615
+ /**
616
+ * Name of the US system, shown by a `<Recipe.SystemOption>` for `'us'` that
617
+ * has no children, or an empty `asChild` child. Defaults to `'US'`.
618
+ *
619
+ * @see https://recipe-book.siraj.page/reference/react/provider/
620
+ */
318
621
  us: string;
319
- /** Marker after a fan-oven temperature in step text: "160 °C fan". */
622
+ /**
623
+ * Marker after a fan-oven temperature in `<Recipe.StepText>`: "160 °C fan".
624
+ * An empty string leaves it out. Defaults to `'fan'`.
625
+ *
626
+ * @see https://recipe-book.siraj.page/reference/react/provider/
627
+ */
320
628
  fan: string;
321
- /** Marker after an optional ingredient, shown as is, punctuation included. */
629
+ /**
630
+ * Marker after an optional ingredient, shown as is, punctuation included.
631
+ * `<Recipe.IngredientOptional>` renders it, and the function from
632
+ * `useFormatIngredient()` returns it as `optional`. Defaults to
633
+ * `'(optional)'`.
634
+ *
635
+ * @see https://recipe-book.siraj.page/reference/react/provider/
636
+ */
322
637
  optional: string;
323
- /** Spoken between the ends of a range, "2 to 3 tbsp". Screen readers only. */
638
+ /**
639
+ * Spoken between the ends of a range, "2 to 3 tbsp". Screen readers only:
640
+ * `<Recipe.IngredientQuantity>` keeps the visible dash, "2–3 tbsp".
641
+ * Defaults to `'to'`.
642
+ *
643
+ * @see https://recipe-book.siraj.page/reference/react/provider/
644
+ */
324
645
  to: string;
325
646
  };
326
647
 
327
648
  /** The locale, labels, and starting system that `RecipeBookProvider` and `<Recipe.Root>` take. */
328
649
  type RecipeBookConfig = {
329
- /** BCP 47 locale for formatting numbers. Defaults to the outer provider's, then `'en-US'`. */
650
+ /**
651
+ * A language tag that `Intl` accepts, such as `'de-DE'`, for formatting
652
+ * numbers. With a tag it rejects, such as `'en_US'`, formatting a number
653
+ * throws `invalid_argument`.
654
+ *
655
+ * @defaultValue The outer provider's `locale`, then `'en-US'`.
656
+ *
657
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider
658
+ * @see https://recipe-book.siraj.page/reference/react/root/#root
659
+ */
330
660
  locale?: string | undefined;
331
- /** Overrides for built-in text. Unset keys keep the outer value. */
661
+ /**
662
+ * Built-in text to override. A key you leave out keeps the outer provider's
663
+ * value, then its English default. Pass an object that keeps its identity
664
+ * between renders: an equal but new one re-renders most parts.
665
+ *
666
+ * @see https://recipe-book.siraj.page/reference/react/provider/
667
+ * @see https://recipe-book.siraj.page/reference/react/root/
668
+ */
332
669
  labels?: RecipeLabelOverrides | undefined;
333
- /** Initial display system. Defaults to the outer provider's, then the system each recipe was written in, then `'metric'`. */
670
+ /**
671
+ * The measurement system a Root starts in, unless its `system` is
672
+ * controlled. Defaults to the outer provider's, then the system its recipe
673
+ * was written in, then `'metric'`. A value other than `'metric'` or `'us'`
674
+ * counts as missing.
675
+ *
676
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider
677
+ * @see https://recipe-book.siraj.page/reference/react/root/#root
678
+ */
334
679
  defaultSystem?: System | undefined;
335
680
  };
336
681
  /**
682
+ * Built-in text to override, for the `labels` prop of `RecipeBookProvider` and
683
+ * `<Recipe.Root>`.
684
+ *
337
685
  * Any keys of `RecipeLabels`. A value replaces the whole key, so `servingUnit`
338
686
  * needs both `one` and `other`.
687
+ *
688
+ * @example
689
+ * // At module scope, so it keeps its identity between renders.
690
+ * const labels = {
691
+ * servings: 'Portions',
692
+ * servingUnit: { one: 'portion', other: 'portions' },
693
+ * } satisfies Recipe.RecipeLabelOverrides
694
+ *
695
+ * <Recipe.Root recipe={recipe} labels={labels}>
696
+ * <Recipe.ServingsSelect />
697
+ * </Recipe.Root>
698
+ *
699
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipelabeloverrides
339
700
  */
340
701
  type RecipeLabelOverrides = {
341
702
  [Key in keyof RecipeLabels]?: RecipeLabels[Key] | undefined;
342
703
  };
343
- /** Defaults for every Root below it, plus `children`. */
704
+ /**
705
+ * Props of `RecipeBookProvider`: defaults for every Root below it, plus
706
+ * `children`.
707
+ *
708
+ * @example
709
+ * export function AppProvider(props: Recipe.RecipeBookProviderProps) {
710
+ * return <Recipe.RecipeBookProvider locale="en-GB" {...props} />
711
+ * }
712
+ *
713
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider
714
+ */
344
715
  type RecipeBookProviderProps = RecipeBookConfig & {
345
- /** The part of the app that uses these defaults. */
716
+ /**
717
+ * The part of the app that uses these defaults.
718
+ *
719
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider
720
+ */
346
721
  children?: ReactNode;
347
722
  };
348
723
  /**
349
724
  * App-wide defaults for every `<Recipe.Root>` below it. Takes only data, so it
350
725
  * can wrap a layout rendered as a Server Component. Nested providers override
351
726
  * the outer one key by key.
727
+ *
728
+ * @example
729
+ * // app/layout.tsx
730
+ * <Recipe.RecipeBookProvider defaultSystem="metric">
731
+ * {children}
732
+ * </Recipe.RecipeBookProvider>
733
+ *
734
+ * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider
352
735
  */
353
736
  declare function RecipeBookProvider({ children, ...config }: RecipeBookProviderProps): JSX.Element;
354
737
  /**
355
- * The state of the nearest `<Recipe.Root>`: the recipe, servings, and display
356
- * system, with their setters.
738
+ * The state of the nearest `<Recipe.Root>`: the recipe, servings, and
739
+ * measurement system, with their setters.
740
+ *
741
+ * @returns The Root's `RecipeState`: `recipe`, `servings`, `scale`, `system`,
742
+ * `canConvert`, `ingredients` and `steps` as the Root shows them, and the
743
+ * `setServings` and `setSystem` that change them.
357
744
  *
358
745
  * @throws {RecipeBookError} `missing_parent` outside a Root.
746
+ *
747
+ * @example
748
+ * function SystemSwitch() {
749
+ * const { system, setSystem, canConvert } = Recipe.useRecipe()
750
+ * if (!canConvert) return null
751
+ * return (
752
+ * <button onClick={() => setSystem(system === 'us' ? 'metric' : 'us')}>
753
+ * {system === 'us' ? 'Show metric' : 'Show US'}
754
+ * </button>
755
+ * )
756
+ * }
757
+ *
758
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#userecipe
359
759
  */
360
760
  declare function useRecipe(): RecipeState;
361
761
 
362
762
  /**
363
- * A union: a parsed `recipe`, or raw data with `parse`. To wrap `Root`,
364
- * intersect (`RecipeRootProps & { … }`) or destructure it, rather than
365
- * `Omit<RecipeRootProps, …>`, which doesn't type-check against a union.
763
+ * The props of `<Recipe.Root>`, a union: a parsed `recipe`, or raw data with
764
+ * `parse`. To wrap `Root`, intersect (`RecipeRootProps & { … }`) or
765
+ * destructure it, rather than `Omit<RecipeRootProps, …>`, which doesn't
766
+ * type-check against a union.
767
+ *
768
+ * @see https://recipe-book.siraj.page/reference/react/root/#root
769
+ * @see https://recipe-book.siraj.page/reference/react/root/#wrap-root
366
770
  */
367
771
  type RecipeRootProps = RecipeBookConfig & Omit<RecipeStateOptions, 'recipe' | 'defaultSystem'> & {
368
772
  /** The parts and components that read the recipe's state. */
369
773
  children?: ReactNode;
370
774
  } & ({
371
775
  /**
372
- * A parsed recipe. Call `parseRecipe` from `@recipe-book/core` on the
373
- * server, in a loader, or at build time, and pass `result.data`.
776
+ * A parsed recipe. Call `parseRecipe` from `@recipe-book/react/core`
777
+ * on the server, in a loader, or at build time, and pass
778
+ * `result.data`.
374
779
  */
375
780
  recipe: Recipe;
781
+ /** Only with recipe data to parse. A parsed recipe takes no `parse`. */
376
782
  parse?: undefined;
377
783
  /** Only with `parse`. A parsed recipe always renders. */
378
784
  fallback?: undefined;
@@ -381,14 +787,19 @@ type RecipeRootProps = RecipeBookConfig & Omit<RecipeStateOptions, 'recipe' | 'd
381
787
  recipe: unknown;
382
788
  /**
383
789
  * Parses `recipe` in the browser. Pass `parseRecipe` from
384
- * `@recipe-book/core`; only apps that do download the parser.
790
+ * `@recipe-book/react/core`; only apps that do download the parser.
385
791
  *
386
792
  * A function, so it can only be passed from a Client Component. Pass a
387
793
  * stable function such as `parseRecipe` itself: an inline arrow
388
794
  * parses again on every render.
389
795
  */
390
796
  parse: (input: unknown) => ParseResult<Recipe>;
391
- /** Rendered instead of `children` when `parse` rejects `recipe`. */
797
+ /**
798
+ * Rendered instead of `children` when `parse` rejects `recipe`.
799
+ *
800
+ * @defaultValue `null`
801
+ * @see https://recipe-book.siraj.page/reference/react/root/#parse-in-the-browser
802
+ */
392
803
  fallback?: ReactNode;
393
804
  });
394
805
  /**
@@ -402,16 +813,37 @@ type RecipeRootProps = RecipeBookConfig & Omit<RecipeStateOptions, 'recipe' | 'd
402
813
  *
403
814
  * @throws {RecipeBookError} `invalid_argument` when `recipe` isn't a parsed
404
815
  * recipe and there is no `parse`.
816
+ *
817
+ * @example
818
+ * <Recipe.Root recipe={recipe} defaultServings={8}>
819
+ * <Recipe.Image />
820
+ * <Recipe.Ingredients />
821
+ * <Recipe.Steps />
822
+ * </Recipe.Root>
823
+ *
824
+ * @see https://recipe-book.siraj.page/reference/react/root/
405
825
  */
406
826
  declare function Root({ recipe, parse, fallback, children, ...options }: RecipeRootProps): JSX.Element;
407
827
 
408
- /** Attributes for the `<select>`, plus the `options` to offer. */
409
- type RecipeServingsSelectProps = Omit<ComponentPropsWithoutRef<'select'>, 'value' | 'defaultValue' | 'multiple' | 'children'> & {
828
+ /**
829
+ * The props of `<Recipe.ServingsSelect>`: the `<select>`'s attributes, plus
830
+ * the `options` to offer. It sets the value and the options itself, so it
831
+ * doesn't take `value`, `defaultValue`, `multiple`, `children` or
832
+ * `dangerouslySetInnerHTML`.
833
+ *
834
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect
835
+ */
836
+ type RecipeServingsSelectProps = Omit<ComponentPropsWithoutRef<'select'>, 'value' | 'defaultValue' | 'multiple' | 'children' | 'dangerouslySetInnerHTML'> & {
410
837
  /**
411
- * Servings to offer, shown in ascending order. Defaults to ½×, 1×, 2×, and
412
- * 3× the servings the recipe scales from (its servings amount, else its
413
- * yield amount, else 1), each rounded to a whole number of at least 1.
414
- * Values the recipe can't be scaled to are left out.
838
+ * Servings to offer, shown in ascending order. A number outside the
839
+ * servings window is left out.
840
+ *
841
+ * @defaultValue ½×, 1×, 2×, and 3× the recipe's scaling base (its servings
842
+ * amount, else its yield amount, else 1), each rounded to a whole number of
843
+ * at least 1.
844
+ *
845
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect
846
+ * @see https://recipe-book.siraj.page/reference/react/root/#servings-window
415
847
  */
416
848
  options?: readonly number[] | undefined;
417
849
  };
@@ -428,18 +860,55 @@ type RecipeServingsSelectProps = Omit<ComponentPropsWithoutRef<'select'>, 'value
428
860
  * It sets `autoComplete="off"`, so when going back reloads the page, the
429
861
  * browser doesn't restore an earlier choice over the Root's servings. An
430
862
  * `autoComplete` you pass wins.
863
+ *
864
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`, and
865
+ * `invalid_argument` when the Root's `locale` isn't a language tag that
866
+ * `Intl` accepts, such as `'en_US'`.
867
+ *
868
+ * @example
869
+ * <Recipe.Root recipe={recipe}>
870
+ * <Recipe.ServingsSelect options={[2, 4, 6, 8]} />
871
+ * </Recipe.Root>
872
+ *
873
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect
431
874
  */
432
875
  declare const ServingsSelect: ForwardRefExoticComponent<RecipeServingsSelectProps & RefAttributes<HTMLSelectElement>>;
433
- /** Attributes for the `<input type="number">`, except its value, which follows the Root's servings. */
876
+ /**
877
+ * The props of `<Recipe.ServingsInput>`: the `<input type="number">`'s
878
+ * attributes, with `min`, `max` and `step` as numbers. It sets the type and
879
+ * the value, which follows the Root's servings, so it doesn't take `type`,
880
+ * `value` or `defaultValue`.
881
+ *
882
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput
883
+ */
434
884
  type RecipeServingsInputProps = Omit<ComponentPropsWithoutRef<'input'>, 'type' | 'value' | 'defaultValue' | 'min' | 'max' | 'step'> & {
435
- /** The fewest servings that can be entered. Defaults to 1. */
885
+ /**
886
+ * The fewest servings that can be entered, set as the `min` attribute. The
887
+ * `step` grid counts from it.
888
+ *
889
+ * @defaultValue `1`
890
+ *
891
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput
892
+ */
436
893
  min?: number | undefined;
437
- /** The most servings that can be entered. */
894
+ /**
895
+ * The most servings that can be entered, set as the `max` attribute.
896
+ * Without it, there's no `max` attribute, and the input accepts numbers up
897
+ * to the top of the servings window.
898
+ *
899
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput
900
+ * @see https://recipe-book.siraj.page/reference/react/root/#servings-window
901
+ */
438
902
  max?: number | undefined;
439
903
  /**
440
904
  * How far the arrows move the value, and the grid, counted from `min`, that
441
- * an entered value must be on. Defaults to 1. `'any'` allows any value. A
442
- * `step` that isn't a number above 0 counts as 1, as in the browser.
905
+ * an entered value must be on. `'any'` allows any value. A `step` that
906
+ * isn't a number above 0 counts as 1, as in the browser.
907
+ *
908
+ * @defaultValue `1`, the browser's step for an input without a `step`
909
+ * attribute
910
+ *
911
+ * @see https://recipe-book.siraj.page/reference/react/servings/#the-step-grid
443
912
  */
444
913
  step?: number | 'any' | undefined;
445
914
  };
@@ -451,12 +920,28 @@ type RecipeServingsInputProps = Omit<ComponentPropsWithoutRef<'input'>, 'type' |
451
920
  * range, so typing them logs no warning.
452
921
  *
453
922
  * Its accessible name and `autoComplete` follow the same rules as
454
- * `<Recipe.ServingsSelect>`.
923
+ * `<Recipe.ServingsSelect>`. `inputMode` defaults to `'numeric'` when `min`
924
+ * and the step are whole numbers, as with the defaults of 1, and to
925
+ * `'decimal'` otherwise, including with `step="any"`.
926
+ *
927
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
928
+ *
929
+ * @example
930
+ * <Recipe.Root recipe={recipe}>
931
+ * <Recipe.ServingsInput max={48} />
932
+ * </Recipe.Root>
933
+ *
934
+ * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput
455
935
  */
456
936
  declare const ServingsInput: ForwardRefExoticComponent<RecipeServingsInputProps & RefAttributes<HTMLInputElement>>;
457
937
 
458
- /** Attributes for the `<span>`; it renders the step's text, so no `children`. */
459
- type RecipeStepTextProps = Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
938
+ /**
939
+ * Attributes for the `<span>`; it renders the step's text, so no `children` or
940
+ * `dangerouslySetInnerHTML`.
941
+ *
942
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steptext
943
+ */
944
+ type RecipeStepTextProps = Omit<ComponentPropsWithoutRef<'span'>, 'children' | 'dangerouslySetInnerHTML'>;
460
945
  /**
461
946
  * The nearest `<Recipe.Step>`'s text, with each temperature shown in Root's
462
947
  * display system: °C for metric, °F for US. A reading the author wrote in that
@@ -467,64 +952,124 @@ type RecipeStepTextProps = Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
467
952
  * mark that follows a temperature as another way to give the same setting, as
468
953
  * in `190C/170C fan/gas 5` or `200°C (gas mark 6)`, is left out. Everything
469
954
  * else, including a gas mark on its own or before a temperature, is shown as
470
- * authored. Each temperature is a `<span data-recipe-temperature>`.
955
+ * authored. Each temperature is a `<span data-recipe-temperature>`. When
956
+ * `segmentStepText` pairs a conventional setting with a fan one, the
957
+ * conventional one shows first and the fan one after a slash, as in
958
+ * `200 °C / 180 °C fan`.
471
959
  *
472
960
  * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Step>`.
961
+ * @throws {RecipeBookError} `invalid_argument` for a step with a temperature
962
+ * when Root's `locale` isn't a language tag that `Intl` accepts, such as
963
+ * `'en_US'`.
473
964
  *
474
965
  * @example
475
966
  * <Recipe.Step item={step}>
476
967
  * <Recipe.StepName /> <Recipe.StepText />
477
968
  * </Recipe.Step>
969
+ *
970
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steptext
478
971
  */
479
972
  declare const StepText: ForwardRefExoticComponent<RecipeStepTextProps & RefAttributes<HTMLSpanElement>>;
480
973
 
481
- /** Attributes for the wrapping `<div>`, plus `headingLevel`; `children` renders each section. */
482
- type RecipeStepsProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
974
+ /**
975
+ * Attributes for the wrapping `<div>` other than `dangerouslySetInnerHTML`,
976
+ * plus `headingLevel`; `children` renders each section.
977
+ *
978
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steps
979
+ */
980
+ type RecipeStepsProps = Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'dangerouslySetInnerHTML'> & {
483
981
  /**
484
982
  * Heading level of section titles in the default rendering. Defaults to 3,
485
983
  * for steps under an `<h2>` such as "Method".
984
+ *
985
+ * @defaultValue `3`
986
+ * @see https://recipe-book.siraj.page/guides/make-a-recipe-accessible/#set-heading-levels
486
987
  */
487
988
  headingLevel?: RecipeHeadingLevel | undefined;
488
989
  /**
489
990
  * Renders each section instead of the default. Each result is keyed for
490
991
  * you, so return one element or a fragment; an array's items need their own
491
992
  * keys, as anywhere in React.
993
+ *
994
+ * @defaultValue A `<section>` named by the section's heading, or a `<div>`
995
+ * for an untitled section, around a `<Recipe.StepList>` of its steps.
996
+ * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-sections
492
997
  */
493
998
  children?: ((section: RecipeSection<StepItem>) => ReactNode) | undefined;
494
999
  };
495
1000
  /**
496
1001
  * The recipe's steps, one block per section. A titled section renders as a
497
1002
  * `<section>` named by its heading, then a `<Recipe.StepList>`.
1003
+ *
1004
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
1005
+ *
1006
+ * @example
1007
+ * <Recipe.Root recipe={recipe}>
1008
+ * <h2>Method</h2>
1009
+ * <Recipe.Steps />
1010
+ * </Recipe.Root>
1011
+ *
1012
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steps
498
1013
  */
499
1014
  declare const Steps: ForwardRefExoticComponent<RecipeStepsProps & RefAttributes<HTMLDivElement>>;
500
- /** Attributes for the `<ol>`, plus the `section` to list; `children` renders each step. */
501
- type RecipeStepListProps = Omit<ComponentPropsWithoutRef<'ol'>, 'children'> & {
1015
+ /**
1016
+ * Attributes for the `<ol>` other than `dangerouslySetInnerHTML`, plus the
1017
+ * `section` to list; `children` renders each step.
1018
+ *
1019
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steplist
1020
+ */
1021
+ type RecipeStepListProps = Omit<ComponentPropsWithoutRef<'ol'>, 'children' | 'dangerouslySetInnerHTML'> & {
502
1022
  /** The section to list. Defaults to every step in the recipe. */
503
1023
  section?: RecipeSection<StepItem> | undefined;
504
1024
  /**
505
1025
  * Renders each step instead of `<Recipe.Step>`. Each result is keyed for
506
1026
  * you, so return one element or a fragment; an array's items need their own
507
1027
  * keys, as anywhere in React.
1028
+ *
1029
+ * @defaultValue `(step) => <Recipe.Step item={step} />`
1030
+ * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-steps
508
1031
  */
509
1032
  children?: ((step: StepItem) => ReactNode) | undefined;
510
1033
  };
511
1034
  /**
512
1035
  * An ordered list of steps. `start` defaults to the first step's number, so
513
1036
  * numbering continues across sections.
1037
+ *
1038
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
1039
+ *
1040
+ * @example
1041
+ * <Recipe.StepList>
1042
+ * {(step) => (
1043
+ * <Recipe.Step item={step}>
1044
+ * <Recipe.StepName /> <Recipe.StepText />
1045
+ * </Recipe.Step>
1046
+ * )}
1047
+ * </Recipe.StepList>
1048
+ *
1049
+ * @see https://recipe-book.siraj.page/reference/react/steps/#steplist
514
1050
  */
515
1051
  declare const StepList: ForwardRefExoticComponent<RecipeStepListProps & RefAttributes<HTMLOListElement>>;
516
- /** Attributes for the `<li>`, plus the `item` to render and `asChild`. */
517
- type RecipeStepProps = ComponentPropsWithoutRef<'li'> & {
1052
+ /**
1053
+ * Attributes for the `<li>` other than `dangerouslySetInnerHTML`, plus the
1054
+ * `item` to render and `asChild`.
1055
+ *
1056
+ * @see https://recipe-book.siraj.page/reference/react/steps/#step
1057
+ */
1058
+ type RecipeStepProps = Omit<ComponentPropsWithoutRef<'li'>, 'dangerouslySetInnerHTML'> & {
518
1059
  /** The step to render, with its number. */
519
1060
  item: StepItem;
520
1061
  /**
521
1062
  * Renders the step as its one element child, such as `<motion.li layout />`,
522
- * instead of an `<li>`. A prop on the child wins, except that the step's
1063
+ * instead of an `<li>`. Render an `<li>` or a component that renders one, so
1064
+ * the list keeps its items. A prop on the child wins, except that the step's
523
1065
  * `tabIndex` wins, `className`s join, `style` merges key by key with the
524
1066
  * child winning, both event handlers run (the child's first), and both refs
525
1067
  * are set. The child's own children replace the step's, so an empty child
526
1068
  * gets the name and text. With anything but one element child, it renders
527
1069
  * its own `<li>`, with a warning in development.
1070
+ *
1071
+ * @defaultValue `false`
1072
+ * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-element
528
1073
  */
529
1074
  asChild?: boolean | undefined;
530
1075
  };
@@ -538,24 +1083,42 @@ type RecipeStepProps = ComponentPropsWithoutRef<'li'> & {
538
1083
  * <Recipe.Step item={step}>
539
1084
  * <Recipe.StepName /> <Recipe.StepText />
540
1085
  * </Recipe.Step>
1086
+ *
1087
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
1088
+ *
1089
+ * @see https://recipe-book.siraj.page/reference/react/steps/#step
541
1090
  */
542
1091
  declare const Step: ForwardRefExoticComponent<RecipeStepProps & RefAttributes<HTMLLIElement>>;
543
- /** Attributes for the `<b>`; it renders the step's name, so no `children`. */
544
- type RecipeStepNameProps = Omit<ComponentPropsWithoutRef<'b'>, 'children'>;
1092
+ /**
1093
+ * Attributes for the `<b>`; it renders the step's name, so no `children` or
1094
+ * `dangerouslySetInnerHTML`.
1095
+ *
1096
+ * @see https://recipe-book.siraj.page/reference/react/steps/#stepname
1097
+ */
1098
+ type RecipeStepNameProps = Omit<ComponentPropsWithoutRef<'b'>, 'children' | 'dangerouslySetInnerHTML'>;
545
1099
  /**
546
1100
  * The nearest `<Recipe.Step>`'s name in a `<b data-recipe-name>`, or nothing
547
1101
  * when the step has none.
548
1102
  *
549
1103
  * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Step>`.
1104
+ *
1105
+ * @see https://recipe-book.siraj.page/reference/react/steps/#stepname
550
1106
  */
551
1107
  declare const StepName: ForwardRefExoticComponent<RecipeStepNameProps & RefAttributes<HTMLElement>>;
552
1108
 
553
1109
  /**
554
- * Attributes for the radio group's `<div>`, except the `role` it sets, plus
555
- * `asChild`.
556
- * The group sets `aria-disabled` itself.
1110
+ * The props of `<Recipe.SystemToggle>`: the radio group's `<div>` attributes,
1111
+ * plus `asChild`. It sets `role` and renders its own content, so it doesn't
1112
+ * take `role` or `dangerouslySetInnerHTML`.
1113
+ *
1114
+ * The group sets `aria-disabled` and its data attributes at runtime, over any
1115
+ * you pass, so `aria-disabled` is there only while the toggle is disabled. An
1116
+ * `asChild` child's own `role`, `aria-disabled` and data attributes still
1117
+ * win.
1118
+ *
1119
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemtoggle
557
1120
  */
558
- type RecipeSystemToggleProps = Omit<ComponentPropsWithoutRef<'div'>, 'role'> & {
1121
+ type RecipeSystemToggleProps = Omit<ComponentPropsWithoutRef<'div'>, 'role' | 'dangerouslySetInnerHTML'> & {
559
1122
  /**
560
1123
  * Renders the radio group as its one element child, such as
561
1124
  * `<motion.div layout />`, instead of a `<div>`. A prop on the child wins,
@@ -565,43 +1128,106 @@ type RecipeSystemToggleProps = Omit<ComponentPropsWithoutRef<'div'>, 'role'> & {
565
1128
  * group's, so an empty child gets the metric and US options. With anything
566
1129
  * but one element child, it renders its own `<div>`, with a warning in
567
1130
  * development.
1131
+ *
1132
+ * @defaultValue `false`
1133
+ *
1134
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#render-your-own-elements
568
1135
  */
569
1136
  asChild?: boolean | undefined;
570
1137
  };
571
1138
  /**
572
- * Switches the display system. A radio group whose default options are
573
- * metric and US. Disabled when there's nothing to convert: no ingredient has a
574
- * unit that belongs to only one system, and no `Recipe.StepText` in the Root
575
- * shows a temperature. A `StepText` counts once it mounts, so for a recipe
576
- * whose only temperatures are in its steps, the toggle enables after
1139
+ * Switches the Root's measurement system. A radio group whose default options
1140
+ * are metric and US. Disabled when there's nothing to convert: no ingredient
1141
+ * has a unit that belongs to only one system, and no `Recipe.StepText` in the
1142
+ * Root shows a temperature. A `StepText` counts once it mounts, so for a
1143
+ * recipe whose only temperatures are in its steps, the toggle enables after
577
1144
  * hydration.
1145
+ *
1146
+ * Its accessible name defaults to the `system` label, unless you pass
1147
+ * `aria-label` or `aria-labelledby`.
1148
+ *
1149
+ * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.
1150
+ *
1151
+ * @example
1152
+ * <Recipe.Root recipe={recipe}>
1153
+ * <Recipe.SystemToggle className="units" />
1154
+ * </Recipe.Root>
1155
+ *
1156
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemtoggle
578
1157
  */
579
1158
  declare const SystemToggle: ForwardRefExoticComponent<RecipeSystemToggleProps & RefAttributes<HTMLDivElement>>;
580
1159
  /**
581
- * Attributes for the radio's `<button>`, except the `role` and `tabIndex` it
582
- * sets, with `value` the system it selects, plus `asChild`.
583
- * The option sets `aria-checked` itself.
1160
+ * The props of `<Recipe.SystemOption>`: the radio's `<button>` attributes,
1161
+ * with `value` the system it selects, plus `asChild`. It sets `role` and
1162
+ * `tabIndex` and renders its own content, so it doesn't take them or
1163
+ * `dangerouslySetInnerHTML`.
1164
+ *
1165
+ * The option sets `aria-checked` and its data attributes at runtime, over any
1166
+ * you pass. An `asChild` child's own `role`, `aria-checked` and data
1167
+ * attributes still win.
1168
+ *
1169
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption
584
1170
  */
585
- type RecipeSystemOptionProps = Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'role' | 'tabIndex'> & {
586
- /** The system this option selects. */
1171
+ type RecipeSystemOptionProps = Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'role' | 'tabIndex' | 'dangerouslySetInnerHTML'> & {
1172
+ /**
1173
+ * The system this option selects: `'metric'` or `'us'`.
1174
+ *
1175
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption
1176
+ */
587
1177
  value: System;
1178
+ /**
1179
+ * The button's `autocomplete` attribute. Off by default, so when going back
1180
+ * reloads the page, Firefox doesn't re-enable an option that the server
1181
+ * rendered disabled and the page enabled later.
1182
+ *
1183
+ * @defaultValue `'off'`
1184
+ *
1185
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption
1186
+ */
1187
+ autoComplete?: string | undefined;
588
1188
  /**
589
1189
  * Renders the radio as its one element child, such as
590
- * `<motion.button layout />`, instead of a `<button>`. A prop on the child
591
- * wins, except that the option's `tabIndex` wins, `className`s join, `style`
592
- * merges key by key with the child winning, both event handlers run (the
593
- * child's first), and both refs are set. The option sets `tabIndex` to keep
594
- * one radio in the tab order once React hydrates the page; before that,
595
- * every enabled checked option is in it. The child's own children replace
596
- * the option's, so an empty child gets the system's label. With anything but
597
- * one element child, it renders its own `<button>`, with a warning in
598
- * development.
1190
+ * `<motion.button layout />`, instead of a `<button>`. Render a `<button>` or
1191
+ * a component that renders one, so Space and Enter check it, and a disabled
1192
+ * option reads as disabled to screen readers and doesn't take focus on a
1193
+ * click. A prop on the child wins, except that the option's `tabIndex` wins,
1194
+ * `className`s join, `style` merges key by key with the child winning, both
1195
+ * event handlers run (the child's first), and both refs are set. The option
1196
+ * sets `tabIndex` to keep one radio in the tab order once React hydrates the
1197
+ * page; before that, every enabled checked option is in it. The child's own
1198
+ * children replace the option's, so an empty child gets the system's label.
1199
+ * With anything but one element child, it renders its own `<button>`, with a
1200
+ * warning in development.
1201
+ *
1202
+ * @defaultValue `false`
1203
+ *
1204
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#render-your-own-elements
599
1205
  */
600
1206
  asChild?: boolean | undefined;
601
1207
  };
602
1208
  /**
603
- * One option of a `<Recipe.SystemToggle>`. Children default to the system's
604
- * label.
1209
+ * One option of a `<Recipe.SystemToggle>`. Checked when its `value` is the
1210
+ * Root's system; a click sets the Root's system to `value`. Children default
1211
+ * to the system's label. Its `type` defaults to `'button'`, so it doesn't
1212
+ * submit a form. It's disabled while the toggle is, even with
1213
+ * `disabled={false}`.
1214
+ *
1215
+ * It sets `autoComplete="off"`, so when going back reloads the page, Firefox
1216
+ * doesn't re-enable an option that the server rendered disabled and the page
1217
+ * enabled later. An `autoComplete` you pass wins.
1218
+ *
1219
+ * @throws {RecipeBookError} `missing_parent` outside a
1220
+ * `<Recipe.SystemToggle>`.
1221
+ *
1222
+ * @example
1223
+ * <Recipe.SystemToggle>
1224
+ * <Recipe.SystemOption value="us">Cups and spoons</Recipe.SystemOption>
1225
+ * <Recipe.SystemOption value="metric">
1226
+ * Grams and milliliters
1227
+ * </Recipe.SystemOption>
1228
+ * </Recipe.SystemToggle>
1229
+ *
1230
+ * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption
605
1231
  */
606
1232
  declare const SystemOption: ForwardRefExoticComponent<RecipeSystemOptionProps & RefAttributes<HTMLButtonElement>>;
607
1233
 
@@ -618,10 +1244,17 @@ type FormattedIngredientItem = FormattedIngredient & {
618
1244
  * renderers without a DOM. Returns the same function until the locale or
619
1245
  * `labels.optional` changes.
620
1246
  *
621
- * Without a Root, call `formatIngredient` from `@recipe-book/core`.
1247
+ * Without a Root, call `formatIngredient` from `@recipe-book/react/core`.
622
1248
  *
623
1249
  * @throws {RecipeBookError} `missing_parent` outside a Root.
624
1250
  *
1251
+ * @returns A function that formats one of the state's ingredient items into
1252
+ * the pieces `<Recipe.Ingredient>` renders. It throws `invalid_argument`
1253
+ * when Root's `locale` isn't a language tag that `Intl` accepts, such as
1254
+ * `'en_US'`, the item isn't `{ ingredient, quantity? }`, or it has an amount
1255
+ * that `formatQuantity` rejects, and `unknown_unit` when the item's unit
1256
+ * isn't a unit ID.
1257
+ *
625
1258
  * @example
626
1259
  * function CopyIngredients() {
627
1260
  * const { ingredients } = Recipe.useRecipe()
@@ -638,6 +1271,8 @@ type FormattedIngredientItem = FormattedIngredient & {
638
1271
  * </button>
639
1272
  * )
640
1273
  * }
1274
+ *
1275
+ * @see https://recipe-book.siraj.page/reference/react/hooks/#useformatingredient
641
1276
  */
642
1277
  declare function useFormatIngredient(): (item: IngredientItem) => FormattedIngredientItem;
643
1278