@recipe-book/react 0.0.3 → 0.1.1

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.
Files changed (167) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -15
  4. package/core/package.json +5 -0
  5. package/core/schema-org/package.json +5 -0
  6. package/dist/core/schema-org.cjs +25 -0
  7. package/dist/core/schema-org.cjs.map +1 -0
  8. package/dist/core/schema-org.d.cts +1 -0
  9. package/dist/core/schema-org.d.ts +1 -0
  10. package/dist/core/schema-org.js +3 -0
  11. package/dist/core/schema-org.js.map +1 -0
  12. package/dist/core.cjs +25 -0
  13. package/dist/core.cjs.map +1 -0
  14. package/dist/core.d.cts +1 -0
  15. package/dist/core.d.ts +1 -0
  16. package/dist/core.js +3 -0
  17. package/dist/core.js.map +1 -0
  18. package/dist/index.cjs +1224 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.cts +1276 -0
  21. package/dist/index.d.ts +1276 -10
  22. package/dist/index.js +1207 -2
  23. package/dist/index.js.map +1 -0
  24. package/package.json +71 -15
  25. package/dist/chunk-2S2Z4HLL.mjs +0 -46
  26. package/dist/chunk-2VMRVR3X.mjs +0 -1
  27. package/dist/chunk-36H6LM2B.mjs +0 -14
  28. package/dist/chunk-4IWVZEXX.mjs +0 -20
  29. package/dist/chunk-4XBZKTOL.mjs +0 -1
  30. package/dist/chunk-6AGILC25.mjs +0 -20
  31. package/dist/chunk-6AXGEB5P.mjs +0 -14
  32. package/dist/chunk-6JEDN4VR.mjs +0 -20
  33. package/dist/chunk-6KLLMLNF.mjs +0 -33
  34. package/dist/chunk-6LTLY5K7.mjs +0 -20
  35. package/dist/chunk-6RA4EVIO.mjs +0 -46
  36. package/dist/chunk-75DF3E6L.mjs +0 -50
  37. package/dist/chunk-7BWMULSB.mjs +0 -55
  38. package/dist/chunk-7PPB3PM6.mjs +0 -40
  39. package/dist/chunk-7SBP7DC5.mjs +0 -42
  40. package/dist/chunk-7XJBP24U.mjs +0 -20
  41. package/dist/chunk-A5JAKCMG.mjs +0 -44
  42. package/dist/chunk-ATOAYKI3.mjs +0 -26
  43. package/dist/chunk-B5IXKKFC.mjs +0 -38
  44. package/dist/chunk-BEMMFA52.mjs +0 -49
  45. package/dist/chunk-BOG5DA6M.mjs +0 -38
  46. package/dist/chunk-BW4DYFBO.mjs +0 -36
  47. package/dist/chunk-CDQFOSWR.mjs +0 -34
  48. package/dist/chunk-CRQVP6PW.mjs +0 -20
  49. package/dist/chunk-CY27OHOG.mjs +0 -1
  50. package/dist/chunk-DACFJWGN.mjs +0 -14
  51. package/dist/chunk-DE5GUZKO.mjs +0 -46
  52. package/dist/chunk-DNZAFS5G.mjs +0 -48
  53. package/dist/chunk-DS3O5PAR.mjs +0 -20
  54. package/dist/chunk-ENGJXHYU.mjs +0 -42
  55. package/dist/chunk-FIFGRJKD.mjs +0 -26
  56. package/dist/chunk-FWOMIZEF.mjs +0 -46
  57. package/dist/chunk-G7XD4VBW.mjs +0 -44
  58. package/dist/chunk-GBU6MVZL.mjs +0 -14
  59. package/dist/chunk-GM5F7IUT.mjs +0 -2
  60. package/dist/chunk-GSGRXRJP.mjs +0 -38
  61. package/dist/chunk-GZRNU24M.mjs +0 -46
  62. package/dist/chunk-HNDXCSZY.mjs +0 -44
  63. package/dist/chunk-HXTUDCO2.mjs +0 -49
  64. package/dist/chunk-I5TR6PEA.mjs +0 -0
  65. package/dist/chunk-IXRYSEMS.mjs +0 -30
  66. package/dist/chunk-J5Q2Z2JG.mjs +0 -38
  67. package/dist/chunk-JBAAWEV6.mjs +0 -1
  68. package/dist/chunk-JCPPNN26.mjs +0 -44
  69. package/dist/chunk-JR3OTSZB.mjs +0 -32
  70. package/dist/chunk-JWS5RTU3.mjs +0 -46
  71. package/dist/chunk-K6EZ773Q.mjs +0 -26
  72. package/dist/chunk-KNXMYQVO.mjs +0 -36
  73. package/dist/chunk-KRUZ7OA7.mjs +0 -44
  74. package/dist/chunk-KXCIJBR6.mjs +0 -14
  75. package/dist/chunk-M5D3UUZF.mjs +0 -19
  76. package/dist/chunk-MASAOP7L.mjs +0 -55
  77. package/dist/chunk-MGBEDCLT.mjs +0 -34
  78. package/dist/chunk-MKBCBPVR.mjs +0 -53
  79. package/dist/chunk-N53TONLF.mjs +0 -39
  80. package/dist/chunk-NYDGFRPM.mjs +0 -46
  81. package/dist/chunk-OPOABKD6.mjs +0 -23
  82. package/dist/chunk-OX6ITS5C.mjs +0 -20
  83. package/dist/chunk-PAAVW47I.mjs +0 -50
  84. package/dist/chunk-PAF5HSSV.mjs +0 -53
  85. package/dist/chunk-PBENQR7Y.mjs +0 -1
  86. package/dist/chunk-PH3LQIHZ.mjs +0 -26
  87. package/dist/chunk-PIB3RAOO.mjs +0 -24
  88. package/dist/chunk-PIXLJD7Y.mjs +0 -37
  89. package/dist/chunk-PTS3BZHK.mjs +0 -1
  90. package/dist/chunk-Q6I5J3IJ.mjs +0 -1
  91. package/dist/chunk-QOCKR2HO.mjs +0 -1
  92. package/dist/chunk-QOZCSS3B.mjs +0 -44
  93. package/dist/chunk-QSFPUODQ.mjs +0 -34
  94. package/dist/chunk-RY7QUBJI.mjs +0 -34
  95. package/dist/chunk-RZJRUG2I.mjs +0 -55
  96. package/dist/chunk-S3GGSQB5.mjs +0 -1
  97. package/dist/chunk-S3HRT5Z5.mjs +0 -14
  98. package/dist/chunk-SB7HBCCZ.mjs +0 -49
  99. package/dist/chunk-SEXTT3NJ.mjs +0 -25
  100. package/dist/chunk-SKEQCOPX.mjs +0 -43
  101. package/dist/chunk-TLBRVWD2.mjs +0 -1
  102. package/dist/chunk-TOOCHDUY.mjs +0 -36
  103. package/dist/chunk-TSKANLT4.mjs +0 -37
  104. package/dist/chunk-UAMZEZUI.mjs +0 -36
  105. package/dist/chunk-UQJ4XNWN.mjs +0 -26
  106. package/dist/chunk-VDSUUXCH.mjs +0 -34
  107. package/dist/chunk-VO7RY2ZK.mjs +0 -44
  108. package/dist/chunk-WJKDFBJ2.mjs +0 -34
  109. package/dist/chunk-WTC7PY7U.mjs +0 -54
  110. package/dist/chunk-WXDV7CMB.mjs +0 -14
  111. package/dist/chunk-X5FG3X6T.mjs +0 -1
  112. package/dist/chunk-X66DY4AZ.mjs +0 -1
  113. package/dist/chunk-XXSJXKWQ.mjs +0 -44
  114. package/dist/chunk-YZMVAQQG.mjs +0 -1
  115. package/dist/chunk-ZCXPZU7W.mjs +0 -20
  116. package/dist/chunk-ZJ4PNVYO.mjs +0 -52
  117. package/dist/chunk-ZU4QJLEY.mjs +0 -53
  118. package/dist/components/ingredients/ingredients-list.d.mts +0 -13
  119. package/dist/components/ingredients/ingredients-list.d.ts +0 -13
  120. package/dist/components/ingredients/ingredients-list.js +0 -2
  121. package/dist/components/ingredients/ingredients-list.mjs +0 -1
  122. package/dist/components/instructions/instruction-list.d.mts +0 -13
  123. package/dist/components/instructions/instruction-list.d.ts +0 -13
  124. package/dist/components/instructions/instruction-list.js +0 -1
  125. package/dist/components/instructions/instruction-list.mjs +0 -1
  126. package/dist/components/layouts/layout-default.d.mts +0 -7
  127. package/dist/components/layouts/layout-default.d.ts +0 -7
  128. package/dist/components/layouts/layout-default.js +0 -1
  129. package/dist/components/layouts/layout-default.mjs +0 -1
  130. package/dist/components/layouts/layout-types.d.mts +0 -8
  131. package/dist/components/layouts/layout-types.d.ts +0 -8
  132. package/dist/components/layouts/layout-types.js +0 -1
  133. package/dist/components/layouts/layout-types.mjs +0 -0
  134. package/dist/components/measurement-select.d.mts +0 -13
  135. package/dist/components/measurement-select.d.ts +0 -13
  136. package/dist/components/measurement-select.js +0 -1
  137. package/dist/components/measurement-select.mjs +0 -1
  138. package/dist/components/root.d.mts +0 -13
  139. package/dist/components/root.d.ts +0 -13
  140. package/dist/components/root.js +0 -1
  141. package/dist/components/root.mjs +0 -1
  142. package/dist/components/servings-select.d.mts +0 -11
  143. package/dist/components/servings-select.d.ts +0 -11
  144. package/dist/components/servings-select.js +0 -1
  145. package/dist/components/servings-select.mjs +0 -1
  146. package/dist/components/thumbnail.d.mts +0 -18
  147. package/dist/components/thumbnail.d.ts +0 -18
  148. package/dist/components/thumbnail.js +0 -1
  149. package/dist/components/thumbnail.mjs +0 -1
  150. package/dist/global-context.d.mts +0 -29
  151. package/dist/global-context.d.ts +0 -29
  152. package/dist/global-context.js +0 -1
  153. package/dist/global-context.mjs +0 -1
  154. package/dist/hooks/use-controllable.d.mts +0 -15
  155. package/dist/hooks/use-controllable.d.ts +0 -15
  156. package/dist/hooks/use-controllable.js +0 -1
  157. package/dist/hooks/use-controllable.mjs +0 -1
  158. package/dist/index.d.mts +0 -10
  159. package/dist/index.mjs +0 -1
  160. package/dist/recipe-context.d.mts +0 -29
  161. package/dist/recipe-context.d.ts +0 -29
  162. package/dist/recipe-context.js +0 -1
  163. package/dist/recipe-context.mjs +0 -1
  164. package/dist/types-from-core.d.mts +0 -1
  165. package/dist/types-from-core.d.ts +0 -1
  166. package/dist/types-from-core.js +0 -1
  167. package/dist/types-from-core.mjs +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/labels.ts","../src/react.ts","../src/state/use-recipe-state.ts","../src/is-parsed-recipe.ts","../src/quote.ts","../src/state/use-controllable-state.ts","../src/parts/image.tsx","../src/parts/ingredients.tsx","../src/slot.tsx","../src/use-format-ingredient.ts","../src/parts/sections.tsx","../src/parts/json-ld.tsx","../src/parts/root.tsx","../src/parts/servings.tsx","../src/compose-event-handlers.ts","../src/parts/step-text.tsx","../src/parts/steps.tsx","../src/parts/system-toggle.tsx"],"sourcesContent":["// Named exports only: consumers write `import * as Recipe`. A namespace export\n// would keep every part in every import and can't be dotted into from a Server\n// Component.\n// Each part is exported twice (design §6.1): unprefixed for `Recipe.Root`, and\n// prefixed for named imports that auto-import finds without a clash. Types take\n// the prefix only, so `Recipe.` completions list parts. Nothing from core is\n// re-exported (§6.7).\nexport {\n Image,\n Image as RecipeImage,\n type RecipeImageProps,\n} from './parts/image'\nexport {\n Ingredient,\n Ingredient as RecipeIngredient,\n IngredientList,\n IngredientList as RecipeIngredientList,\n IngredientName,\n IngredientName as RecipeIngredientName,\n IngredientNote,\n IngredientNote as RecipeIngredientNote,\n IngredientOptional,\n IngredientOptional as RecipeIngredientOptional,\n IngredientQuantity,\n IngredientQuantity as RecipeIngredientQuantity,\n Ingredients,\n Ingredients as RecipeIngredients,\n type RecipeIngredientListProps,\n type RecipeIngredientNameProps,\n type RecipeIngredientNoteProps,\n type RecipeIngredientOptionalProps,\n type RecipeIngredientProps,\n type RecipeIngredientQuantityProps,\n type RecipeIngredientsProps,\n} from './parts/ingredients'\nexport {\n JsonLd,\n JsonLd as RecipeJsonLd,\n type RecipeJsonLdProps,\n} from './parts/json-ld'\nexport { Root, Root as RecipeRoot, type RecipeRootProps } from './parts/root'\nexport type { RecipeHeadingLevel } from './parts/sections'\nexport {\n ServingsInput,\n ServingsInput as RecipeServingsInput,\n ServingsSelect,\n ServingsSelect as RecipeServingsSelect,\n type RecipeServingsInputProps,\n type RecipeServingsSelectProps,\n} from './parts/servings'\nexport {\n StepText,\n StepText as RecipeStepText,\n type RecipeStepTextProps,\n} from './parts/step-text'\nexport {\n Step,\n Step as RecipeStep,\n StepList,\n StepList as RecipeStepList,\n StepName,\n StepName as RecipeStepName,\n Steps,\n Steps as RecipeSteps,\n type RecipeStepListProps,\n type RecipeStepNameProps,\n type RecipeStepProps,\n type RecipeStepsProps,\n} from './parts/steps'\nexport {\n SystemOption,\n SystemOption as RecipeSystemOption,\n SystemToggle,\n SystemToggle as RecipeSystemToggle,\n type RecipeSystemOptionProps,\n type RecipeSystemToggleProps,\n} from './parts/system-toggle'\nexport { RecipeBookProvider, useRecipe } from './context'\nexport { useRecipeState } from './state/use-recipe-state'\nexport { useFormatIngredient } from './use-format-ingredient'\nexport type { RecipeBookProviderProps, RecipeLabelOverrides } from './context'\nexport type { RecipeLabels } from './labels'\nexport type {\n IngredientItem,\n RecipeSection,\n RecipeState,\n RecipeStateOptions,\n StepItem,\n} from './state/use-recipe-state'\nexport type { FormattedIngredientItem } from './use-format-ingredient'\n","import { RecipeBookError, type Recipe, type System } from '@recipe-book/core'\nimport {\n useContext,\n useMemo,\n type Context,\n type JSX,\n type ReactNode,\n} from 'react'\nimport { defaultLabels, type RecipeLabels } from './labels'\nimport { createContext } from './react'\nimport {\n isSystem,\n type RecipeSection,\n type RecipeState,\n type StepItem,\n} from './state/use-recipe-state'\n\n/** The locale, labels, and starting system that `RecipeBookProvider` and `<Recipe.Root>` take. */\nexport type RecipeBookConfig = {\n /**\n * A language tag that `Intl` accepts, such as `'de-DE'`, for formatting\n * numbers. With a tag it rejects, such as `'en_US'`, formatting a number\n * throws `invalid_argument`.\n *\n * @defaultValue The outer provider's `locale`, then `'en-US'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider\n * @see https://recipe-book.siraj.page/reference/react/root/#root\n */\n locale?: string | undefined\n /**\n * Built-in text to override. A key you leave out keeps the outer provider's\n * value, then its English default. Pass an object that keeps its identity\n * between renders: an equal but new one re-renders most parts.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n * @see https://recipe-book.siraj.page/reference/react/root/\n */\n labels?: RecipeLabelOverrides | undefined\n /**\n * The measurement system a Root starts in, unless its `system` is\n * controlled. Defaults to the outer provider's, then the system its recipe\n * was written in, then `'metric'`. A value other than `'metric'` or `'us'`\n * counts as missing.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider\n * @see https://recipe-book.siraj.page/reference/react/root/#root\n */\n defaultSystem?: System | undefined\n}\n\n/**\n * Built-in text to override, for the `labels` prop of `RecipeBookProvider` and\n * `<Recipe.Root>`.\n *\n * Any keys of `RecipeLabels`. A value replaces the whole key, so `servingUnit`\n * needs both `one` and `other`.\n *\n * @example\n * // At module scope, so it keeps its identity between renders.\n * const labels = {\n * servings: 'Portions',\n * servingUnit: { one: 'portion', other: 'portions' },\n * } satisfies Recipe.RecipeLabelOverrides\n *\n * <Recipe.Root recipe={recipe} labels={labels}>\n * <Recipe.ServingsSelect />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipelabeloverrides\n */\nexport type RecipeLabelOverrides = {\n [Key in keyof RecipeLabels]?: RecipeLabels[Key] | undefined\n}\n\n/**\n * Props of `RecipeBookProvider`: defaults for every Root below it, plus\n * `children`.\n *\n * @example\n * export function AppProvider(props: Recipe.RecipeBookProviderProps) {\n * return <Recipe.RecipeBookProvider locale=\"en-GB\" {...props} />\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider\n */\nexport type RecipeBookProviderProps = RecipeBookConfig & {\n /**\n * The part of the app that uses these defaults.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider\n */\n children?: ReactNode\n}\n\ntype ResolvedConfig = {\n locale: string\n labels: RecipeLabels\n defaultSystem?: System | undefined\n}\n\nconst ConfigContext = /* @__PURE__ */ createContext<ResolvedConfig>({\n locale: 'en-US',\n labels: defaultLabels,\n})\n\n/**\n * App-wide defaults for every `<Recipe.Root>` below it. Takes only data, so it\n * can wrap a layout rendered as a Server Component. Nested providers override\n * the outer one key by key.\n *\n * @example\n * // app/layout.tsx\n * <Recipe.RecipeBookProvider defaultSystem=\"metric\">\n * {children}\n * </Recipe.RecipeBookProvider>\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/#recipebookprovider\n */\nexport function RecipeBookProvider({\n children,\n ...config\n}: RecipeBookProviderProps): JSX.Element {\n const { locale, labels, defaultSystem } = useConfig(config)\n const value = useMemo(\n () => ({ locale, labels, defaultSystem }),\n [locale, labels, defaultSystem],\n )\n return (\n <ConfigContext.Provider value={value}>{children}</ConfigContext.Provider>\n )\n}\n\nexport function useConfig({\n locale,\n labels,\n defaultSystem,\n}: RecipeBookConfig): ResolvedConfig {\n const outer = useContext(ConfigContext)\n return {\n locale: locale ?? outer.locale,\n labels: useMemo(\n () => ({\n ...outer.labels,\n ...Object.fromEntries(\n Object.entries({ ...labels }).filter(\n ([, value]) => value !== undefined,\n ),\n ),\n }),\n [outer.labels, labels],\n ),\n defaultSystem: [defaultSystem, outer.defaultSystem].find(isSystem),\n }\n}\n\n/** Root data that doesn't change with servings or system. */\nexport type RecipeData = {\n recipe: Recipe\n steps: RecipeSection<StepItem>[]\n labels: RecipeLabels\n locale: string\n /** Counts a temperature that `StepText` shows toward `canConvert` until the returned cleanup runs. */\n reportTemperature: () => () => void\n}\n\nexport const RecipeDataContext =\n /* @__PURE__ */ createContext<RecipeData | null>(null)\nexport const RecipeStateContext =\n /* @__PURE__ */ createContext<RecipeState | null>(null)\n\nexport function useRequired<T extends object>(\n context: Context<T | null>,\n message: string,\n): T {\n const value = useContext(context)\n if (!value) {\n throw new RecipeBookError('missing_parent', message)\n }\n return value\n}\n\nexport function useRecipeData(part: string): RecipeData {\n return useRequired(\n RecipeDataContext,\n `<${part}> must be rendered inside <Recipe.Root>.`,\n )\n}\n\nexport function usePartState(part: string): RecipeState {\n return useRequired(\n RecipeStateContext,\n `<${part}> must be rendered inside <Recipe.Root>.`,\n )\n}\n\n/**\n * The state of the nearest `<Recipe.Root>`: the recipe, servings, and\n * measurement system, with their setters.\n *\n * @returns The Root's `RecipeState`: `recipe`, `servings`, `scale`, `system`,\n * `canConvert`, `ingredients` and `steps` as the Root shows them, and the\n * `setServings` and `setSystem` that change them.\n *\n * @throws {RecipeBookError} `missing_parent` outside a Root.\n *\n * @example\n * function SystemSwitch() {\n * const { system, setSystem, canConvert } = Recipe.useRecipe()\n * if (!canConvert) return null\n * return (\n * <button onClick={() => setSystem(system === 'us' ? 'metric' : 'us')}>\n * {system === 'us' ? 'Show metric' : 'Show US'}\n * </button>\n * )\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#userecipe\n */\nexport function useRecipe(): RecipeState {\n return useRequired(\n RecipeStateContext,\n 'useRecipe() must be called inside <Recipe.Root>. To use recipe state without a Root, call useRecipeState().',\n )\n}\n","/**\n * Built-in text that parts render or announce. Override any of it with the\n * `labels` prop on `<Recipe.Root>` or `<RecipeBookProvider>`.\n *\n * A new key is additive: labels that leave it out keep its English default,\n * and a label pack checked with `satisfies RecipeLabels` gets a compile error\n * naming the new key.\n *\n * @example\n * const spanish = {\n * servings: 'Raciones',\n * servingUnit: { one: 'ración', other: 'raciones' },\n * system: 'Sistema de medida',\n * metric: 'Métrico',\n * us: 'EE. UU.',\n * fan: 'con ventilador',\n * optional: '(opcional)',\n * to: 'a',\n * } satisfies Recipe.RecipeLabels\n *\n * <Recipe.RecipeBookProvider locale=\"es-ES\" labels={spanish}>\n * {children}\n * </Recipe.RecipeBookProvider>\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\nexport type RecipeLabels = {\n /**\n * Accessible name of `<Recipe.ServingsSelect>` and `<Recipe.ServingsInput>`,\n * unless they get an `aria-label` or `aria-labelledby`. Defaults to\n * `'Servings'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n servings: string\n /**\n * Unit for the servings count: \"1 serving\", \"4 servings\".\n * `<Recipe.ServingsSelect>` words each option with it, for a recipe with\n * `servings`. Defaults to `{ one: 'serving', other: 'servings' }`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n servingUnit: {\n /** Follows 1 and a fraction below 1: \"1 serving\", \"½ serving\". */\n one: string\n /** Follows decimals and any other number: \"0.3 servings\", \"4 servings\". */\n other: string\n }\n /**\n * Accessible name of `<Recipe.SystemToggle>`, unless it gets an\n * `aria-label` or `aria-labelledby`. Defaults to `'Measurement system'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n system: string\n /**\n * Name of the metric system, shown by a `<Recipe.SystemOption>` for\n * `'metric'` that has no children, or an empty `asChild` child. Defaults to\n * `'Metric'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n metric: string\n /**\n * Name of the US system, shown by a `<Recipe.SystemOption>` for `'us'` that\n * has no children, or an empty `asChild` child. Defaults to `'US'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n us: string\n /**\n * Marker after a fan-oven temperature in `<Recipe.StepText>`: \"160 °C fan\".\n * An empty string leaves it out. Defaults to `'fan'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n fan: string\n /**\n * Marker after an optional ingredient, shown as is, punctuation included.\n * `<Recipe.IngredientOptional>` renders it, and the function from\n * `useFormatIngredient()` returns it as `optional`. Defaults to\n * `'(optional)'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n optional: string\n /**\n * Spoken between the ends of a range, \"2 to 3 tbsp\". Screen readers only:\n * `<Recipe.IngredientQuantity>` keeps the visible dash, \"2–3 tbsp\".\n * Defaults to `'to'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/provider/\n */\n to: string\n}\n\nexport const defaultLabels: RecipeLabels = {\n servings: 'Servings',\n servingUnit: { one: 'serving', other: 'servings' },\n system: 'Measurement system',\n metric: 'Metric',\n us: 'US',\n fan: 'fan',\n optional: '(optional)',\n to: 'to',\n}\n","// Hooks stay imported from 'react' in each module: eslint-plugin-react-hooks\n// recognizes hooks only when they come from 'react' or 'react-dom'.\nexport {\n cloneElement,\n createContext,\n forwardRef,\n Fragment,\n isValidElement,\n} from 'react'\n","import {\n resolveRecipe,\n type Recipe,\n type ResolvedIngredient,\n type Step,\n type System,\n} from '@recipe-book/core'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { assertParsedRecipe } from '../is-parsed-recipe'\nimport { quote } from '../quote'\nimport { useControllableState } from './use-controllable-state'\n\n/**\n * What `useRecipeState()` takes. The state props of `<Recipe.Root>` are the\n * same.\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#recipestateoptions\n */\nexport type RecipeStateOptions = {\n /** A parsed recipe, as returned by `parseRecipe` in `@recipe-book/react/core`. */\n recipe: Recipe\n /**\n * The number of servings to show. Passing it makes servings controlled. A\n * number outside the servings window shows `defaultServings` instead, with a\n * warning in development.\n *\n * @see https://recipe-book.siraj.page/reference/react/root/#controlled-and-uncontrolled-state\n */\n servings?: number | undefined\n /**\n * Starting servings when uncontrolled. A number outside the servings window\n * falls back to the scaling base, with a warning in development.\n *\n * @defaultValue The recipe's scaling base: its servings, then its yield,\n * then 1.\n * @see https://recipe-book.siraj.page/reference/react/root/#scaling-base\n */\n defaultServings?: number | undefined\n /**\n * Called when `setServings` accepts a number other than the current one,\n * whether or not servings are controlled. While a controlled `servings` is\n * outside the range `setServings` accepts, passing it the number shown calls\n * this too.\n */\n onServingsChange?: ((servings: number) => void) | undefined\n /** The measurement system to show. Passing it makes the system controlled. */\n system?: System | undefined\n /** Starting system when uncontrolled; defaults to the system the recipe was written in, then `'metric'`. */\n defaultSystem?: System | undefined\n /**\n * Called when `setSystem` accepts a system other than the current one,\n * whether or not it's controlled. While a controlled `system` is neither\n * `'metric'` nor `'us'`, passing `setSystem` the system shown calls this too.\n */\n onSystemChange?: ((system: System) => void) | undefined\n}\n\n/**\n * An ingredient scaled to the servings and expressed in the display\n * system, unrounded and unformatted. Render its text with the ingredient\n * sub-parts inside `<Recipe.Ingredient>`, or format it with\n * `useFormatIngredient()`.\n */\nexport type IngredientItem = ResolvedIngredient\n\n/** A step with its position, counted from 1 across sections. */\nexport type StepItem = Step & {\n /** The step's position, counted from 1 across sections. */\n number: number\n}\n\n/**\n * A section of a recipe's ingredients or steps. Untitled sections have no\n * `title`.\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#recipesection\n */\nexport type RecipeSection<T> = {\n /** The section's id from the recipe. */\n id: string\n /** The section's title from the recipe. */\n title?: string | undefined\n /** The ingredients or steps in the section. */\n items: T[]\n}\n\n/**\n * What `useRecipe()` and `useRecipeState()` return.\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#recipestate\n */\nexport type RecipeState = {\n /** The parsed recipe. */\n recipe: Recipe\n /** The number of servings shown. For a recipe with a yield but no servings, it counts in the yield's unit. */\n servings: number\n /**\n * Calls `onServingsChange` with a number other than the current one, and\n * changes the servings unless controlled. Ignores a number outside the\n * servings window, from a millionth to a million times the scaling base\n * including both ends, and warns about it in development. While a\n * controlled `servings` is outside that window, passing the number shown\n * calls `onServingsChange` too.\n *\n * @see https://recipe-book.siraj.page/reference/react/root/#servings-window\n */\n setServings: (servings: number) => void\n /** From `resolveRecipe`: `servings` divided by the recipe's servings amount, else its yield amount, else 1. */\n scale: number\n /** The display system. */\n system: System\n /**\n * Calls `onSystemChange` with a system other than the current one, and\n * changes the system unless controlled; ignores anything but `'metric'` and\n * `'us'`. While a controlled `system` is neither, passing the system shown\n * calls `onSystemChange` too.\n */\n setSystem: (system: System) => void\n /**\n * True when an ingredient's quantity has a unit that belongs to only one\n * system. Under `<Recipe.Root>`, a `Recipe.StepText` that shows a\n * temperature also counts once it mounts, which is after the server render.\n * This hook alone reads ingredients only.\n */\n canConvert: boolean\n /** From `resolveRecipe`: each section's ingredients at `servings`, in `system`. */\n ingredients: RecipeSection<IngredientItem>[]\n /** The recipe's steps in their sections, numbered from 1 across sections. */\n steps: RecipeSection<StepItem>[]\n}\n\n/**\n * Headless recipe state: servings, the display system, and data derived from\n * them. Needs no provider and renders nothing. `<Recipe.Root>` is built on it.\n *\n * Each piece of state is controlled when its value is defined (`servings`,\n * `system`) and uncontrolled otherwise. Uncontrolled state resets when\n * `recipe.id` changes.\n *\n * @throws {RecipeBookError} `invalid_argument` in development when `recipe`\n * isn't a parsed recipe.\n *\n * @param options - The recipe and its state.\n * @returns The recipe, its servings and display system with their setters,\n * its ingredients at those settings, and its numbered steps.\n *\n * @example\n * import type { Recipe as ParsedRecipe } from '@recipe-book/react/core'\n * import * as Recipe from '@recipe-book/react'\n *\n * function ServingsSummary({ recipe }: { recipe: ParsedRecipe }) {\n * const { servings, scale } = Recipe.useRecipeState({\n * recipe,\n * defaultServings: 8,\n * })\n * return <p>{`Serves ${servings}, scaled ×${scale}`}</p>\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#userecipestate\n */\nexport function useRecipeState(options: RecipeStateOptions): RecipeState {\n const { recipe } = options\n // Development only: the check costs a hook-only bundle about 0.5 kB.\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- NODE_ENV is fixed per build, so every render calls the same hooks.\n useMemo(() => {\n assertParsedRecipe(\n recipe,\n 'useRecipeState()',\n 'Call parseRecipe() from @recipe-book/react/core and pass result.data.',\n )\n }, [recipe])\n }\n const base = servingsBase(recipe)\n const defaultServings = isServingsFor(options.defaultServings, base)\n ? options.defaultServings\n : base\n const defaultSystem =\n [options.defaultSystem, recipe.system].find(isSystem) ?? 'metric'\n\n const [rawServings, updateServings] = useControllableState({\n prop: 'servings',\n value: options.servings,\n defaultValue: defaultServings,\n onChange: options.onServingsChange,\n resetKey: recipe.id,\n })\n const [rawSystem, updateSystem] = useControllableState({\n prop: 'system',\n value: options.system,\n defaultValue: defaultSystem,\n onChange: options.onSystemChange,\n resetKey: recipe.id,\n })\n\n const servings = isServingsFor(rawServings, base)\n ? rawServings\n : defaultServings\n const system = isSystem(rawSystem) ? rawSystem : defaultSystem\n\n if (process.env.NODE_ENV !== 'production') {\n /* eslint-disable react-hooks/rules-of-hooks -- NODE_ENV is fixed per build, so every render calls the same hooks. */\n useWarning(\n options.defaultServings !== undefined &&\n options.defaultServings !== defaultServings &&\n `Recipe Book: \\`defaultServings\\` must be ${describeRange(base)}, received ${describe(options.defaultServings)}. Using ${defaultServings} instead.`,\n )\n useWarning(\n servings !== rawServings &&\n `Recipe Book: \\`servings\\` must be ${describeRange(base)}, received ${describe(rawServings)}. Showing ${servings} instead.`,\n )\n useWarning(\n system !== rawSystem &&\n `Recipe Book: \\`system\\` must be \"metric\" or \"us\", received ${describe(rawSystem)}. Showing \"${system}\" instead.`,\n )\n /* eslint-enable react-hooks/rules-of-hooks */\n }\n\n const setServings = useCallback(\n (next: number) => {\n if (isServingsFor(next, base)) {\n updateServings(next)\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `Recipe Book: setServings() expects ${describeRange(base)}, but received ${describe(next)}. The value was ignored.`,\n )\n }\n },\n [updateServings, base],\n )\n\n const setSystem = useCallback(\n (next: System) => {\n if (isSystem(next)) {\n updateSystem(next)\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `Recipe Book: setSystem() expects \"metric\" or \"us\", but received ${describe(next)}. The value was ignored.`,\n )\n }\n },\n [updateSystem],\n )\n\n const steps = useMemo(() => resolveRecipe(recipe).steps, [recipe])\n const resolved = useMemo(\n () => resolveRecipe(recipe, { servings, system }),\n [recipe, servings, system],\n )\n\n return useMemo(\n () => ({\n recipe,\n servings,\n setServings,\n scale: resolved.scale,\n system,\n setSystem,\n canConvert: resolved.canConvert,\n ingredients: resolved.ingredients,\n steps,\n }),\n [recipe, servings, setServings, resolved, system, setSystem, steps],\n )\n}\n\nfunction useWarning(message: string | false): void {\n const warned = useRef<string | false>(false)\n useEffect(() => {\n if (message !== warned.current) {\n warned.current = message\n if (message) console.warn(message)\n }\n }, [message])\n}\n\nfunction isServings(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0\n}\n\n/** The servings `resolveRecipe` scales from: the servings amount, else the yield amount, else 1. */\nexport function servingsBase(recipe: Recipe): number {\n return [recipe.servings?.amount, recipe.yield?.amount].find(isServings) ?? 1\n}\n\n// `resolveRecipe` scales by 1 for servings outside a millionth to a million\n// times the base. It finds both bounds by moving the base's decimal point six\n// places, so a bound written out, such as 700000 for a base of 0.7, is in.\nfunction servingsWindow(base: number): [min: number, max: number] {\n const [mantissa, exponent] = base.toExponential().split('e')\n return [\n Number(`${mantissa}e${Number(exponent) - 6}`),\n Number(`${mantissa}e${Number(exponent) + 6}`),\n ]\n}\n\n/** True for the servings `setServings` accepts, given `servingsBase(recipe)`. */\nexport function isServingsFor(value: unknown, base: number): value is number {\n const [min, max] = servingsWindow(base)\n return isServings(value) && value >= min && value <= max\n}\n\nfunction describeRange(base: number): string {\n const [min, max] = servingsWindow(base)\n return `a number from ${roundInward(min, true)} to ${roundInward(max, false)} for this recipe`\n}\n\n// Six significant digits, rounded toward the inside of the window so the number\n// printed is accepted.\nfunction roundInward(bound: number, up: boolean): number {\n const nearest = Number(bound.toPrecision(6))\n if (up ? nearest >= bound : nearest <= bound) {\n return nearest\n }\n const [mantissa, exponent] = bound.toExponential().split('e')\n const digits = Number(mantissa!.replace('.', '').slice(0, 6))\n return Number(`${up ? digits + 1 : digits}e${Number(exponent) - 5}`)\n}\n\nexport function isSystem(value: unknown): value is System {\n return value === 'metric' || value === 'us'\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') {\n return quote(value)\n }\n\n // A function's source could be any length.\n if (typeof value === 'function') {\n return 'a function'\n }\n\n // A symbol's description can hold any text, newlines included.\n if (value === null || typeof value !== 'object') {\n return quote(String(value)).slice(1, -1)\n }\n\n return Array.isArray(value) ? 'an array' : 'an object'\n}\n","import { RecipeBookError, type Recipe } from '@recipe-book/core'\n\ntype Fields = Record<string, unknown>\n\n/** A cheap structural check that catches raw recipe data; it doesn't validate values. */\nexport function assertParsedRecipe(\n value: unknown,\n caller: string,\n fix: string,\n): asserts value is Recipe {\n if (\n isFields(value) &&\n typeof value.id === 'string' &&\n typeof value.name === 'string' &&\n isFields(value.times) &&\n Array.isArray(value.times.custom) &&\n Array.isArray(value.notes) &&\n Array.isArray(value.equipment) &&\n (value.servings === undefined ||\n (isFields(value.servings) &&\n typeof value.servings.amount === 'number')) &&\n (value.yield === undefined ||\n (isFields(value.yield) &&\n typeof value.yield.amount === 'number' &&\n typeof value.yield.unit === 'string')) &&\n isSections(\n value.ingredients,\n (item) =>\n // Parts format each line with formatIngredient, which checks the name.\n (item.quantity === undefined ||\n (isFields(item.quantity) &&\n (typeof item.quantity.amount === 'number' ||\n isFields(item.quantity.amount)))) &&\n Array.isArray(item.equivalents) &&\n typeof item.optional === 'boolean',\n ) &&\n isSections(value.steps, (item) => typeof item.text === 'string')\n ) {\n return\n }\n // Names the kind of value without echoing it: recipe data can be large or private.\n throw new RecipeBookError(\n 'invalid_argument',\n `${caller}: recipe must be a parsed recipe, received ${\n value === undefined || value === null\n ? String(value)\n : Array.isArray(value)\n ? 'an array'\n : typeof value === 'object'\n ? \"an object that parseRecipe hasn't normalized\"\n : `a ${typeof value}`\n }. ${fix}`,\n )\n}\n\nfunction isSections(value: unknown, isItem: (item: Fields) => boolean) {\n return (\n Array.isArray(value) &&\n value.every(\n (section) =>\n isFields(section) &&\n typeof section.id === 'string' &&\n Array.isArray(section.items) &&\n section.items.every(\n (item) =>\n isFields(item) && typeof item.id === 'string' && isItem(item),\n ),\n )\n )\n}\n\nfunction isFields(value: unknown): value is Fields {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","// The characters JSON.stringify leaves raw that can break a log line or reorder\n// it: C1 controls, line and paragraph separators, and bidi controls.\nconst UNESCAPED_BY_JSON =\n /[\\x80-\\x9f\\u061c\\u200e\\u200f\\u2028-\\u202e\\u2066-\\u2069]/g\n\nexport function quote(text: string): string {\n // A cut inside a surrogate pair would print a lone `\\ud83d`.\n const shown =\n text.length > 60\n ? `${text.slice(0, 59).replace(/[\\ud800-\\udbff]$/, '')}…`\n : text\n return JSON.stringify(shown).replace(\n UNESCAPED_BY_JSON,\n (char) => `\\\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`,\n )\n}\n","import {\n useCallback,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n} from 'react'\n\ntype ControllableStateOptions<T> = {\n /** Names the props in dev warnings: 'servings' → servings / defaultServings / onServingsChange. */\n prop: string\n /** Controlled when not undefined. */\n value: T | undefined\n defaultValue: T\n onChange?: ((value: T) => void) | undefined\n /** When this changes, uncontrolled state resets to the current defaultValue. */\n resetKey?: string\n}\n\nexport function useControllableState<T extends number | string>(\n options: ControllableStateOptions<T>,\n): readonly [value: T, setValue: (value: T) => void] {\n const { value, defaultValue, onChange, resetKey } = options\n const [internal, setInternal] = useState(defaultValue)\n const [internalResetKey, setInternalResetKey] = useState(resetKey)\n\n let uncontrolled = internal\n if (!Object.is(resetKey, internalResetKey)) {\n setInternalResetKey(resetKey)\n setInternal(defaultValue)\n uncontrolled = defaultValue\n }\n const current = value === undefined ? uncontrolled : value\n\n const latest = useRef({ value, current, onChange })\n useInsertionEffect(() => {\n latest.current = { value, current, onChange }\n })\n\n const setValue = useCallback((next: T) => {\n const { value, current, onChange } = latest.current\n if (Object.is(next, current)) return\n if (value === undefined) {\n latest.current.current = next\n setInternal(next)\n }\n onChange?.(next)\n }, [])\n\n if (process.env.NODE_ENV !== 'production') {\n const controlled = value !== undefined\n // eslint-disable-next-line react-hooks/rules-of-hooks -- NODE_ENV is fixed per build, so every render calls the same hooks.\n useModeWarnings(\n options.prop,\n controlled,\n controlled && onChange === undefined,\n )\n }\n\n return [current, setValue]\n}\n\nfunction useModeWarnings(\n prop: string,\n controlled: boolean,\n readOnly: boolean,\n): void {\n const initiallyControlled = useRef(controlled)\n const warned = useRef({ readOnly: false, modeSwitch: false })\n useEffect(() => {\n const name = prop.charAt(0).toUpperCase() + prop.slice(1)\n if (readOnly && !warned.current.readOnly) {\n warned.current.readOnly = true\n console.warn(\n `Recipe Book: \\`${prop}\\` was passed without \\`on${name}Change\\`, so it is read-only. Pass \\`on${name}Change\\` to update it, or \\`default${name}\\` instead of \\`${prop}\\` for uncontrolled state.`,\n )\n }\n if (\n controlled !== initiallyControlled.current &&\n !warned.current.modeSwitch\n ) {\n warned.current.modeSwitch = true\n const [from, to] = controlled\n ? ['undefined to a value', 'uncontrolled to controlled']\n : ['a value to undefined', 'controlled to uncontrolled']\n console.warn(\n `Recipe Book: \\`${prop}\\` changed from ${from}, which switches it from ${to}. Decide between controlled and uncontrolled for the component's lifetime: pass \\`${prop}\\` on every render (never undefined), or pass only \\`default${name}\\`.`,\n )\n }\n }, [prop, controlled, readOnly])\n}\n","import type {\n ComponentPropsWithoutRef,\n ComponentRef,\n ElementType,\n ReactNode,\n Ref,\n} from 'react'\nimport { useRecipeData } from '../context'\nimport { forwardRef } from '../react'\n\n/** What `<Recipe.Image>` passes to `as`: a string `src` and `alt`. */\ntype ImageAttributes = { src: string; alt: string }\n\n/** The type error for an `as` component whose `src` and `alt` props don't take a string. */\ntype NotAnImageComponent =\n 'Recipe.Image: as must be a component whose src and alt props take a string'\n\n// A Pick of keys that C's props lack gives `unknown`, which takes a string, so\n// without the keyof check a component without `src` or `alt` would pass. With\n// `never` instead of the message, the error would say `as` must be undefined.\n/** `C` when its `src` and `alt` props take a string, else `NotAnImageComponent`. */\ntype ImageComponent<C extends ElementType> =\n 'src' | 'alt' extends keyof ComponentPropsWithoutRef<C>\n ? ImageAttributes extends Pick<ComponentPropsWithoutRef<C>, 'src' | 'alt'>\n ? C\n : NotAnImageComponent\n : NotAnImageComponent\n\n/**\n * The props of `<Recipe.Image>`: those of `C` without its `ref`, with `src`\n * and `alt` optional, plus `as`. `C` defaults to `'img'`. Use it to type a\n * wrapper that takes what `<Recipe.Image as={C}>` takes.\n *\n * @example\n * import NextImage from 'next/image'\n *\n * function Hero(props: Recipe.RecipeImageProps<typeof NextImage>) {\n * return <Recipe.Image {...props} as={NextImage} className=\"hero\" />\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/image/#type-a-wrapper\n */\nexport type RecipeImageProps<C extends ElementType = 'img'> = {\n /**\n * The component to render instead of `<img>`, such as `next/image`. It\n * gets `src`, `alt`, `data-recipe-image` and the ref, and `Recipe.Image`\n * takes its props. Its `src` and `alt` must take strings, and its other\n * required props are required on `Recipe.Image`. From a Server Component,\n * pass a Client Component: one whose module starts with `'use client'`, as\n * `next/image`'s does.\n *\n * @defaultValue `'img'`\n *\n * @see https://recipe-book.siraj.page/reference/react/image/#render-another-component\n */\n as?: ImageComponent<C> | undefined\n} & Omit<ComponentPropsWithoutRef<C>, 'as' | 'src' | 'alt'> & {\n /**\n * Replaces the recipe's `image`, such as with a CDN URL. Nothing renders\n * when the recipe has no `image`, even with `src`. With `as`, it takes\n * that component's `src` type, such as `string | StaticImport` for\n * `next/image`.\n *\n * @defaultValue The recipe's `image`.\n *\n * @see https://recipe-book.siraj.page/reference/react/image/#image\n */\n src?:\n | (ComponentPropsWithoutRef<C> extends { src?: infer S } ? S : never)\n | undefined\n /**\n * The alt text. Pass `''` for a decorative image.\n *\n * @defaultValue The recipe's `name`.\n *\n * @see https://recipe-book.siraj.page/reference/react/image/#decorative-images\n */\n alt?: string | undefined\n }\n\n/**\n * The recipe's image, as an `<img>` or the component passed to `as`, or\n * nothing when the recipe has none. `src` defaults to the recipe's image and\n * `alt` to its name; pass `alt=\"\"` when the image is decorative. Other props\n * pass through, and it always sets `data-recipe-image`.\n *\n * `Recipe.Image` takes `as`, not `asChild`, so a component such as\n * `next/image` gets `src` and `alt` from the recipe and still has its\n * required props checked.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * import NextImage from 'next/image'\n *\n * function RecipeHero() {\n * return <Recipe.Image as={NextImage} width={1200} height={800} />\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/image/\n */\nexport const Image = /* @__PURE__ */ forwardRef(function Image(\n {\n as: Comp = 'img',\n src,\n alt,\n ...props\n }: { as?: ElementType | undefined; src?: unknown; alt?: string | undefined },\n ref: Ref<unknown>,\n) {\n const { recipe } = useRecipeData('Recipe.Image')\n return (\n recipe.image !== undefined && (\n <Comp\n {...props}\n src={src ?? recipe.image}\n alt={alt ?? recipe.name}\n data-recipe-image=\"\"\n ref={ref}\n />\n )\n )\n}) as <C extends ElementType = 'img'>(\n props: RecipeImageProps<C> & {\n /**\n * Set to the `<img>`, or passed to the `as` component. Left unset when the recipe has no image.\n *\n * @see https://recipe-book.siraj.page/reference/react/image/#image\n */\n ref?: Ref<ComponentRef<C>> | undefined\n },\n) => ReactNode\n","import type { QuantityPart } from '@recipe-book/core'\nimport {\n useMemo,\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type ForwardedRef,\n type ForwardRefExoticComponent,\n type ReactNode,\n type RefAttributes,\n} from 'react'\nimport { usePartState, useRecipeData, useRequired } from '../context'\nimport { cloneElement, createContext, forwardRef } from '../react'\nimport { isEmpty, resolveAsChild } from '../slot'\nimport type { IngredientItem, RecipeSection } from '../state/use-recipe-state'\nimport {\n formatLine,\n lineQuantity,\n type FormattedIngredientItem,\n} from '../use-format-ingredient'\nimport { renderKeyed, SectionBlock, type RecipeHeadingLevel } from './sections'\n\n/**\n * Attributes for the wrapping `<div>` other than `dangerouslySetInnerHTML`,\n * plus `headingLevel`; `children` renders each section.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredients\n */\nexport type RecipeIngredientsProps = Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'dangerouslySetInnerHTML'\n> & {\n /**\n * Heading level of section titles in the default rendering. Defaults to 3,\n * for ingredients under an `<h2>` such as \"Ingredients\".\n *\n * @defaultValue `3`\n * @see https://recipe-book.siraj.page/guides/make-a-recipe-accessible/#set-heading-levels\n */\n headingLevel?: RecipeHeadingLevel | undefined\n /**\n * Renders each section instead of the default. Each result is keyed for\n * you, so return one element or a fragment; an array's items need their own\n * keys, as anywhere in React.\n *\n * @defaultValue A `<section>` named by the section's heading, or a `<div>`\n * for an untitled section, around a `<Recipe.IngredientList>` of its\n * ingredients.\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-sections\n */\n children?: ((section: RecipeSection<IngredientItem>) => ReactNode) | undefined\n}\n\n/**\n * The recipe's ingredients at the current servings and display system, one\n * block per section. A titled section renders as a `<section>` named by its\n * heading, then a `<Recipe.IngredientList>`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n * @throws {RecipeBookError} `invalid_argument` from the `<Recipe.Ingredient>`\n * it renders for each item by default, when Root's `locale` isn't a language\n * tag that `Intl` accepts, such as `'en_US'`.\n *\n * @example\n * <Recipe.Root recipe={recipe}>\n * <h2>Ingredients</h2>\n * <Recipe.Ingredients />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredients\n */\nexport const Ingredients: ForwardRefExoticComponent<\n RecipeIngredientsProps & RefAttributes<HTMLDivElement>\n> = /* @__PURE__ */ forwardRef<HTMLDivElement, RecipeIngredientsProps>(\n function Ingredients({ headingLevel = 3, children, ...props }, ref) {\n const { ingredients } = usePartState('Recipe.Ingredients')\n const renderSection =\n children ??\n ((section: RecipeSection<IngredientItem>) => (\n <SectionBlock\n kind=\"ingredient\"\n title={section.title}\n headingLevel={headingLevel}\n >\n <IngredientList section={section} />\n </SectionBlock>\n ))\n\n return (\n <div {...props} data-recipe-ingredients=\"\" ref={ref}>\n {renderKeyed(ingredients, renderSection)}\n </div>\n )\n },\n)\n\n/**\n * Attributes for the `<ul>` other than `dangerouslySetInnerHTML`, plus the\n * `section` to list; `children` renders each ingredient.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientlist\n */\nexport type RecipeIngredientListProps = Omit<\n ComponentPropsWithoutRef<'ul'>,\n 'children' | 'dangerouslySetInnerHTML'\n> & {\n /** The section to list. Defaults to every ingredient in the recipe. */\n section?: RecipeSection<IngredientItem> | undefined\n /**\n * Renders each ingredient instead of `<Recipe.Ingredient>`. Each result is\n * keyed for you, so return one element or a fragment; an array's items need\n * their own keys, as anywhere in React.\n *\n * @defaultValue `(item) => <Recipe.Ingredient item={item} />`\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-ingredients\n */\n children?: ((item: IngredientItem) => ReactNode) | undefined\n}\n\n/**\n * An unordered list of ingredients, one `<Recipe.Ingredient>` each unless\n * `children` renders them.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n * @throws {RecipeBookError} `invalid_argument` from the `<Recipe.Ingredient>`\n * it renders for each item by default, when Root's `locale` isn't a language\n * tag that `Intl` accepts, such as `'en_US'`.\n *\n * @example\n * <Recipe.IngredientList>\n * {(item) => (\n * <Recipe.Ingredient item={item}>\n * <Recipe.IngredientName /> <Recipe.IngredientQuantity />\n * </Recipe.Ingredient>\n * )}\n * </Recipe.IngredientList>\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientlist\n */\nexport const IngredientList: ForwardRefExoticComponent<\n RecipeIngredientListProps & RefAttributes<HTMLUListElement>\n> = /* @__PURE__ */ forwardRef<HTMLUListElement, RecipeIngredientListProps>(\n function IngredientList(\n { section, children = (item) => <Ingredient item={item} />, ...props },\n ref,\n ) {\n const { ingredients } = usePartState('Recipe.IngredientList')\n const items = section?.items ?? ingredients.flatMap((s) => s.items)\n\n return (\n <ul {...props} data-recipe-ingredient-list=\"\" ref={ref}>\n {renderKeyed(items, children)}\n </ul>\n )\n },\n)\n\n// Carries `labels.to`, so a sub-part in custom children doesn't read Root's\n// data and re-render when an unrelated label changes. The default children\n// re-render with the line.\ntype Line = FormattedIngredientItem & { to: string }\n\nconst LineContext = /* @__PURE__ */ createContext<Line | null>(null)\n\n/**\n * Attributes for the `<li>` other than `dangerouslySetInnerHTML`, plus the\n * `item` to render and `asChild`.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredient\n */\nexport type RecipeIngredientProps = Omit<\n ComponentPropsWithoutRef<'li'>,\n 'dangerouslySetInnerHTML'\n> & {\n /** The ingredient to render, such as one that `<Recipe.IngredientList>` passes to its `children`. */\n item: IngredientItem\n /**\n * Renders the line as its one element child, such as `<motion.li layout />`,\n * instead of an `<li>`. A prop on the child wins, except that the line's\n * `tabIndex` wins, `className`s join, `style` merges key by key with the\n * child winning, both event handlers run (the child's first), and both refs\n * are set. The child's own children replace the line's, so an empty child\n * gets the default line. With anything but one element child, it renders\n * its own `<li>`, with a warning in development.\n *\n * @defaultValue `false`\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#render-your-own-element\n */\n asChild?: boolean | undefined\n}\n\n/**\n * One ingredient line, formatted with the nearest Root's locale and labels.\n * Default children are `<Recipe.IngredientQuantity>`,\n * `<Recipe.IngredientName>`, and `<Recipe.IngredientNote>`, joined as in\n * `formatIngredient`'s `text`, then `<Recipe.IngredientOptional>` after a\n * space. Custom children can use the same sub-parts, which render this line's\n * text.\n *\n * `data-origin` tells where the quantity comes from: `authored`, `equivalent`,\n * or `converted` into the display system. Unquantified lines have\n * `data-unquantified` instead. Optional ingredients have `data-optional`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n * @throws {RecipeBookError} `invalid_argument` when Root's `locale` isn't a\n * language tag that `Intl` accepts, such as `'en_US'`; when `item` isn't\n * `{ ingredient, quantity? }`, such as an authored ingredient; or when an\n * `item` you build has an amount that isn't a finite number greater than 0\n * or a range of them, or a range whose `min` isn't less than its `max`.\n * @throws {RecipeBookError} `unknown_unit` when the item's unit isn't a unit\n * ID.\n *\n * @example\n * <Recipe.Ingredient item={item} className=\"flex gap-2\">\n * <Recipe.IngredientQuantity className=\"w-24 tabular-nums\" />\n * <Recipe.IngredientName />\n * <Recipe.IngredientNote className=\"text-stone-500\" />\n * </Recipe.Ingredient>\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredient\n */\nexport const Ingredient: ForwardRefExoticComponent<\n RecipeIngredientProps & RefAttributes<HTMLLIElement>\n> = /* @__PURE__ */ forwardRef<HTMLLIElement, RecipeIngredientProps>(\n function Ingredient({ item, asChild = false, children, ...props }, ref) {\n const {\n labels: { optional, to },\n locale,\n } = useRecipeData('Recipe.Ingredient')\n const line = useMemo(\n () => ({ ...formatLine(item, locale, optional), to }),\n [item, locale, optional, to],\n )\n\n const quantity = lineQuantity(item)\n const [Comp, content] = resolveAsChild(\n 'Recipe.Ingredient',\n 'li',\n asChild,\n children,\n <>\n <IngredientQuantity />\n {quantity && (quantity.unit === undefined ? '\\u00a0' : ' ')}\n <IngredientName />\n {line.note !== undefined && ', '}\n <IngredientNote />\n {line.optional && ' '}\n <IngredientOptional />\n </>,\n )\n return (\n <LineContext.Provider value={line}>\n <Comp\n {...props}\n data-recipe-ingredient=\"\"\n data-origin={quantity && item.origin}\n data-unquantified={quantity ? undefined : ''}\n data-optional={item.ingredient.optional ? '' : undefined}\n ref={ref}\n >\n {content}\n </Comp>\n </LineContext.Provider>\n )\n },\n)\n\n/** Attributes for an ingredient sub-part's `<span>`, plus `asChild`; `children` go before its text. */\ntype IngredientTextProps = Omit<\n ComponentPropsWithoutRef<'span'>,\n 'dangerouslySetInnerHTML'\n> & {\n /**\n * Renders as its one element child, such as `<a href={url} />`, instead of a\n * `<span>`, with the text after the child's own children. A prop on the\n * child wins, except that the part's `tabIndex` wins, `className`s join,\n * `style` merges key by key with the child winning, both event handlers run\n * (the child's first), and both refs are set. With anything but one element\n * child, it renders its own `<span>`, with a warning in development.\n */\n asChild?: boolean | undefined\n}\n\nfunction ingredientText(\n name: string,\n attribute: `data-recipe-${string}`,\n read: (line: Line, children: ReactNode) => ReactNode,\n): ForwardRefExoticComponent<\n IngredientTextProps & RefAttributes<HTMLSpanElement>\n> {\n const part = `Recipe.${name}`\n function IngredientText(\n { asChild = false, children, ...props }: IngredientTextProps,\n ref: ForwardedRef<HTMLSpanElement>,\n ) {\n const line = useRequired(\n LineContext,\n `<${part}> must be rendered inside <Recipe.Ingredient>.`,\n )\n const text = read(line, children)\n if (text === undefined) {\n return null\n }\n\n const [Comp, child] = resolveAsChild(part, 'span', asChild, children, null)\n return (\n <Comp {...props} {...{ [attribute]: '' }} ref={ref}>\n {Comp === 'span' ? (\n <>\n {children}\n {text}\n </>\n ) : (\n cloneElement(child, undefined, child.props.children, text)\n )}\n </Comp>\n )\n }\n if (process.env.NODE_ENV !== 'production') {\n // React 18's component stacks show the render function's own name, not a\n // displayName.\n Object.defineProperty(IngredientText, 'name', { value: name })\n }\n return forwardRef(IngredientText)\n}\n\n/** Attributes for the `<span>`, plus `asChild`; `children` go before the quantity. */\nexport type RecipeIngredientQuantityProps = IngredientTextProps\n\n/**\n * The nearest `<Recipe.Ingredient>`'s formatted quantity, or nothing for an\n * unquantified line. A range's dash is hidden from screen readers, which hear\n * `labels.to` instead: \"2 to 3 tbsp\". Children come before the quantity.\n *\n * @example\n * <Recipe.IngredientQuantity>\n * {item.origin === 'converted' && '≈ '}\n * </Recipe.IngredientQuantity>\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientquantity\n */\nexport const IngredientQuantity: ForwardRefExoticComponent<\n RecipeIngredientQuantityProps & RefAttributes<HTMLSpanElement>\n> = /* @__PURE__ */ ingredientText(\n 'IngredientQuantity',\n 'data-recipe-quantity',\n ({ quantity, quantityParts, to }) =>\n quantity === undefined ? undefined : renderQuantity(quantityParts, to),\n)\n\n// Hidden without the app's CSS, and left out when the line is copied.\nconst hiddenStyle: CSSProperties = {\n position: 'absolute',\n border: 0,\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n wordWrap: 'normal',\n userSelect: 'none',\n WebkitUserSelect: 'none',\n}\n\nfunction renderQuantity(parts: QuantityPart[], to: string): ReactNode {\n const join = (from: QuantityPart[]) => from.map((part) => part.value).join('')\n const dash = parts.findIndex((part) => part.type === 'rangeSeparator')\n const separator = parts[dash]\n if (!separator) {\n return join(parts)\n }\n\n return (\n <>\n {join(parts.slice(0, dash))}\n <span data-recipe-range-separator=\"\" aria-hidden=\"true\">\n {separator.value}\n </span>\n <span style={hiddenStyle}>{` ${to} `}</span>\n {join(parts.slice(dash + 1))}\n </>\n )\n}\n\n/** Attributes for the `<span>`, plus `asChild`; `children` go before the name. */\nexport type RecipeIngredientNameProps = IngredientTextProps\n\n/**\n * The nearest `<Recipe.Ingredient>`'s name, or its `plural` after a bare\n * count that takes the plural, as in \"2 eggs\". Children come before the name.\n *\n * @example\n * // The name goes inside the link.\n * <Recipe.IngredientName asChild>\n * <a href={`/glossary/${item.id}`} />\n * </Recipe.IngredientName>\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientname\n */\nexport const IngredientName: ForwardRefExoticComponent<\n RecipeIngredientNameProps & RefAttributes<HTMLSpanElement>\n> = /* @__PURE__ */ ingredientText(\n 'IngredientName',\n 'data-recipe-name',\n ({ name }) => name,\n)\n\n/** Attributes for the `<span>`, plus `asChild`; `children` go before the note. */\nexport type RecipeIngredientNoteProps = IngredientTextProps\n\n/**\n * The nearest `<Recipe.Ingredient>`'s note, such as \"sifted\", or nothing when\n * it has none. Children come before the note.\n *\n * @example\n * <Recipe.IngredientNote className=\"text-stone-500\" />\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientnote\n */\nexport const IngredientNote: ForwardRefExoticComponent<\n RecipeIngredientNoteProps & RefAttributes<HTMLSpanElement>\n> = /* @__PURE__ */ ingredientText(\n 'IngredientNote',\n 'data-recipe-note',\n ({ note }) => note,\n)\n\n/** Attributes for the `<span>`, plus `asChild`; `children` go before the label. */\nexport type RecipeIngredientOptionalProps = IngredientTextProps\n\n/**\n * `labels.optional`, \"(optional)\" by default, when the nearest\n * `<Recipe.Ingredient>` is optional; nothing otherwise. It's text, so screen\n * readers read it with the line. Children come before the label.\n *\n * @example\n * <Recipe.IngredientOptional className=\"text-stone-500\" />\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Ingredient>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#ingredientoptional\n */\nexport const IngredientOptional: ForwardRefExoticComponent<\n RecipeIngredientOptionalProps & RefAttributes<HTMLSpanElement>\n> = /* @__PURE__ */ ingredientText(\n 'IngredientOptional',\n 'data-recipe-optional',\n // An empty label shows only the part's own children, such as an icon.\n ({ optional }, children) =>\n optional === '' && isEmpty(children) ? undefined : optional,\n)\n","import { useCallback, type ReactElement, type ReactNode } from 'react'\nimport { quote } from './quote'\nimport { cloneElement, forwardRef, Fragment, isValidElement } from './react'\n\ntype Props = Record<string, unknown>\ntype Child = ReactElement<Props> & { ref?: unknown }\ntype Callback = (...args: unknown[]) => unknown\ntype AnyRef =\n | ((node: unknown) => void | (() => void))\n | { current: unknown }\n | null\n | undefined\n\n/**\n * Picks what a part renders: its own element, `tag`, or with `asChild` its one\n * element child through `Slot`. The child's own children act as the part's\n * children. Either way, no children (`null`, `undefined`, `true` or `false`)\n * get `defaults`. With `asChild`, anything but one element child (no child,\n * text, several children, or a Fragment) is ignored: the part renders `tag`\n * with `children` or `defaults`, and warns once per part in development.\n */\nexport function resolveAsChild<Tag extends 'li' | 'div' | 'button' | 'span'>(\n part: string,\n tag: Tag,\n asChild: boolean,\n children: ReactNode,\n defaults: ReactNode,\n): [typeof Slot, ReactElement<{ children?: ReactNode }>] | [Tag, ReactNode] {\n if (asChild) {\n if (\n isValidElement<{ children?: ReactNode }>(children) &&\n children.type !== Fragment\n ) {\n return [\n Slot,\n isEmpty(children.props.children)\n ? cloneElement(children, undefined, defaults)\n : children,\n ]\n }\n if (process.env.NODE_ENV !== 'production' && !warned.has(part)) {\n warned.add(part)\n console.warn(\n `Recipe Book: <${part}> has asChild but no single element child, received ${describeChildren(children)}, so it renders ${tag === 'li' ? 'an' : 'a'} <${tag}>. Pass one element, such as <${tag}>.`,\n )\n }\n }\n return [tag, isEmpty(children) ? defaults : children]\n}\n\n/**\n * Renders its one element child with the part's props merged in. A prop on the\n * child wins, except that the part's `tabIndex` wins, `className`s join,\n * `style` merges key by key with the child winning, both event handlers run\n * (the child's first), and both refs are set.\n */\nconst Slot = /* @__PURE__ */ forwardRef<unknown, Props>(function Slot(\n { children, ...props },\n ref,\n) {\n const child = children as Child\n const merged = { ...props, ...child.props }\n for (const name in child.props) {\n const ours = props[name]\n const theirs = child.props[name]\n if (name === 'tabIndex' && ours !== undefined) {\n merged[name] = ours\n } else if (name === 'className') {\n merged[name] = [ours, theirs].filter(Boolean).join(' ') || undefined\n } else if (name === 'style') {\n merged[name] = { ...(ours as object), ...(theirs as object) }\n } else if (/^on/.test(name) && typeof ours === 'function') {\n merged[name] =\n typeof theirs === 'function'\n ? (...args: unknown[]) => {\n const [first, second] = [theirs, ours] as [Callback, Callback]\n first(...args)\n second(...args)\n }\n : ours\n }\n }\n\n // React 19 keeps the ref in props, and warns when `element.ref` is read. React\n // 18 keeps it on the element, and in development props.ref is a getter that\n // warns. So read props.ref only when it's a plain value.\n const childRef: unknown =\n Object.getOwnPropertyDescriptor(child.props, 'ref')?.value ?? child.ref\n // A new function would make React detach and attach both refs on every render.\n merged.ref = useCallback(\n (node: unknown) => {\n const refs = [ref, childRef] as AnyRef[]\n const cleanups = refs.map((each) => setRef(each, node))\n // React 18 warns when a callback ref returns a function, so return a\n // cleanup only when a ref returned one, which only React 19 code does.\n if (cleanups.some((cleanup) => typeof cleanup === 'function')) {\n return () =>\n refs.forEach((each, index) => {\n const cleanup = cleanups[index]\n if (typeof cleanup === 'function') {\n cleanup()\n } else {\n setRef(each, null)\n }\n })\n }\n return undefined\n },\n [ref, childRef],\n )\n return cloneElement(child, merged)\n})\n\nfunction setRef(ref: AnyRef, node: unknown): void | (() => void) {\n if (typeof ref === 'function') {\n return ref(node)\n }\n if (ref) {\n ref.current = node\n }\n return undefined\n}\n\nconst warned = /* @__PURE__ */ new Set<string>()\n\nfunction describeChildren(children: ReactNode): string {\n if (isValidElement(children)) {\n return 'a Fragment'\n }\n if (Array.isArray(children)) {\n const count = children.length\n return `an array of ${count} ${count === 1 ? 'child' : 'children'}`\n }\n if (typeof children === 'string' || typeof children === 'number') {\n return `text ${quote(String(children))}`\n }\n return isEmpty(children) ? 'no children' : 'a child that is not an element'\n}\n\nexport function isEmpty(\n children: unknown,\n): children is null | undefined | boolean {\n return children == null || typeof children === 'boolean'\n}\n","import {\n formatIngredient,\n formatQuantityToParts,\n type FormattedIngredient,\n type Quantity,\n type QuantityPart,\n} from '@recipe-book/core'\nimport { useCallback } from 'react'\nimport { RecipeDataContext, useRequired } from './context'\nimport type { IngredientItem } from './state/use-recipe-state'\n\n/** An ingredient formatted with the nearest Root's locale and labels. */\nexport type FormattedIngredientItem = FormattedIngredient & {\n /** The quantity from `formatQuantityToParts`. Empty for an unquantified line. */\n quantityParts: QuantityPart[]\n /** `labels.optional`, set only for an optional ingredient. `text` never includes it. */\n optional?: string | undefined\n}\n\n/**\n * Formats ingredient lines as `<Recipe.Ingredient>` does, with the nearest\n * Root's locale and labels: for markup without the ingredient parts, and for\n * renderers without a DOM. Returns the same function until the locale or\n * `labels.optional` changes.\n *\n * Without a Root, call `formatIngredient` from `@recipe-book/react/core`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a Root.\n *\n * @returns A function that formats one of the state's ingredient items into\n * the pieces `<Recipe.Ingredient>` renders. It throws `invalid_argument`\n * when Root's `locale` isn't a language tag that `Intl` accepts, such as\n * `'en_US'`, the item isn't `{ ingredient, quantity? }`, or it has an amount\n * that `formatQuantity` rejects, and `unknown_unit` when the item's unit\n * isn't a unit ID.\n *\n * @example\n * function CopyIngredients() {\n * const { ingredients } = Recipe.useRecipe()\n * const format = Recipe.useFormatIngredient()\n * const lines = ingredients\n * .flatMap((section) => section.items)\n * .map((item) => {\n * const line = format(item)\n * return line.optional ? `${line.text} ${line.optional}` : line.text\n * })\n * return (\n * <button onClick={() => navigator.clipboard.writeText(lines.join('\\n'))}>\n * Copy ingredients\n * </button>\n * )\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/hooks/#useformatingredient\n */\nexport function useFormatIngredient(): (\n item: IngredientItem,\n) => FormattedIngredientItem {\n const {\n locale,\n labels: { optional },\n } = useRequired(\n RecipeDataContext,\n 'useFormatIngredient() must be called inside <Recipe.Root>. To format ingredients without a Root, call formatIngredient() from @recipe-book/react/core.',\n )\n return useCallback(\n (item: IngredientItem) => formatLine(item, locale, optional),\n [locale, optional],\n )\n}\n\n// The parts and the hook both format through here, so they can't disagree.\nexport function formatLine(\n item: IngredientItem,\n locale: string,\n optional: string,\n): FormattedIngredientItem {\n const options = { locale }\n // formatIngredient checks the item's shape, so it runs before anything reads `item.ingredient`.\n const formatted = formatIngredient(item, options)\n const quantity = lineQuantity(item)\n return {\n ...formatted,\n quantityParts: quantity ? formatQuantityToParts(quantity, options) : [],\n ...(item.ingredient.optional && { optional }),\n }\n}\n\n// formatIngredient falls back to the authored quantity, which an item built by\n// hand may carry instead of `quantity`.\nexport function lineQuantity(item: IngredientItem): Quantity | undefined {\n return item.quantity ?? item.ingredient.quantity\n}\n","import { useId, type ReactNode } from 'react'\nimport { Fragment } from '../react'\n\n/**\n * The heading levels `<Recipe.Ingredients>` and `<Recipe.Steps>` take as\n * `headingLevel` for section titles; level 1 belongs to the page's title.\n * Both default to 3, for sections under an `<h2>` such as \"Ingredients\". Pass\n * the level below your own heading to keep the outline in order.\n *\n * @see https://recipe-book.siraj.page/reference/react/ingredients/#recipeheadinglevel\n */\nexport type RecipeHeadingLevel = 2 | 3 | 4 | 5 | 6\n\nexport function renderKeyed<T extends { id: string }>(\n items: readonly T[],\n render: (item: T) => ReactNode,\n): ReactNode {\n return items.map((item) => <Fragment key={item.id}>{render(item)}</Fragment>)\n}\n\ntype SectionBlockProps = {\n kind: 'step' | 'ingredient'\n title: string | undefined\n headingLevel: RecipeHeadingLevel\n children: ReactNode\n}\n\n/** A `<section>` without a name isn't a landmark, so an untitled section is a `<div>`. */\nexport function SectionBlock({\n kind,\n title,\n headingLevel,\n children,\n}: SectionBlockProps) {\n const headingId = useId()\n const marker = `data-recipe-${kind}-section`\n\n const Heading = `h${headingLevel}` as const\n return title ? (\n <section {...{ [marker]: '' }} aria-labelledby={headingId}>\n <Heading id={headingId}>{title}</Heading>\n {children}\n </section>\n ) : (\n <div {...{ [marker]: '' }}>{children}</div>\n )\n}\n","import { toJsonLd, type ToJsonLdOptions } from '@recipe-book/core/schema-org'\nimport {\n useEffect,\n useMemo,\n useRef,\n type ComponentPropsWithoutRef,\n type ForwardRefExoticComponent,\n type RefAttributes,\n} from 'react'\nimport { useRecipeData } from '../context'\nimport { quote } from '../quote'\nimport { forwardRef } from '../react'\n\n/**\n * The props of `<Recipe.JsonLd>`: `toJsonLd`'s `servings`, `system`, `url`\n * and `extra`, passed to it as they are, plus the `<script>`'s attributes but\n * `type`, `src` and its content, which `<Recipe.JsonLd>` sets.\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld\n */\nexport type RecipeJsonLdProps = {\n /**\n * Writes the recipe at this many servings, as `resolveRecipe` scales it.\n * The Root's servings don't change it.\n *\n * @defaultValue The recipe's own servings, unscaled.\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld\n */\n servings?: ToJsonLdOptions['servings']\n /**\n * Writes quantities in this measurement system. The Root's system doesn't\n * change it.\n *\n * @defaultValue `recipe.system`, then `'metric'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld\n */\n system?: ToJsonLdOptions['system']\n /**\n * The recipe page's URL. Each step gets it as `url`, with the step's id,\n * percent-encoded, as the fragment; without it, steps have no `url`.\n * `<Recipe.Step>` renders no `id`, so pass it the step's `id` for the\n * fragment to point at it.\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/#step-ids\n */\n url?: ToJsonLdOptions['url']\n /**\n * schema.org fields the recipe doesn't model, such as `author`,\n * `datePublished`, or `keywords`, written as you pass them. A field\n * `toJsonLd` writes from the recipe wins; `@context` and `@type` are always\n * its own. A field that is `undefined` is left out, so\n * `{ image: maybeImage }` adds an image only when there is one, and an\n * `image` here stops the missing-image warning. A field `toJsonLd` writes\n * from a recipe takes the type `SchemaOrgRecipe` gives it here too, so an\n * `image` is a URL. Pass the `extra` that `fromJsonLd` returned to write them\n * back.\n *\n * @example\n * <Recipe.JsonLd\n * url=\"https://example.com/pancakes\"\n * extra={{ author: { '@type': 'Person', name: 'Ada Lovelace' } }}\n * />\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/#jsonld\n */\n extra?: ToJsonLdOptions['extra']\n} & Omit<\n ComponentPropsWithoutRef<'script'>,\n 'type' | 'children' | 'dangerouslySetInnerHTML' | 'src'\n>\n\n/**\n * The recipe as schema.org Recipe JSON-LD, for search engines' recipe results,\n * in a `<script type=\"application/ld+json\">` with `<` escaped as `\\u003c`.\n * Writes the recipe as authored: at its own servings and in `recipe.system`,\n * else metric, unless `servings` or `system` say otherwise. Root's current\n * servings and system don't change it. The text is in English. Other props\n * pass to the `<script>`, and it always sets `data-recipe-json-ld`.\n *\n * In development, logs to the browser console the warnings that `toJsonLd`\n * returns, such as for a missing `image`, unless the previous render had the\n * same ones in the same order. Nothing logs where it renders only on the\n * server, such as in an Astro page without a `client:` directive.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * // app/pancakes/page.tsx, a Server Component: no 'use client' needed\n * export default function Page() {\n * return (\n * <Recipe.Root recipe={recipe}>\n * <Recipe.JsonLd url=\"https://example.com/pancakes\" />\n * </Recipe.Root>\n * )\n * }\n *\n * @see https://recipe-book.siraj.page/reference/react/json-ld/\n */\nexport const JsonLd: ForwardRefExoticComponent<\n RecipeJsonLdProps & RefAttributes<HTMLScriptElement>\n> = /* @__PURE__ */ forwardRef<HTMLScriptElement, RecipeJsonLdProps>(\n function JsonLd(\n {\n servings,\n system,\n url,\n extra,\n // Off the props type, but a JavaScript caller can still pass them.\n children,\n src,\n ...props\n }: RecipeJsonLdProps &\n Pick<ComponentPropsWithoutRef<'script'>, 'children' | 'src'>,\n ref,\n ) {\n const { recipe } = useRecipeData('Recipe.JsonLd')\n const result = useMemo(\n () => toJsonLd(recipe, { servings, system, url, extra }),\n [recipe, servings, system, url, extra],\n )\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- NODE_ENV is fixed per build, so every render calls the same hooks.\n useWarningsReport(recipe.name, result.warnings)\n }\n\n return (\n <script\n {...props}\n type=\"application/ld+json\"\n data-recipe-json-ld=\"\"\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(result.data).replace(/</g, '\\\\u003c'),\n }}\n ref={ref}\n />\n )\n },\n)\n\nfunction useWarningsReport(name: string, warnings: readonly unknown[]): void {\n const reported = useRef<string | undefined>(undefined)\n\n useEffect(() => {\n const key = JSON.stringify(warnings)\n const count = warnings.length\n if (count > 0 && key !== reported.current) {\n console.warn(\n `Recipe Book: <Recipe.JsonLd> for ${quote(name)} has ${count} ${count === 1 ? 'warning' : 'warnings'}. The script still renders, but without the fields they name.`,\n warnings,\n )\n }\n reported.current = key\n }, [name, warnings])\n}\n","import type { ParseResult, Recipe } from '@recipe-book/core'\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n type ReactNode,\n} from 'react'\nimport {\n RecipeDataContext,\n RecipeStateContext,\n useConfig,\n type RecipeBookConfig,\n} from '../context'\nimport { assertParsedRecipe } from '../is-parsed-recipe'\nimport { quote } from '../quote'\nimport {\n useRecipeState,\n type RecipeStateOptions,\n} from '../state/use-recipe-state'\n\n/**\n * The props of `<Recipe.Root>`, a union: a parsed `recipe`, or raw data with\n * `parse`. To wrap `Root`, intersect (`RecipeRootProps & { … }`) or\n * destructure it, rather than `Omit<RecipeRootProps, …>`, which doesn't\n * type-check against a union.\n *\n * @see https://recipe-book.siraj.page/reference/react/root/#root\n * @see https://recipe-book.siraj.page/reference/react/root/#wrap-root\n */\nexport type RecipeRootProps = RecipeBookConfig &\n Omit<RecipeStateOptions, 'recipe' | 'defaultSystem'> & {\n /** The parts and components that read the recipe's state. */\n children?: ReactNode\n } & (\n | {\n /**\n * A parsed recipe. Call `parseRecipe` from `@recipe-book/react/core`\n * on the server, in a loader, or at build time, and pass\n * `result.data`.\n */\n recipe: Recipe\n /** Only with recipe data to parse. A parsed recipe takes no `parse`. */\n parse?: undefined\n /** Only with `parse`. A parsed recipe always renders. */\n fallback?: undefined\n }\n | {\n /** Recipe data for `parse` to validate and normalize. */\n recipe: unknown\n /**\n * Parses `recipe` in the browser. Pass `parseRecipe` from\n * `@recipe-book/react/core`; only apps that do download the parser.\n *\n * A function, so it can only be passed from a Client Component. Pass a\n * stable function such as `parseRecipe` itself: an inline arrow\n * parses again on every render.\n */\n parse: (input: unknown) => ParseResult<Recipe>\n /**\n * Rendered instead of `children` when `parse` rejects `recipe`.\n *\n * @defaultValue `null`\n * @see https://recipe-book.siraj.page/reference/react/root/#parse-in-the-browser\n */\n fallback?: ReactNode\n }\n )\n\n/**\n * Provides a recipe's state to the parts inside. Renders no element of its own.\n *\n * Takes a parsed recipe. To parse recipe data in the browser instead, pass\n * `parse={parseRecipe}`: an invalid recipe then renders `fallback`, and in\n * development a result's validation error or warnings are logged to the\n * browser console unless the previous result had the same ones in the same\n * order.\n *\n * @throws {RecipeBookError} `invalid_argument` when `recipe` isn't a parsed\n * recipe and there is no `parse`.\n *\n * @example\n * <Recipe.Root recipe={recipe} defaultServings={8}>\n * <Recipe.Image />\n * <Recipe.Ingredients />\n * <Recipe.Steps />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/root/\n */\nexport function Root({\n recipe,\n parse,\n fallback = null,\n children,\n ...options\n}: RecipeRootProps): JSX.Element {\n const result = useMemo((): ParseResult<Recipe> => {\n if (parse !== undefined) {\n return parse(recipe)\n }\n assertParsedRecipe(\n recipe,\n '<Recipe.Root>',\n 'Call parseRecipe() from @recipe-book/react/core on the server, in a loader, or at build time and pass result.data, or pass parse={parseRecipe} to parse it in the browser.',\n )\n return { success: true, data: recipe, warnings: [] }\n }, [parse, recipe])\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- NODE_ENV is fixed per build, so every render calls the same hooks.\n useParseReport(result)\n }\n\n if (!result.success) {\n return <>{fallback}</>\n }\n\n return (\n <RecipeProvider {...options} recipe={result.data}>\n {children}\n </RecipeProvider>\n )\n}\n\ntype RecipeProviderProps = RecipeBookConfig &\n Omit<RecipeStateOptions, 'defaultSystem'> & {\n children: ReactNode\n }\n\nfunction RecipeProvider({ children, ...options }: RecipeProviderProps) {\n const { locale, labels, defaultSystem } = useConfig(options)\n const state = useRecipeState({ ...options, defaultSystem })\n const [temperatures, setTemperatures] = useState(0)\n const reportTemperature = useCallback(() => {\n setTemperatures((count) => count + 1)\n return () => setTemperatures((count) => count - 1)\n }, [])\n const canConvert = state.canConvert || temperatures > 0\n const value = useMemo(() => ({ ...state, canConvert }), [state, canConvert])\n\n const { recipe, steps } = state\n const data = useMemo(\n () => ({ recipe, steps, labels, locale, reportTemperature }),\n [recipe, steps, labels, locale, reportTemperature],\n )\n\n return (\n <RecipeDataContext.Provider value={data}>\n <RecipeStateContext.Provider value={value}>\n {children}\n </RecipeStateContext.Provider>\n </RecipeDataContext.Provider>\n )\n}\n\nfunction useParseReport(result: ParseResult<Recipe>): void {\n const reported = useRef<string | undefined>(undefined)\n\n useEffect(() => {\n const key = result.success\n ? result.warnings.length > 0\n ? `warnings ${JSON.stringify(result.warnings)}`\n : undefined\n : `error ${JSON.stringify([result.error.message, result.error.issues])}`\n if (key === reported.current) {\n return\n }\n\n reported.current = key\n if (key === undefined) {\n return\n }\n if (result.success) {\n const count = result.warnings.length\n console.warn(\n `Recipe Book: ${quote(result.data.name)} has ${count} ${count === 1 ? 'warning' : 'warnings'}. It still renders, but a warning can mean a misspelled field.`,\n result.warnings,\n )\n } else {\n console.error(result.error)\n }\n }, [result])\n}\n","import {\n formatServings,\n formatYield,\n type FormatQuantityOptions,\n type Recipe,\n} from '@recipe-book/core'\nimport {\n useState,\n type ComponentPropsWithoutRef,\n type ForwardRefExoticComponent,\n type RefAttributes,\n} from 'react'\nimport { composeEventHandlers } from '../compose-event-handlers'\nimport { usePartState, useRecipeData } from '../context'\nimport type { RecipeLabels } from '../labels'\nimport { forwardRef } from '../react'\nimport { isServingsFor, servingsBase } from '../state/use-recipe-state'\n\n/**\n * The props of `<Recipe.ServingsSelect>`: the `<select>`'s attributes, plus\n * the `options` to offer. It sets the value and the options itself, so it\n * doesn't take `value`, `defaultValue`, `multiple`, `children` or\n * `dangerouslySetInnerHTML`.\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect\n */\nexport type RecipeServingsSelectProps = Omit<\n ComponentPropsWithoutRef<'select'>,\n 'value' | 'defaultValue' | 'multiple' | 'children' | 'dangerouslySetInnerHTML'\n> & {\n /**\n * Servings to offer, shown in ascending order. A number outside the\n * servings window is left out.\n *\n * @defaultValue ½×, 1×, 2×, and 3× the recipe's scaling base (its servings\n * amount, else its yield amount, else 1), each rounded to a whole number of\n * at least 1.\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect\n * @see https://recipe-book.siraj.page/reference/react/root/#servings-window\n */\n options?: readonly number[] | undefined\n}\n\n/**\n * A `<select>` of servings. Options read \"4 servings\" when the recipe has\n * servings, \"24 cookies\" in the yield's word when it has only a yield, and\n * \"2×\" when it has neither. Their values are always servings. The current\n * servings are always an option, so a value set elsewhere still shows.\n *\n * Its accessible name defaults to the `servings` label. An `aria-label` you\n * pass replaces it and `aria-labelledby` outranks it. To name the select with\n * a `<label>`, pass `aria-label=\"\"`.\n *\n * It sets `autoComplete=\"off\"`, so when going back reloads the page, the\n * browser doesn't restore an earlier choice over the Root's servings. An\n * `autoComplete` you pass wins.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`, and\n * `invalid_argument` when the Root's `locale` isn't a language tag that\n * `Intl` accepts, such as `'en_US'`.\n *\n * @example\n * <Recipe.Root recipe={recipe}>\n * <Recipe.ServingsSelect options={[2, 4, 6, 8]} />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsselect\n */\nexport const ServingsSelect: ForwardRefExoticComponent<\n RecipeServingsSelectProps & RefAttributes<HTMLSelectElement>\n> = /* @__PURE__ */ forwardRef<HTMLSelectElement, RecipeServingsSelectProps>(\n function ServingsSelect(\n { options, 'aria-label': ariaLabel, onChange, ...props },\n ref,\n ) {\n const { recipe, labels, locale } = useRecipeData('Recipe.ServingsSelect')\n const { servings, setServings } = usePartState('Recipe.ServingsSelect')\n const base = servingsBase(recipe)\n const choices = [\n ...new Set([\n ...(\n options ??\n [0.5, 1, 2, 3].map((factor) => Math.max(1, Math.round(base * factor)))\n ).filter((choice) => isServingsFor(choice, base)),\n servings,\n ]),\n ].sort((a, b) => a - b)\n\n return (\n <select\n autoComplete=\"off\"\n {...props}\n aria-label={(ariaLabel ?? labels.servings) || undefined}\n value={servings}\n data-recipe-servings-select=\"\"\n ref={ref}\n onChange={composeEventHandlers(onChange, (event) => {\n setServings(Number(event.target.value))\n })}\n >\n {choices.map((choice) => (\n <option key={choice} value={choice}>\n {optionText(choice, recipe, base, labels, locale)}\n </option>\n ))}\n </select>\n )\n },\n)\n\n/**\n * The props of `<Recipe.ServingsInput>`: the `<input type=\"number\">`'s\n * attributes, with `min`, `max` and `step` as numbers. It sets the type and\n * the value, which follows the Root's servings, so it doesn't take `type`,\n * `value` or `defaultValue`.\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput\n */\nexport type RecipeServingsInputProps = Omit<\n ComponentPropsWithoutRef<'input'>,\n 'type' | 'value' | 'defaultValue' | 'min' | 'max' | 'step'\n> & {\n /**\n * The fewest servings that can be entered, set as the `min` attribute. The\n * `step` grid counts from it.\n *\n * @defaultValue `1`\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput\n */\n min?: number | undefined\n /**\n * The most servings that can be entered, set as the `max` attribute.\n * Without it, there's no `max` attribute, and the input accepts numbers up\n * to the top of the servings window.\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput\n * @see https://recipe-book.siraj.page/reference/react/root/#servings-window\n */\n max?: number | undefined\n /**\n * How far the arrows move the value, and the grid, counted from `min`, that\n * an entered value must be on. `'any'` allows any value. A `step` that\n * isn't a number above 0 counts as 1, as in the browser.\n *\n * @defaultValue `1`, the browser's step for an input without a `step`\n * attribute\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#the-step-grid\n */\n step?: number | 'any' | undefined\n}\n\n/**\n * A number input for servings. Each valid value commits as it's typed. An\n * empty or out-of-range entry, text that isn't a number yet, or a number off\n * the `step` grid stays a draft, and leaving the input shows the current\n * servings again. Servings the recipe can't be scaled to count as out of\n * range, so typing them logs no warning.\n *\n * Its accessible name and `autoComplete` follow the same rules as\n * `<Recipe.ServingsSelect>`. `inputMode` defaults to `'numeric'` when `min`\n * and the step are whole numbers, as with the defaults of 1, and to\n * `'decimal'` otherwise, including with `step=\"any\"`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * <Recipe.Root recipe={recipe}>\n * <Recipe.ServingsInput max={48} />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/servings/#servingsinput\n */\nexport const ServingsInput: ForwardRefExoticComponent<\n RecipeServingsInputProps & RefAttributes<HTMLInputElement>\n> = /* @__PURE__ */ forwardRef<HTMLInputElement, RecipeServingsInputProps>(\n function ServingsInput(\n {\n min = 1,\n max,\n step,\n inputMode,\n 'aria-label': ariaLabel,\n onChange,\n onBlur,\n ...props\n },\n ref,\n ) {\n const { recipe, labels } = useRecipeData('Recipe.ServingsInput')\n const { servings, setServings } = usePartState('Recipe.ServingsInput')\n const base = servingsBase(recipe)\n const [draft, setDraft] = useState({ text: String(servings), servings })\n if (draft.servings !== servings) {\n setDraft({\n text: Number(draft.text) === servings ? draft.text : String(servings),\n servings,\n })\n }\n\n const whole = Number.isInteger(min) && Number.isInteger(step ?? 1)\n\n return (\n <input\n autoComplete=\"off\"\n {...props}\n type=\"number\"\n inputMode={inputMode ?? (whole ? 'numeric' : 'decimal')}\n aria-label={(ariaLabel ?? labels.servings) || undefined}\n min={min}\n max={max}\n step={step}\n value={draft.text}\n data-recipe-servings-input=\"\"\n ref={ref}\n onChange={composeEventHandlers(onChange, (event) => {\n const text = event.target.value\n const next = Number(text)\n setDraft({ text, servings })\n if (\n isServingsFor(next, base) &&\n next >= min &&\n (max === undefined || next <= max)\n ) {\n const steps =\n step === 'any' ? 0 : (next - min) / (step && step > 0 ? step : 1)\n // Tolerates 1e-15 * (steps + next / step), so step 0.1 accepts 1.3.\n // For min >= 0 and up to 13 significant digits at the finest\n // decimal place of value, min and step, nothing a browser flags\n // commits.\n if (\n Math.abs(steps - Math.round(steps)) <=\n (Math.round(steps) && 1e-15 * (steps + steps / (1 - min / next)))\n ) {\n setServings(next)\n }\n }\n })}\n onBlur={composeEventHandlers(onBlur, () => {\n setDraft({ text: String(servings), servings })\n })}\n />\n )\n },\n)\n\n/**\n * With neither servings nor a yield, the base is 1, so the servings are the\n * multiplier. Servings are worded like a yield, by core's plural rule (§4.4):\n * \"½ serving\", \"0.3 servings\".\n */\nfunction optionText(\n choice: number,\n { servings, yield: makes }: Recipe,\n base: number,\n labels: RecipeLabels,\n locale: string,\n): string {\n // Kitchen rounding would print a typed 2.1 as \"2\", like the 2 option.\n const format: FormatQuantityOptions = {\n locale,\n rounding: Number.isInteger(choice * 4) ? 'kitchen' : 'none',\n }\n // `servingsBase` takes the first valid amount, so an invalid one isn't the base.\n if (base === servings?.amount) {\n return formatYield(\n {\n amount: choice,\n unit: labels.servingUnit.one,\n plural: labels.servingUnit.other,\n },\n format,\n )\n }\n if (base === makes?.amount) {\n return formatYield(\n { amount: choice, unit: makes.unit, plural: makes.plural },\n format,\n )\n }\n return `${formatServings({ amount: choice }, format)}×`\n}\n","import type { SyntheticEvent } from 'react'\n\nexport function composeEventHandlers<E extends SyntheticEvent>(\n theirs: ((event: E) => void) | undefined,\n ours: (event: E) => void,\n): (event: E) => void {\n return (event) => {\n theirs?.(event)\n if (!event.defaultPrevented) {\n ours(event)\n }\n }\n}\n","import {\n convertTemperature,\n formatTemperature,\n segmentStepText,\n type TemperatureSegment,\n} from '@recipe-book/core'\nimport {\n useEffect,\n useMemo,\n type ComponentPropsWithoutRef,\n type ForwardRefExoticComponent,\n type RefAttributes,\n} from 'react'\nimport { usePartState, useRecipeData, useRequired } from '../context'\nimport { forwardRef } from '../react'\nimport { StepContext } from './steps'\n\n/**\n * Attributes for the `<span>`; it renders the step's text, so no `children` or\n * `dangerouslySetInnerHTML`.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steptext\n */\nexport type RecipeStepTextProps = Omit<\n ComponentPropsWithoutRef<'span'>,\n 'children' | 'dangerouslySetInnerHTML'\n>\n\n/**\n * The nearest `<Recipe.Step>`'s text, with each temperature shown in Root's\n * display system: °C for metric, °F for US. A reading the author wrote in that\n * unit keeps its value as written, such as 56.5 °C. A converted one is in\n * whole degrees, because step text doesn't say whether it's an oven setting or\n * a food temperature. A setting the author already wrote in both units isn't\n * converted again, and a fan-oven setting is followed by `labels.fan`. A gas\n * mark that follows a temperature as another way to give the same setting, as\n * in `190C/170C fan/gas 5` or `200°C (gas mark 6)`, is left out. Everything\n * else, including a gas mark on its own or before a temperature, is shown as\n * authored. Each temperature is a `<span data-recipe-temperature>`. When\n * `segmentStepText` pairs a conventional setting with a fan one, the\n * conventional one shows first and the fan one after a slash, as in\n * `200 °C / 180 °C fan`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Step>`.\n * @throws {RecipeBookError} `invalid_argument` for a step with a temperature\n * when Root's `locale` isn't a language tag that `Intl` accepts, such as\n * `'en_US'`.\n *\n * @example\n * <Recipe.Step item={step}>\n * <Recipe.StepName /> <Recipe.StepText />\n * </Recipe.Step>\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steptext\n */\nexport const StepText: ForwardRefExoticComponent<\n RecipeStepTextProps & RefAttributes<HTMLSpanElement>\n> = /* @__PURE__ */ forwardRef<HTMLSpanElement, RecipeStepTextProps>(\n function StepText(props, ref) {\n const step = useRequired(\n StepContext,\n '<Recipe.StepText> must be rendered inside <Recipe.Step>.',\n )\n const segments = useMemo(() => segmentStepText(step.text), [step.text])\n\n return (\n <span {...props} data-recipe-step-text=\"\" ref={ref}>\n {segments.map((segment, index) =>\n segment.type === 'temperature' ? (\n <Temperature key={index} segment={segment} />\n ) : (\n // Core may add segment types in a minor release; show those as authored.\n segment.text\n ),\n )}\n </span>\n )\n },\n)\n\n// Its own component, so a servings or system change re-renders only the temperatures.\n// Its text must match showStep in core's units reference, which says StepText does.\nfunction Temperature({ segment }: { segment: TemperatureSegment }) {\n const { labels, locale, reportTemperature } = useRecipeData('Recipe.StepText')\n const unit = usePartState('Recipe.StepText').system === 'us' ? 'F' : 'C'\n const readings = [segment, ...segment.alternatives]\n\n useEffect(reportTemperature, [reportTemperature])\n\n return (\n <span data-recipe-temperature=\"\">\n {[false, true]\n .map((fan) => {\n const kind = readings.filter((reading) => reading.fan === fan)\n const reading =\n kind.find((each) => each.temperature.unit === unit) ?? kind[0]\n return (\n reading &&\n formatTemperature(convertTemperature(reading.temperature, unit), {\n locale,\n rounding: reading.temperature.unit === unit ? 'none' : undefined,\n }) + (fan && labels.fan ? ` ${labels.fan}` : '')\n )\n })\n .filter(Boolean)\n .join(' / ')}\n </span>\n )\n}\n","import type {\n ComponentPropsWithoutRef,\n ForwardRefExoticComponent,\n ReactNode,\n RefAttributes,\n} from 'react'\nimport { useRecipeData, useRequired } from '../context'\nimport { createContext, forwardRef } from '../react'\nimport { resolveAsChild } from '../slot'\nimport type { RecipeSection, StepItem } from '../state/use-recipe-state'\nimport { renderKeyed, SectionBlock, type RecipeHeadingLevel } from './sections'\n\n/**\n * Attributes for the wrapping `<div>` other than `dangerouslySetInnerHTML`,\n * plus `headingLevel`; `children` renders each section.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steps\n */\nexport type RecipeStepsProps = Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'dangerouslySetInnerHTML'\n> & {\n /**\n * Heading level of section titles in the default rendering. Defaults to 3,\n * for steps under an `<h2>` such as \"Method\".\n *\n * @defaultValue `3`\n * @see https://recipe-book.siraj.page/guides/make-a-recipe-accessible/#set-heading-levels\n */\n headingLevel?: RecipeHeadingLevel | undefined\n /**\n * Renders each section instead of the default. Each result is keyed for\n * you, so return one element or a fragment; an array's items need their own\n * keys, as anywhere in React.\n *\n * @defaultValue A `<section>` named by the section's heading, or a `<div>`\n * for an untitled section, around a `<Recipe.StepList>` of its steps.\n * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-sections\n */\n children?: ((section: RecipeSection<StepItem>) => ReactNode) | undefined\n}\n\n/**\n * The recipe's steps, one block per section. A titled section renders as a\n * `<section>` named by its heading, then a `<Recipe.StepList>`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * <Recipe.Root recipe={recipe}>\n * <h2>Method</h2>\n * <Recipe.Steps />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steps\n */\nexport const Steps: ForwardRefExoticComponent<\n RecipeStepsProps & RefAttributes<HTMLDivElement>\n> = /* @__PURE__ */ forwardRef<HTMLDivElement, RecipeStepsProps>(function Steps(\n { headingLevel = 3, children, ...props },\n ref,\n) {\n const { steps } = useRecipeData('Recipe.Steps')\n const renderSection =\n children ??\n ((section: RecipeSection<StepItem>) => (\n <SectionBlock\n kind=\"step\"\n title={section.title}\n headingLevel={headingLevel}\n >\n <StepList section={section} />\n </SectionBlock>\n ))\n\n return (\n <div {...props} data-recipe-steps=\"\" ref={ref}>\n {renderKeyed(steps, renderSection)}\n </div>\n )\n})\n\n/**\n * Attributes for the `<ol>` other than `dangerouslySetInnerHTML`, plus the\n * `section` to list; `children` renders each step.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steplist\n */\nexport type RecipeStepListProps = Omit<\n ComponentPropsWithoutRef<'ol'>,\n 'children' | 'dangerouslySetInnerHTML'\n> & {\n /** The section to list. Defaults to every step in the recipe. */\n section?: RecipeSection<StepItem> | undefined\n /**\n * Renders each step instead of `<Recipe.Step>`. Each result is keyed for\n * you, so return one element or a fragment; an array's items need their own\n * keys, as anywhere in React.\n *\n * @defaultValue `(step) => <Recipe.Step item={step} />`\n * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-steps\n */\n children?: ((step: StepItem) => ReactNode) | undefined\n}\n\n/**\n * An ordered list of steps. `start` defaults to the first step's number, so\n * numbering continues across sections.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * <Recipe.StepList>\n * {(step) => (\n * <Recipe.Step item={step}>\n * <Recipe.StepName /> <Recipe.StepText />\n * </Recipe.Step>\n * )}\n * </Recipe.StepList>\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#steplist\n */\nexport const StepList: ForwardRefExoticComponent<\n RecipeStepListProps & RefAttributes<HTMLOListElement>\n> = /* @__PURE__ */ forwardRef<HTMLOListElement, RecipeStepListProps>(\n function StepList(\n { section, children = (step) => <Step item={step} />, start, ...props },\n ref,\n ) {\n const { steps } = useRecipeData('Recipe.StepList')\n const items = section?.items ?? steps.flatMap((s) => s.items)\n\n return (\n <ol\n {...props}\n start={start ?? items[0]?.number}\n data-recipe-step-list=\"\"\n ref={ref}\n >\n {renderKeyed(items, children)}\n </ol>\n )\n },\n)\n\nexport const StepContext = /* @__PURE__ */ createContext<StepItem | null>(null)\n\n/**\n * Attributes for the `<li>` other than `dangerouslySetInnerHTML`, plus the\n * `item` to render and `asChild`.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#step\n */\nexport type RecipeStepProps = Omit<\n ComponentPropsWithoutRef<'li'>,\n 'dangerouslySetInnerHTML'\n> & {\n /** The step to render, with its number. */\n item: StepItem\n /**\n * Renders the step as its one element child, such as `<motion.li layout />`,\n * instead of an `<li>`. A prop on the child wins, except that the step's\n * `tabIndex` wins, `className`s join, `style` merges key by key with the\n * child winning, both event handlers run (the child's first), and both refs\n * are set. The child's own children replace the step's, so an empty child\n * gets the name and text. With anything but one element child, it renders\n * its own `<li>`, with a warning in development.\n *\n * @defaultValue `false`\n * @see https://recipe-book.siraj.page/reference/react/steps/#render-your-own-element\n */\n asChild?: boolean | undefined\n}\n\n/**\n * One step. Default children are `<Recipe.StepName>`, then a space if the\n * step has a name, then its text as authored. Custom children can use\n * `<Recipe.StepName>` and `<Recipe.StepText>` to read like the default, with\n * temperatures in Root's display system.\n *\n * @example\n * <Recipe.Step item={step}>\n * <Recipe.StepName /> <Recipe.StepText />\n * </Recipe.Step>\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#step\n */\nexport const Step: ForwardRefExoticComponent<\n RecipeStepProps & RefAttributes<HTMLLIElement>\n> = /* @__PURE__ */ forwardRef<HTMLLIElement, RecipeStepProps>(function Step(\n { item, asChild = false, children, ...props },\n ref,\n) {\n useRecipeData('Recipe.Step')\n\n const [Comp, content] = resolveAsChild(\n 'Recipe.Step',\n 'li',\n asChild,\n children,\n <>\n <StepName />\n {item.name !== undefined && ' '}\n {item.text}\n </>,\n )\n return (\n <StepContext.Provider value={item}>\n <Comp {...props} data-recipe-step=\"\" ref={ref}>\n {content}\n </Comp>\n </StepContext.Provider>\n )\n})\n\n/**\n * Attributes for the `<b>`; it renders the step's name, so no `children` or\n * `dangerouslySetInnerHTML`.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#stepname\n */\nexport type RecipeStepNameProps = Omit<\n ComponentPropsWithoutRef<'b'>,\n 'children' | 'dangerouslySetInnerHTML'\n>\n\n/**\n * The nearest `<Recipe.Step>`'s name in a `<b data-recipe-name>`, or nothing\n * when the step has none.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Step>`.\n *\n * @see https://recipe-book.siraj.page/reference/react/steps/#stepname\n */\nexport const StepName: ForwardRefExoticComponent<\n RecipeStepNameProps & RefAttributes<HTMLElement>\n> = /* @__PURE__ */ forwardRef<HTMLElement, RecipeStepNameProps>(\n function StepName(props, ref) {\n const step = useRequired(\n StepContext,\n '<Recipe.StepName> must be rendered inside <Recipe.Step>.',\n )\n return step.name === undefined ? null : (\n <b {...props} data-recipe-name=\"\" ref={ref}>\n {step.name}\n </b>\n )\n },\n)\n","import type { System } from '@recipe-book/core'\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useState,\n type ComponentPropsWithoutRef,\n type ForwardRefExoticComponent,\n type KeyboardEvent,\n type RefAttributes,\n} from 'react'\nimport { composeEventHandlers } from '../compose-event-handlers'\nimport { usePartState, useRecipeData, useRequired } from '../context'\nimport { createContext, forwardRef } from '../react'\nimport { resolveAsChild } from '../slot'\n\ntype ToggleContextValue = {\n system: System\n setSystem: (system: System) => void\n disabled: boolean\n /** The `useId` of the option in the tab order, once an option registers. */\n tabStop: string | undefined\n /** Registers an enabled option until the returned cleanup runs. */\n offer: (id: string, value: System) => () => void\n /** Moves the tab stop to this option while its value is checked. */\n choose: (id: string) => void\n}\n\nconst ToggleContext = /* @__PURE__ */ createContext<ToggleContextValue | null>(\n null,\n)\n\n/**\n * The props of `<Recipe.SystemToggle>`: the radio group's `<div>` attributes,\n * plus `asChild`. It sets `role` and renders its own content, so it doesn't\n * take `role` or `dangerouslySetInnerHTML`.\n *\n * The group sets `aria-disabled` and its data attributes at runtime, over any\n * you pass, so `aria-disabled` is there only while the toggle is disabled. An\n * `asChild` child's own `role`, `aria-disabled` and data attributes still\n * win.\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemtoggle\n */\nexport type RecipeSystemToggleProps = Omit<\n ComponentPropsWithoutRef<'div'>,\n 'role' | 'dangerouslySetInnerHTML'\n> & {\n /**\n * Renders the radio group as its one element child, such as\n * `<motion.div layout />`, instead of a `<div>`. A prop on the child wins,\n * except that the group's `tabIndex` wins, `className`s join, `style` merges\n * key by key with the child winning, both event handlers run (the child's\n * first), and both refs are set. The child's own children replace the\n * group's, so an empty child gets the metric and US options. With anything\n * but one element child, it renders its own `<div>`, with a warning in\n * development.\n *\n * @defaultValue `false`\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#render-your-own-elements\n */\n asChild?: boolean | undefined\n}\n\n/**\n * Switches the Root's measurement system. A radio group whose default options\n * are metric and US. Disabled when there's nothing to convert: no ingredient\n * has a unit that belongs to only one system, and no `Recipe.StepText` in the\n * Root shows a temperature. A `StepText` counts once it mounts, so for a\n * recipe whose only temperatures are in its steps, the toggle enables after\n * hydration.\n *\n * Its accessible name defaults to the `system` label, unless you pass\n * `aria-label` or `aria-labelledby`.\n *\n * @throws {RecipeBookError} `missing_parent` outside a `<Recipe.Root>`.\n *\n * @example\n * <Recipe.Root recipe={recipe}>\n * <Recipe.SystemToggle className=\"units\" />\n * </Recipe.Root>\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemtoggle\n */\nexport const SystemToggle: ForwardRefExoticComponent<\n RecipeSystemToggleProps & RefAttributes<HTMLDivElement>\n> = /* @__PURE__ */ forwardRef<HTMLDivElement, RecipeSystemToggleProps>(\n function SystemToggle(\n { asChild = false, 'aria-label': ariaLabel, children, ...props },\n ref,\n ) {\n const { labels } = useRecipeData('Recipe.SystemToggle')\n const { system, setSystem, canConvert } = usePartState(\n 'Recipe.SystemToggle',\n )\n const disabled = !canConvert\n const [offers, setOffers] = useState<\n readonly { id: string; value: System }[]\n >([])\n const [chosen, choose] = useState<string>()\n\n const offer = useCallback((id: string, value: System) => {\n const entry = { id, value }\n setOffers((current) => [...current, entry])\n return () =>\n setOffers((current) => current.filter((other) => other !== entry))\n }, [])\n\n const tabStop = (\n offers.find((entry) => entry.value === system && entry.id === chosen) ??\n offers.find((entry) => entry.value === system) ??\n offers[0]\n )?.id\n\n const context = useMemo(\n () => ({ system, setSystem, disabled, tabStop, offer, choose }),\n [system, setSystem, disabled, tabStop, offer],\n )\n\n const [Comp, content] = resolveAsChild(\n 'Recipe.SystemToggle',\n 'div',\n asChild,\n children,\n <>\n <SystemOption value=\"metric\" />\n <SystemOption value=\"us\" />\n </>,\n )\n return (\n <ToggleContext.Provider value={context}>\n <Comp\n {...props}\n aria-label={\n ariaLabel ??\n (props['aria-labelledby'] === undefined ? labels.system : undefined)\n }\n role=\"radiogroup\"\n aria-disabled={disabled || undefined}\n data-recipe-system-toggle=\"\"\n data-disabled={disabled ? '' : undefined}\n ref={ref}\n >\n {content}\n </Comp>\n </ToggleContext.Provider>\n )\n },\n)\n\n/**\n * The props of `<Recipe.SystemOption>`: the radio's `<button>` attributes,\n * with `value` the system it selects, plus `asChild`. It sets `role` and\n * `tabIndex` and renders its own content, so it doesn't take them or\n * `dangerouslySetInnerHTML`.\n *\n * The option sets `aria-checked` and its data attributes at runtime, over any\n * you pass. An `asChild` child's own `role`, `aria-checked` and data\n * attributes still win.\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption\n */\nexport type RecipeSystemOptionProps = Omit<\n ComponentPropsWithoutRef<'button'>,\n 'value' | 'role' | 'tabIndex' | 'dangerouslySetInnerHTML'\n> & {\n /**\n * The system this option selects: `'metric'` or `'us'`.\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption\n */\n value: System\n /**\n * The button's `autocomplete` attribute. Off by default, so when going back\n * reloads the page, Firefox doesn't re-enable an option that the server\n * rendered disabled and the page enabled later.\n *\n * @defaultValue `'off'`\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption\n */\n autoComplete?: string | undefined\n /**\n * Renders the radio as its one element child, such as\n * `<motion.button layout />`, instead of a `<button>`. A prop on the child\n * wins, except that the option's `tabIndex` wins, `className`s join, `style`\n * merges key by key with the child winning, both event handlers run (the\n * child's first), and both refs are set. The option sets `tabIndex` to keep\n * one radio in the tab order once React hydrates the page; before that,\n * every enabled checked option is in it. The child's own children replace\n * the option's, so an empty child gets the system's label. With anything but\n * one element child, it renders its own `<button>`, with a warning in\n * development.\n *\n * @defaultValue `false`\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#render-your-own-elements\n */\n asChild?: boolean | undefined\n}\n\n/**\n * One option of a `<Recipe.SystemToggle>`. Checked when its `value` is the\n * Root's system; a click sets the Root's system to `value`. Children default\n * to the system's label. Its `type` defaults to `'button'`, so it doesn't\n * submit a form. It's disabled while the toggle is, even with\n * `disabled={false}`.\n *\n * It sets `autoComplete=\"off\"`, so when going back reloads the page, Firefox\n * doesn't re-enable an option that the server rendered disabled and the page\n * enabled later. An `autoComplete` you pass wins.\n *\n * @throws {RecipeBookError} `missing_parent` outside a\n * `<Recipe.SystemToggle>`.\n *\n * @example\n * <Recipe.SystemToggle>\n * <Recipe.SystemOption value=\"us\">Cups and spoons</Recipe.SystemOption>\n * <Recipe.SystemOption value=\"metric\">\n * Grams and milliliters\n * </Recipe.SystemOption>\n * </Recipe.SystemToggle>\n *\n * @see https://recipe-book.siraj.page/reference/react/system-toggle/#systemoption\n */\nexport const SystemOption: ForwardRefExoticComponent<\n RecipeSystemOptionProps & RefAttributes<HTMLButtonElement>\n> = /* @__PURE__ */ forwardRef<HTMLButtonElement, RecipeSystemOptionProps>(\n function SystemOption(\n {\n value,\n asChild = false,\n type,\n disabled: ownDisabled = false,\n children,\n onClick,\n onKeyDown,\n ...props\n },\n ref,\n ) {\n const {\n system,\n setSystem,\n disabled: groupDisabled,\n tabStop,\n offer,\n choose,\n } = useRequired(\n ToggleContext,\n '<Recipe.SystemOption> must be rendered inside <Recipe.SystemToggle>.',\n )\n const { labels } = useRecipeData('Recipe.SystemOption')\n const id = useId()\n const disabled = groupDisabled || ownDisabled\n const checked = value === system\n\n useEffect(\n () => (disabled ? undefined : offer(id, value)),\n [disabled, offer, id, value],\n )\n\n // On the server and before options register, every enabled option with the\n // checked value holds the tab stop.\n const tabbable =\n !disabled && (tabStop === undefined ? checked : tabStop === id)\n\n const [Comp, content] = resolveAsChild(\n 'Recipe.SystemOption',\n 'button',\n asChild,\n children,\n labels[value],\n )\n return (\n <Comp\n autoComplete=\"off\"\n {...props}\n type={type ?? 'button'}\n role=\"radio\"\n aria-checked={checked}\n tabIndex={tabbable ? 0 : -1}\n disabled={disabled}\n data-recipe-system-option=\"\"\n data-state={checked ? 'checked' : 'unchecked'}\n data-disabled={disabled ? '' : undefined}\n ref={ref}\n onClick={composeEventHandlers(onClick, () => {\n if (!disabled) {\n setSystem(value)\n choose(id)\n }\n })}\n onKeyDown={composeEventHandlers(onKeyDown, moveOnArrowKey)}\n >\n {content}\n </Comp>\n )\n },\n)\n\nfunction moveOnArrowKey(event: KeyboardEvent<HTMLElement>): void {\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return\n }\n const { key } = event\n let step: 1 | -1\n if (key === 'ArrowDown') {\n step = 1\n } else if (key === 'ArrowUp') {\n step = -1\n } else if (key === 'ArrowRight') {\n step = isRtl(event.currentTarget) ? -1 : 1\n } else if (key === 'ArrowLeft') {\n step = isRtl(event.currentTarget) ? 1 : -1\n } else {\n return\n }\n\n const group = event.currentTarget.closest('[data-recipe-system-toggle]')\n const options = Array.from(\n group?.querySelectorAll<HTMLElement>(\n '[data-recipe-system-option]:not([data-disabled])',\n ) ?? [],\n )\n const index = options.indexOf(event.currentTarget)\n if (index === -1) {\n return\n }\n\n event.preventDefault()\n const next = options[(index + step + options.length) % options.length]\n next?.focus()\n next?.click()\n}\n\nfunction isRtl(element: Element): boolean {\n return element.closest('[dir]')?.getAttribute('dir')?.toLowerCase() === 'rtl'\n}\n"],"mappings":"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","names":["import_core","import_react","import_core","import_react","import_react","value","current","onChange","warned","warned","import_jsx_runtime","Image","import_react","import_react","Slot","import_core","import_react","import_react","import_jsx_runtime","import_jsx_runtime","Ingredients","IngredientList","Ingredient","import_react","import_jsx_runtime","JsonLd","import_react","import_jsx_runtime","import_core","import_react","import_jsx_runtime","ServingsSelect","ServingsInput","import_core","import_react","import_jsx_runtime","Steps","StepList","Step","StepName","import_jsx_runtime","StepText","reading","import_react","import_jsx_runtime","SystemToggle","SystemOption"]}