@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 +50 -0
- package/README.md +1 -1
- package/dist/index.cjs +63 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -12
- package/dist/index.d.ts +16 -12
- package/dist/index.js +63 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
1203
|
+
step = isRtl(group) ? -1 : 1;
|
|
1156
1204
|
} else if (key === "ArrowLeft") {
|
|
1157
|
-
step = isRtl(
|
|
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
|
|
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.
|
|
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 = {
|