@recipe-book/react 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # @recipe-book/react
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - `docsUrl`, and the link at the end of every error message, now end with a slash, such as `https://recipe-book.siraj.page/errors/unknown_unit/`, so they open the page without a redirect. ([#1377](https://github.com/SirajChokshi/recipe-book/pull/1377) by [@SirajChokshi](https://github.com/SirajChokshi))
8
+
9
+ - `RecipeBookError` now sets `cause` from its options in browsers whose built-in `Error` ignores them. ([#1217](https://github.com/SirajChokshi/recipe-book/pull/1217) by [@SirajChokshi](https://github.com/SirajChokshi))
10
+
11
+ - In Chrome and Edge before 93, Firefox before 91, and Safari before 15, `error.cause` was `undefined`.
12
+
13
+ - The TSDoc for core's conversion, format, and resolve functions now says which inputs pass through an error thrown by a getter or proxy. ([#1368](https://github.com/SirajChokshi/recipe-book/pull/1368) by [@SirajChokshi](https://github.com/SirajChokshi))
14
+
15
+ - The input and options: `resolveIngredient`, `formatQuantity`, `formatQuantityToParts`, `formatIngredient`, `formatServings`, `formatYield`, and `formatTemperature`.
16
+ - The input: `scaleQuantity`, `convert`, `toSystem`, and `convertTemperature`.
17
+ - The options: `segmentStepText`, `formatDuration`, and `toJsonLd`.
18
+
19
+ - Add `isRecipeValidationError`, which checks whether a caught value is a `RecipeValidationError` and narrows its type, so `issues` needs no cast. ([#1266](https://github.com/SirajChokshi/recipe-book/pull/1266) by [@SirajChokshi](https://github.com/SirajChokshi))
20
+
21
+ - It checks the error's `name`, `code`, and `issues` rather than using `instanceof`, so it also recognizes errors from another installed copy of `@recipe-book/core`, as `isRecipeBookError` does.
22
+
23
+ - Add `ParsedRecipe`, the same type as `Recipe` under another name. ([#924](https://github.com/SirajChokshi/recipe-book/pull/924) by [@SirajChokshi](https://github.com/SirajChokshi))
24
+
25
+ - A file that imports `@recipe-book/react` as `Recipe` can import `ParsedRecipe` from `@recipe-book/react/core` instead of renaming the type with `import type { Recipe as ParsedRecipe }`.
26
+
27
+ - Development warnings and React DevTools name each part as you write it, such as `Recipe.Step`, instead of the name the published build gave it, such as `ForwardRef(Step2)`. ([#1092](https://github.com/SirajChokshi/recipe-book/pull/1092) by [@SirajChokshi](https://github.com/SirajChokshi))
28
+
29
+ - Component stacks in React 18 and 19 use the same names, such as `at Recipe.Step` instead of `at Step2`. The provider is `Recipe.RecipeBookProvider`.
30
+ - Warnings about an `asChild` child, such as one that can't take a ref or children without keys, name `Slot` instead of `ForwardRef(Slot2)`.
31
+ - Production builds leave the names out.
32
+
33
+ - `parseRecipe` and `recipeSchema` now list `duplicate_id` warnings in input order when a repeated section id follows repeated item ids in earlier sections. ([#1221](https://github.com/SirajChokshi/recipe-book/pull/1221) by [@SirajChokshi](https://github.com/SirajChokshi))
34
+
35
+ - Before, when no other issue came between them, the section's warning came before the items' warnings.
36
+
37
+ - The TSDoc for `ResolvedRecipe.servings` and `yield` now says that at a scale within 1e-9 of 1, including one the `servings` option sets, they're the authored servings and yield. ([#1368](https://github.com/SirajChokshi/recipe-book/pull/1368) by [@SirajChokshi](https://github.com/SirajChokshi))
38
+
39
+ - In development, the summary `<Recipe.Root>` logs before its `parse` warnings now links the Issue codes table, which gives the fix for each warning's code. ([#954](https://github.com/SirajChokshi/recipe-book/pull/954) by [@SirajChokshi](https://github.com/SirajChokshi))
40
+
41
+ - The summary now reads: `Recipe Book: "Buttermilk pancakes" has 1 warning. It still renders. https://recipe-book.siraj.page/errors/#issue-codes gives the fix for each warning's code.`
42
+ - Only the text changes, and only in development. If a test matches the old summary, update it.
43
+
44
+ - On React 18, a part with `asChild` no longer makes React warn that function components cannot be given refs when its child is a function component and you pass the part no `ref`. ([#1329](https://github.com/SirajChokshi/recipe-book/pull/1329) by [@SirajChokshi](https://github.com/SirajChokshi))
45
+
46
+ - The arrow keys in `<Recipe.SystemToggle>` now follow the toggle's computed CSS `direction` instead of the nearest `dir` attribute, so Left Arrow and Right Arrow also swap under CSS `direction: rtl` and under `dir="auto"` on right-to-left text, no longer swap under CSS `direction: ltr` inside `dir="rtl"`, and no longer depend on the focused option's own `dir`. ([#1339](https://github.com/SirajChokshi/recipe-book/pull/1339) by [@SirajChokshi](https://github.com/SirajChokshi))
47
+
48
+ - `segmentStepText` no longer reads a "-" right after a number with no unit of its own, or with only a degree sign, as a minus sign. ([#919](https://github.com/SirajChokshi/recipe-book/pull/919) by [@SirajChokshi](https://github.com/SirajChokshi))
49
+
50
+ - In `Bake at 350 -375°F.` and `Bake at 350° -375°F.`, it read the second end as a negative temperature, −375 °F. Such a range now stays text, as `350–375°F` does.
51
+ - After a unit, as in `350°F -375°F`, the "-" is still a minus sign.
52
+
3
53
  ## 0.1.1
4
54
 
5
55
  ### Patch Changes
package/README.md CHANGED
@@ -49,7 +49,7 @@ export function Pancakes() {
49
49
  }
50
50
  ```
51
51
 
52
- Parse where you load the recipe, such as in a Server Component or at build time, so the parser stays out of the browser bundle. [Render a recipe on the server](https://recipe-book.siraj.page/guides/render-a-recipe-on-the-server/) shows how with Next.js and React Router. With Next.js, and with Vite when each page loads as its own chunk, such as a lazy route, a page that parses in the browser with `import { parseRecipe } from '@recipe-book/react/core'` doesn't put the parser on other pages. Otherwise, such as with esbuild's code splitting or with Vite without lazy routes, parse on the server on every page: one page that parses in the browser can put the parser on other pages. Calling `import('@recipe-book/react/core')` can also download it, as [Why parse on the server](https://recipe-book.siraj.page/guides/render-a-recipe-in-react/#why-parse-on-the-server) describes.
52
+ Parse where you load the recipe, such as in a Server Component or at build time, so the parser stays out of the browser bundle. [Render a recipe on the server](https://recipe-book.siraj.page/guides/render-a-recipe-on-the-server/) shows how with the Next.js App Router and Pages Router, React Router, Astro, and your own server. With Next.js, and with Vite when each page loads as its own chunk, such as a lazy route, a page that parses in the browser with `import { parseRecipe } from '@recipe-book/react/core'` doesn't put the parser on other pages. Otherwise, such as with esbuild's code splitting or with Vite without lazy routes, parse on the server on every page: one page that parses in the browser can put the parser on other pages. Calling `import('@recipe-book/react/core')` can also download it, as [Why parse on the server](https://recipe-book.siraj.page/guides/render-a-recipe-in-react/#why-parse-on-the-server) describes.
53
53
 
54
54
  ## Documentation
55
55
 
package/dist/index.cjs CHANGED
@@ -70,6 +70,13 @@ module.exports = __toCommonJS(index_exports);
70
70
  var import_core3 = require("@recipe-book/core");
71
71
  var import_react4 = require("react");
72
72
 
73
+ // src/display-name.ts
74
+ function setDisplayName(component, name) {
75
+ const target = component;
76
+ target.displayName = name;
77
+ Object.defineProperty(target.render ?? component, "name", { value: name });
78
+ }
79
+
73
80
  // src/labels.ts
74
81
  var defaultLabels = {
75
82
  servings: "Servings",
@@ -391,6 +398,9 @@ function useRecipe() {
391
398
  "useRecipe() must be called inside <Recipe.Root>. To use recipe state without a Root, call useRecipeState()."
392
399
  );
393
400
  }
401
+ if (process.env.NODE_ENV !== "production") {
402
+ setDisplayName(RecipeBookProvider, "Recipe.RecipeBookProvider");
403
+ }
394
404
 
395
405
  // src/parts/image.tsx
396
406
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -412,6 +422,9 @@ var Image = /* @__PURE__ */ (0, import_react.forwardRef)(function Image2({
412
422
  }
413
423
  );
414
424
  });
425
+ if (process.env.NODE_ENV !== "production") {
426
+ setDisplayName(Image, "Recipe.Image");
427
+ }
415
428
 
416
429
  // src/parts/ingredients.tsx
417
430
  var import_react12 = require("react");
@@ -456,7 +469,7 @@ var Slot = /* @__PURE__ */ (0, import_react.forwardRef)(function Slot2({ childre
456
469
  }
457
470
  }
458
471
  const childRef = Object.getOwnPropertyDescriptor(child.props, "ref")?.value ?? child.ref;
459
- merged.ref = (0, import_react7.useCallback)(
472
+ const mergedRef = (0, import_react7.useCallback)(
460
473
  (node) => {
461
474
  const refs = [ref, childRef];
462
475
  const cleanups = refs.map((each) => setRef(each, node));
@@ -474,6 +487,9 @@ var Slot = /* @__PURE__ */ (0, import_react.forwardRef)(function Slot2({ childre
474
487
  },
475
488
  [ref, childRef]
476
489
  );
490
+ if (ref != null) {
491
+ merged.ref = mergedRef;
492
+ }
477
493
  return (0, import_react.cloneElement)(child, merged);
478
494
  });
479
495
  function setRef(ref, node) {
@@ -502,6 +518,9 @@ function describeChildren(children) {
502
518
  function isEmpty(children) {
503
519
  return children == null || typeof children === "boolean";
504
520
  }
521
+ if (process.env.NODE_ENV !== "production") {
522
+ setDisplayName(Slot, "Slot");
523
+ }
505
524
 
506
525
  // src/use-format-ingredient.ts
507
526
  var import_core4 = require("@recipe-book/core");
@@ -636,9 +655,6 @@ function ingredientText(name, attribute, read) {
636
655
  text
637
656
  ] }) : (0, import_react.cloneElement)(child, void 0, child.props.children, text) });
638
657
  }
639
- if (process.env.NODE_ENV !== "production") {
640
- Object.defineProperty(IngredientText, "name", { value: name });
641
- }
642
658
  return (0, import_react.forwardRef)(IngredientText);
643
659
  }
644
660
  var IngredientQuantity = /* @__PURE__ */ ingredientText(
@@ -690,6 +706,15 @@ var IngredientOptional = /* @__PURE__ */ ingredientText(
690
706
  // An empty label shows only the part's own children, such as an icon.
691
707
  ({ optional }, children) => optional === "" && isEmpty(children) ? void 0 : optional
692
708
  );
709
+ if (process.env.NODE_ENV !== "production") {
710
+ setDisplayName(Ingredients, "Recipe.Ingredients");
711
+ setDisplayName(IngredientList, "Recipe.IngredientList");
712
+ setDisplayName(Ingredient, "Recipe.Ingredient");
713
+ setDisplayName(IngredientQuantity, "Recipe.IngredientQuantity");
714
+ setDisplayName(IngredientName, "Recipe.IngredientName");
715
+ setDisplayName(IngredientNote, "Recipe.IngredientNote");
716
+ setDisplayName(IngredientOptional, "Recipe.IngredientOptional");
717
+ }
693
718
 
694
719
  // src/parts/json-ld.tsx
695
720
  var import_schema_org = require("@recipe-book/core/schema-org");
@@ -742,6 +767,9 @@ function useWarningsReport(name, warnings) {
742
767
  reported.current = key;
743
768
  }, [name, warnings]);
744
769
  }
770
+ if (process.env.NODE_ENV !== "production") {
771
+ setDisplayName(JsonLd, "Recipe.JsonLd");
772
+ }
745
773
 
746
774
  // src/parts/root.tsx
747
775
  var import_react16 = require("react");
@@ -803,7 +831,7 @@ function useParseReport(result) {
803
831
  if (result.success) {
804
832
  const count = result.warnings.length;
805
833
  console.warn(
806
- `Recipe Book: ${quote(result.data.name)} has ${count} ${count === 1 ? "warning" : "warnings"}. It still renders, but a warning can mean a misspelled field.`,
834
+ `Recipe Book: ${quote(result.data.name)} has ${count} ${count === 1 ? "warning" : "warnings"}. It still renders. https://recipe-book.siraj.page/errors/#issue-codes gives the fix for each warning's code.`,
807
835
  result.warnings
808
836
  );
809
837
  } else {
@@ -811,6 +839,9 @@ function useParseReport(result) {
811
839
  }
812
840
  }, [result]);
813
841
  }
842
+ if (process.env.NODE_ENV !== "production") {
843
+ setDisplayName(Root, "Recipe.Root");
844
+ }
814
845
 
815
846
  // src/parts/servings.tsx
816
847
  var import_core5 = require("@recipe-book/core");
@@ -933,6 +964,10 @@ function optionText(choice, { servings, yield: makes }, base, labels, locale) {
933
964
  }
934
965
  return `${(0, import_core5.formatServings)({ amount: choice }, format)}\xD7`;
935
966
  }
967
+ if (process.env.NODE_ENV !== "production") {
968
+ setDisplayName(ServingsSelect, "Recipe.ServingsSelect");
969
+ setDisplayName(ServingsInput, "Recipe.ServingsInput");
970
+ }
936
971
 
937
972
  // src/parts/step-text.tsx
938
973
  var import_core6 = require("@recipe-book/core");
@@ -991,9 +1026,15 @@ var StepName = /* @__PURE__ */ (0, import_react.forwardRef)(
991
1026
  StepContext,
992
1027
  "<Recipe.StepName> must be rendered inside <Recipe.Step>."
993
1028
  );
994
- return step.name === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("b", { ...props, "data-recipe-name": "", ref, children: step.name });
1029
+ return step.name !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("b", { ...props, "data-recipe-name": "", ref, children: step.name });
995
1030
  }
996
1031
  );
1032
+ if (process.env.NODE_ENV !== "production") {
1033
+ setDisplayName(Steps, "Recipe.Steps");
1034
+ setDisplayName(StepList, "Recipe.StepList");
1035
+ setDisplayName(Step, "Recipe.Step");
1036
+ setDisplayName(StepName, "Recipe.StepName");
1037
+ }
997
1038
 
998
1039
  // src/parts/step-text.tsx
999
1040
  var import_jsx_runtime9 = require("react/jsx-runtime");
@@ -1026,6 +1067,9 @@ function Temperature({ segment }) {
1026
1067
  }) + (fan && labels.fan ? ` ${labels.fan}` : "");
1027
1068
  }).filter(Boolean).join(" / ") });
1028
1069
  }
1070
+ if (process.env.NODE_ENV !== "production") {
1071
+ setDisplayName(StepText, "Recipe.StepText");
1072
+ }
1029
1073
 
1030
1074
  // src/parts/system-toggle.tsx
1031
1075
  var import_react22 = require("react");
@@ -1145,6 +1189,10 @@ function moveOnArrowKey(event) {
1145
1189
  if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
1146
1190
  return;
1147
1191
  }
1192
+ const group = event.currentTarget.closest("[data-recipe-system-toggle]");
1193
+ if (group === null) {
1194
+ return;
1195
+ }
1148
1196
  const { key } = event;
1149
1197
  let step;
1150
1198
  if (key === "ArrowDown") {
@@ -1152,17 +1200,16 @@ function moveOnArrowKey(event) {
1152
1200
  } else if (key === "ArrowUp") {
1153
1201
  step = -1;
1154
1202
  } else if (key === "ArrowRight") {
1155
- step = isRtl(event.currentTarget) ? -1 : 1;
1203
+ step = isRtl(group) ? -1 : 1;
1156
1204
  } else if (key === "ArrowLeft") {
1157
- step = isRtl(event.currentTarget) ? 1 : -1;
1205
+ step = isRtl(group) ? 1 : -1;
1158
1206
  } else {
1159
1207
  return;
1160
1208
  }
1161
- const group = event.currentTarget.closest("[data-recipe-system-toggle]");
1162
1209
  const options = Array.from(
1163
- group?.querySelectorAll(
1210
+ group.querySelectorAll(
1164
1211
  "[data-recipe-system-option]:not([data-disabled])"
1165
- ) ?? []
1212
+ )
1166
1213
  );
1167
1214
  const index = options.indexOf(event.currentTarget);
1168
1215
  if (index === -1) {
@@ -1174,7 +1221,11 @@ function moveOnArrowKey(event) {
1174
1221
  next?.click();
1175
1222
  }
1176
1223
  function isRtl(element) {
1177
- return element.closest("[dir]")?.getAttribute("dir")?.toLowerCase() === "rtl";
1224
+ return getComputedStyle(element).direction === "rtl";
1225
+ }
1226
+ if (process.env.NODE_ENV !== "production") {
1227
+ setDisplayName(SystemToggle, "Recipe.SystemToggle");
1228
+ setDisplayName(SystemOption, "Recipe.SystemOption");
1178
1229
  }
1179
1230
  // Annotate the CommonJS export names for ESM import in node:
1180
1231
  0 && (module.exports = {