@terrafirmagreg-team/recipe 0.1.0 → 1.2.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 (240) hide show
  1. package/package.json +16 -16
  2. package/src/components/button-copy.tsx +1 -0
  3. package/src/components/cards/card/index.tsx +5 -3
  4. package/src/components/cards/card/scene.tsx +4 -2
  5. package/src/components/cards/card/strip.tsx +4 -2
  6. package/src/components/cards/card/text.tsx +2 -1
  7. package/src/components/cards/card/tips.tsx +1 -0
  8. package/src/components/cards/default-item.tsx +6 -2
  9. package/src/components/cards/glare-filter.tsx +1 -0
  10. package/src/components/cards/paged-card.tsx +1 -0
  11. package/src/components/cards/slot-hitbox.tsx +4 -2
  12. package/src/components/cards/strip-card/buttons.tsx +7 -2
  13. package/src/components/cards/strip-card/index.tsx +3 -1
  14. package/src/components/cards/strip-card/member-cell.tsx +4 -2
  15. package/src/components/cards/strip-card/sprite.tsx +1 -0
  16. package/src/components/embed-card.tsx +44 -0
  17. package/src/components/mdx/recipe.tsx +34 -16
  18. package/src/components/tool-list.tsx +1 -0
  19. package/src/{lib/tree.ts → components/tree.tsx} +20 -12
  20. package/src/components/views/alloy/index.tsx +14 -7
  21. package/src/components/views/alloy/list.tsx +3 -2
  22. package/src/components/views/alloy/mix/index.tsx +1 -0
  23. package/src/components/views/alloy/mix/ratio.tsx +7 -6
  24. package/src/components/views/alloy/mix/rows.tsx +6 -7
  25. package/src/components/views/alloy/mix/status.tsx +8 -7
  26. package/src/components/views/alloy/mix/total.tsx +13 -12
  27. package/src/components/views/alloy/range-bar.tsx +2 -1
  28. package/src/components/views/alloy/stack-bar.tsx +4 -2
  29. package/src/components/views/browser/axis-switcher.tsx +13 -12
  30. package/src/components/views/browser/card-grid.tsx +2 -1
  31. package/src/components/views/browser/favorite-button.tsx +2 -1
  32. package/src/components/views/browser/frame.tsx +3 -2
  33. package/src/components/views/browser/index.tsx +20 -2
  34. package/src/components/views/browser/item-panel/index.tsx +11 -9
  35. package/src/components/views/browser/item-panel/skeleton.tsx +1 -0
  36. package/src/components/views/browser/item-panel-grid/cell.tsx +5 -3
  37. package/src/components/views/browser/item-panel-grid/favorite-cell.tsx +4 -2
  38. package/src/components/views/browser/item-panel-grid/index.tsx +4 -2
  39. package/src/components/views/browser/item-view/index.tsx +7 -12
  40. package/src/components/views/browser/item-view/tags.tsx +7 -5
  41. package/src/components/views/browser/item-view-header.tsx +10 -9
  42. package/src/components/views/browser/pane-tabs.tsx +1 -0
  43. package/src/components/views/browser/place-header.tsx +4 -3
  44. package/src/components/views/browser/query-controls.tsx +3 -1
  45. package/src/components/views/browser/recipe-item-header.tsx +5 -4
  46. package/src/components/views/browser/settings.tsx +4 -3
  47. package/src/components/views/browser/toolbar.tsx +3 -2
  48. package/src/components/views/browser/type-tabs.tsx +5 -3
  49. package/src/components/views/browser/type-view.tsx +7 -12
  50. package/src/components/views/browser/workstation-rail.tsx +4 -3
  51. package/src/components/views/calc/calculator/actions.tsx +4 -14
  52. package/src/components/views/calc/calculator/help.tsx +69 -28
  53. package/src/components/views/calc/calculator/index.tsx +34 -82
  54. package/src/components/views/calc/dot-overlay.tsx +1 -0
  55. package/src/components/views/calc/edge.tsx +134 -32
  56. package/src/components/views/calc/flow/index.tsx +92 -54
  57. package/src/components/views/calc/flow/picker-dialogs.tsx +84 -6
  58. package/src/components/views/calc/flow/toolbar.tsx +9 -21
  59. package/src/components/views/calc/flow/view-menu.tsx +16 -120
  60. package/src/components/views/calc/member-picker.tsx +8 -6
  61. package/src/components/views/calc/node-card/actions.tsx +28 -106
  62. package/src/components/views/calc/node-card/badges.tsx +10 -28
  63. package/src/components/views/calc/node-card/chips.tsx +8 -40
  64. package/src/components/views/calc/node-card/far.tsx +13 -65
  65. package/src/components/views/calc/node-card/full.tsx +133 -83
  66. package/src/components/views/calc/node-card/index.tsx +1 -0
  67. package/src/components/views/calc/node-card/menu.tsx +93 -22
  68. package/src/components/views/calc/node-card/port-cells.tsx +186 -0
  69. package/src/components/views/calc/node-card/port-rails.tsx +251 -0
  70. package/src/components/views/calc/node-card/ports.tsx +86 -0
  71. package/src/components/views/calc/recipe-picker/body.tsx +17 -14
  72. package/src/components/views/calc/recipe-picker/footer.tsx +5 -3
  73. package/src/components/views/calc/recipe-picker/index.tsx +5 -0
  74. package/src/components/views/calc/sidebar.tsx +19 -10
  75. package/src/components/views/calc/trees/icon-picker.tsx +3 -2
  76. package/src/components/views/calc/trees/index.tsx +5 -4
  77. package/src/components/views/calc/trees/label.tsx +6 -4
  78. package/src/components/views/calc/trees/rows.tsx +6 -5
  79. package/src/components/views/forge/gui.tsx +2 -1
  80. package/src/components/views/forge/index.tsx +14 -7
  81. package/src/components/views/forge/list.tsx +3 -2
  82. package/src/components/views/forge/workbench/controls.tsx +13 -6
  83. package/src/components/views/forge/workbench/index.tsx +3 -2
  84. package/src/components/views/forge/workbench/panel.tsx +1 -0
  85. package/src/components/views/forge/workbench/ruler.tsx +5 -4
  86. package/src/components/views/forge/workbench/status.tsx +6 -5
  87. package/src/components/views/forge/workbench/tape.tsx +5 -4
  88. package/src/hooks/alloy/use-fluid-colors.ts +12 -9
  89. package/src/hooks/alloy/use-mix-state.ts +3 -2
  90. package/src/hooks/calc/flow/use-engage.ts +129 -0
  91. package/src/hooks/calc/flow/use-handlers.ts +192 -0
  92. package/src/hooks/calc/flow/use-layout.ts +105 -0
  93. package/src/hooks/calc/flow/{mount.ts → use-mount.ts} +1 -0
  94. package/src/hooks/calc/flow/{nodes.ts → use-nodes.ts} +46 -37
  95. package/src/hooks/calc/flow/use-pickers.ts +57 -0
  96. package/src/hooks/calc/flow/{viewport.ts → use-viewport.ts} +13 -26
  97. package/src/hooks/calc/flow/{window.ts → use-window.ts} +1 -0
  98. package/src/hooks/calc/use-actions.ts +208 -229
  99. package/src/hooks/calc/use-amounts.ts +23 -60
  100. package/src/hooks/calc/use-data.ts +106 -192
  101. package/src/hooks/calc/use-defaults.ts +4 -2
  102. package/src/hooks/calc/use-far-mode.ts +1 -0
  103. package/src/hooks/calc/use-focus.ts +8 -7
  104. package/src/hooks/calc/use-maps.ts +1 -0
  105. package/src/hooks/calc/use-reset.ts +1 -0
  106. package/src/hooks/calc/use-resolver.ts +32 -196
  107. package/src/hooks/calc/use-session.ts +1 -0
  108. package/src/hooks/calc/use-share.ts +5 -2
  109. package/src/hooks/calc/use-storage.ts +5 -4
  110. package/src/hooks/calc/use-tier.ts +1 -0
  111. package/src/hooks/calc/use-view-mode.ts +1 -0
  112. package/src/hooks/calc/use-worker.ts +56 -121
  113. package/src/hooks/forge/use-anvil-gui.ts +4 -2
  114. package/src/hooks/forge/use-forge-state.ts +1 -0
  115. package/src/hooks/forge/use-ruler.ts +1 -0
  116. package/src/hooks/use-add-to-calc.ts +23 -19
  117. package/src/hooks/use-categories-by-id.ts +18 -0
  118. package/src/hooks/use-favorite-hotkey.ts +1 -0
  119. package/src/hooks/use-favorites.ts +1 -0
  120. package/src/hooks/use-group-outlines.ts +1 -0
  121. package/src/hooks/use-hide-unused.ts +2 -1
  122. package/src/hooks/use-index.ts +6 -2
  123. package/src/hooks/use-item-feeds.ts +3 -1
  124. package/src/hooks/use-item-pane.ts +6 -4
  125. package/src/hooks/use-item-press.ts +27 -23
  126. package/src/hooks/use-item-tag-groups.ts +4 -2
  127. package/src/hooks/use-item-tooltips.ts +3 -1
  128. package/src/hooks/use-left-sidebar-tree.ts +11 -3
  129. package/src/hooks/use-mod-names.ts +4 -2
  130. package/src/hooks/use-mount-limit.ts +1 -0
  131. package/src/hooks/use-panel-cells.ts +3 -1
  132. package/src/hooks/use-panel-page.ts +9 -6
  133. package/src/hooks/use-panel-tabs.ts +2 -1
  134. package/src/hooks/use-query.ts +8 -6
  135. package/src/hooks/use-session.ts +6 -2
  136. package/src/hooks/use-sidebar-group.ts +3 -7
  137. package/src/hooks/use-tag-members.ts +3 -1
  138. package/src/hooks/use-tool-recipes.ts +1 -0
  139. package/src/hooks/use-type-filter.ts +1 -0
  140. package/src/lib/alloy/mix.ts +1 -0
  141. package/src/lib/alloy/parse.ts +1 -0
  142. package/src/lib/calc/defaults.ts +6 -4
  143. package/src/lib/calc/flow.ts +143 -107
  144. package/src/lib/calc/focus.ts +1 -0
  145. package/src/lib/calc/meta.ts +3 -1
  146. package/src/lib/calc/pack.ts +47 -154
  147. package/src/lib/calc/ports.ts +43 -0
  148. package/src/lib/calc/resolve.ts +6 -38
  149. package/src/lib/calc/route/buckets.ts +1 -0
  150. package/src/lib/calc/route/geometry.ts +13 -24
  151. package/src/lib/calc/route/index.ts +1 -0
  152. package/src/lib/calc/route/polyline.ts +3 -3
  153. package/src/lib/calc/route/router.ts +181 -57
  154. package/src/lib/calc/scheme.ts +226 -0
  155. package/src/lib/calc/storage/entry.ts +27 -19
  156. package/src/lib/calc/storage/index.ts +2 -0
  157. package/src/lib/calc/storage/keys.ts +4 -8
  158. package/src/lib/calc/storage/store.ts +11 -36
  159. package/src/lib/calc/tree/index.ts +2 -16
  160. package/src/lib/calc/tree/materials.ts +1 -0
  161. package/src/lib/calc/tree/recipe.ts +1 -0
  162. package/src/lib/calc/tree/share.ts +86 -149
  163. package/src/lib/calc/worker/api.ts +3 -11
  164. package/src/lib/calc/worker/fetch.ts +1 -0
  165. package/src/lib/calc/worker/flush.ts +7 -20
  166. package/src/lib/calc/worker/index.ts +1 -1
  167. package/src/lib/calc/worker/protocol.ts +16 -13
  168. package/src/lib/calc/worker/resolve.ts +32 -84
  169. package/src/lib/calc/worker/state.ts +5 -6
  170. package/src/{components/cards/card/model.ts → lib/card-model.ts} +1 -0
  171. package/src/lib/client/recipe-categories.ts +11 -93
  172. package/src/lib/client/recipe.ts +13 -11
  173. package/src/lib/client-index/catalog.ts +33 -27
  174. package/src/lib/client-index/chrome.ts +30 -30
  175. package/src/lib/client-index/index.ts +1 -0
  176. package/src/lib/client-index/registry.ts +70 -59
  177. package/src/lib/client-index/rows.ts +63 -57
  178. package/src/lib/client-index/tooltips.ts +28 -34
  179. package/src/lib/config.ts +2 -1
  180. package/src/lib/data/category/dto.ts +4 -3
  181. package/src/lib/data/category/load.ts +9 -8
  182. package/src/lib/data/category/parse.ts +4 -3
  183. package/src/lib/data/dto.ts +4 -3
  184. package/src/lib/data/grid.ts +2 -1
  185. package/src/lib/data/parse/entry.ts +3 -2
  186. package/src/lib/data/parse/index.ts +1 -0
  187. package/src/lib/data/parse/layout.ts +5 -2
  188. package/src/lib/data/parse/slots.ts +3 -2
  189. package/src/lib/data/parse/widgets.ts +3 -2
  190. package/src/lib/data/scene.ts +1 -1
  191. package/src/lib/data/slot-io.ts +1 -0
  192. package/src/lib/dump.ts +4 -3
  193. package/src/lib/embed.ts +22 -0
  194. package/src/lib/favorite-hover.ts +1 -0
  195. package/src/lib/fluid-outputs.ts +10 -12
  196. package/src/lib/forge/actions.ts +2 -1
  197. package/src/lib/forge/data.ts +2 -1
  198. package/src/lib/forge/solve.ts +1 -0
  199. package/src/lib/group.ts +1 -0
  200. package/src/lib/index-store.ts +15 -9
  201. package/src/lib/links.ts +15 -9
  202. package/src/lib/lookup.ts +10 -8
  203. package/src/lib/panel-outline.ts +1 -0
  204. package/src/lib/panel.ts +3 -2
  205. package/src/lib/preview.ts +12 -8
  206. package/src/lib/recipe-slots.ts +1 -0
  207. package/src/lib/search.ts +1 -0
  208. package/src/lib/sidebar.ts +1 -0
  209. package/src/lib/used-items.ts +1 -0
  210. package/src/locales/en_us.json +170 -226
  211. package/src/locales/ru_ru.json +170 -226
  212. package/src/locales.ts +1 -0
  213. package/src/types/alloy.ts +1 -0
  214. package/src/{hooks/calc/flow/props.ts → types/calc-flow-props.ts} +18 -14
  215. package/src/types/calc.ts +41 -44
  216. package/src/types/forge.ts +1 -0
  217. package/src/types/index.ts +4 -2
  218. package/styles/calc.css +308 -47
  219. package/src/components/cards/fit-card.tsx +0 -26
  220. package/src/components/views/calc/target.tsx +0 -271
  221. package/src/hooks/calc/flow/engage.ts +0 -89
  222. package/src/hooks/calc/flow/handlers.ts +0 -115
  223. package/src/hooks/calc/flow/layout.ts +0 -149
  224. package/src/hooks/calc/flow/pickers.ts +0 -50
  225. package/src/hooks/calc/use-calc-fill.ts +0 -91
  226. package/src/hooks/calc/use-density.ts +0 -28
  227. package/src/hooks/calc/use-derived.ts +0 -258
  228. package/src/hooks/calc/use-direction.ts +0 -23
  229. package/src/hooks/calc/use-edge-style.ts +0 -40
  230. package/src/hooks/calc/use-fill.ts +0 -213
  231. package/src/lib/alloy/alloy.test.ts +0 -186
  232. package/src/lib/calc/tree/build.ts +0 -196
  233. package/src/lib/calc/tree/context.ts +0 -42
  234. package/src/lib/calc/tree/goal.ts +0 -64
  235. package/src/lib/calc/tree/ideal.ts +0 -36
  236. package/src/lib/calc/tree/pick.ts +0 -68
  237. package/src/lib/calc/tree/tree.test.ts +0 -169
  238. package/src/lib/calc/worker/fill.ts +0 -123
  239. package/src/lib/client-index/cache.ts +0 -13
  240. package/src/lib/forge/forge.test.ts +0 -123
@@ -2,34 +2,23 @@
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
4
  import type {
5
- CalcMaterial,
5
+ CalcCard,
6
+ CalcWire,
6
7
  CalculatorState,
7
- CalculatorTarget,
8
8
  } from '@terrafirmagreg-team/recipe/types/calc';
9
9
 
10
- type PendingAmounts = {
11
- target: CalculatorTarget | null;
12
- inventory: CalcMaterial[];
13
- };
14
-
15
10
  export function useCalcAmounts({
16
- target,
17
- inventory,
18
- persist,
19
- selections,
11
+ cards,
12
+ wires,
20
13
  tagSelections,
21
- collapsed,
22
- auto,
14
+ persist,
23
15
  }: {
24
- target: CalculatorTarget | null;
25
- inventory: CalcMaterial[];
26
- persist: (next: CalculatorState) => void;
27
- selections: Record<string, string>;
16
+ cards: CalcCard[];
17
+ wires: CalcWire[];
28
18
  tagSelections: Record<string, string>;
29
- collapsed: string[];
30
- auto: string[];
19
+ persist: (next: CalculatorState) => void;
31
20
  }) {
32
- const [pending, setPending] = useState<PendingAmounts | null>(null);
21
+ const [pending, setPending] = useState<CalcCard[] | null>(null);
33
22
  const amountTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
34
23
 
35
24
  useEffect(
@@ -39,63 +28,37 @@ export function useCalcAmounts({
39
28
  [],
40
29
  );
41
30
 
42
- const flushAmounts = useCallback((): PendingAmounts => {
31
+ const flushAmounts = useCallback((): CalcCard[] => {
43
32
  if (amountTimer.current) {
44
33
  clearTimeout(amountTimer.current);
45
34
  amountTimer.current = undefined;
46
35
  }
47
- if (!pending) return { target, inventory };
36
+ if (!pending) return cards;
48
37
  setPending(null);
49
38
  return pending;
50
- }, [pending, target, inventory]);
39
+ }, [pending, cards]);
51
40
 
52
- const schedule = useCallback(
53
- (next: PendingAmounts) => {
41
+ const onCrafts = useCallback(
42
+ (cardId: string, crafts: number) => {
43
+ const base = pending ?? cards;
44
+ const next = base.map((card) =>
45
+ card.id === cardId ? { ...card, crafts: Math.max(1, crafts) } : card,
46
+ );
54
47
  setPending(next);
55
48
  if (amountTimer.current) clearTimeout(amountTimer.current);
56
49
  amountTimer.current = setTimeout(() => {
57
50
  amountTimer.current = undefined;
58
51
  setPending(null);
59
- persist({
60
- target: next.target,
61
- inventory: next.inventory,
62
- selections,
63
- tagSelections,
64
- collapsed,
65
- auto,
66
- });
52
+ persist({ cards: next, wires, tagSelections });
67
53
  }, 300);
68
54
  },
69
- [persist, selections, tagSelections, collapsed, auto],
70
- );
71
-
72
- const onAmount = useCallback(
73
- (amount: number) => {
74
- const base = pending ?? { target, inventory };
75
- if (!base.target) return;
76
- schedule({ ...base, target: { ...base.target, amount } });
77
- },
78
- [pending, target, inventory, schedule],
79
- );
80
-
81
- const onStockAmount = useCallback(
82
- (index: number, amount: number) => {
83
- const base = pending ?? { target, inventory };
84
- schedule({
85
- ...base,
86
- inventory: base.inventory.map((row, i) =>
87
- i === index ? { ...row, amount } : row,
88
- ),
89
- });
90
- },
91
- [pending, target, inventory, schedule],
55
+ [pending, cards, persist, wires, tagSelections],
92
56
  );
93
57
 
94
58
  return {
95
- displayTarget: pending?.target ?? target,
96
- displayInventory: pending?.inventory ?? inventory,
59
+ displayCards: pending ?? cards,
97
60
  flushAmounts,
98
- onAmount,
99
- onStockAmount,
61
+ onCrafts,
100
62
  };
101
63
  }
64
+
@@ -1,21 +1,23 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useEffect, useMemo, useRef } from 'react';
4
- import { encodeCalcShare } from '@terrafirmagreg-team/recipe/lib/calc/tree';
5
- import { pickAutoRecipe } from '@terrafirmagreg-team/recipe/lib/calc/resolve';
3
+ import { useCallback, useMemo } from 'react';
4
+ import { encodeCalcState } from '@terrafirmagreg-team/recipe/lib/calc/tree';
6
5
  import {
7
- calcStorageKey,
8
- updateCalcTab,
9
- } from '@terrafirmagreg-team/recipe/lib/calc/storage';
6
+ summaryCacheFor,
7
+ summarizeRecipes,
8
+ } from '@terrafirmagreg-team/recipe/lib/calc/resolve';
9
+ import { buildScheme, schemeSummary } from '@terrafirmagreg-team/recipe/lib/calc/scheme';
10
+ import { calcStorageKey } from '@terrafirmagreg-team/recipe/lib/calc/storage';
10
11
  import type { RecipeSession } from '@terrafirmagreg-team/recipe/types';
11
- import type { CalcNode, CalculatorState } from '@terrafirmagreg-team/recipe/types/calc';
12
+ import type {
13
+ CalcKind,
14
+ CalcRecipeSummary,
15
+ } from '@terrafirmagreg-team/recipe/types/calc';
12
16
  import { useCalcStorage } from './use-storage';
13
17
  import { useCalcShare } from './use-share';
14
18
  import { useCalcMaps } from './use-maps';
15
19
  import { useCalcWorker } from './use-worker';
16
- import { useCalcDerived } from './use-derived';
17
20
  import { useCalcResolver } from './use-resolver';
18
- import { useFillTree } from './use-fill';
19
21
  import { useRecipeDefaults } from './use-defaults';
20
22
 
21
23
  export function useCalcData(session: RecipeSession) {
@@ -48,222 +50,130 @@ export function useCalcData(session: RecipeSession) {
48
50
  const {
49
51
  outMap: dataOutMap,
50
52
  recipeMap: dataRecipeMap,
53
+ tagMap: dataTagMap,
51
54
  deadIds: dataDeadIds,
52
55
  } = data;
53
56
 
54
- const selections = useMemo(
55
- () => calcState?.selections ?? {},
56
- [calcState],
57
- );
57
+ const cards = useMemo(() => calcState?.cards ?? [], [calcState]);
58
+ const wires = useMemo(() => calcState?.wires ?? [], [calcState]);
58
59
  const tagSelections = useMemo(
59
60
  () => calcState?.tagSelections ?? {},
60
61
  [calcState],
61
62
  );
62
- const collapsed = useMemo(() => calcState?.collapsed ?? [], [calcState]);
63
- const collapsedSet = useMemo(() => new Set(collapsed), [collapsed]);
64
- const auto = useMemo(() => calcState?.auto ?? [], [calcState]);
65
- const target = useMemo(() => calcState?.target ?? null, [calcState]);
66
- const inventory = useMemo(() => calcState?.inventory ?? [], [calcState]);
67
- const effectiveSelections = useMemo(
68
- () => ({ ...defaults, ...selections }),
69
- [defaults, selections],
63
+
64
+ const getRecipesForItem = useCallback(
65
+ (materialId: string, kind: CalcKind): CalcRecipeSummary[] => {
66
+ if (!catalog) return [];
67
+ return summarizeRecipes(
68
+ dataOutMap,
69
+ dataRecipeMap,
70
+ catalog.types,
71
+ summaryCacheFor(dataOutMap, dataRecipeMap),
72
+ materialId,
73
+ kind,
74
+ );
75
+ },
76
+ [catalog, dataOutMap, dataRecipeMap],
77
+ );
78
+
79
+ const tagMembers = useCallback(
80
+ (tagId: string) => dataTagMap.get(tagId),
81
+ [dataTagMap],
70
82
  );
71
- const inputKey = useMemo(
83
+
84
+ const { nodes, flows } = useMemo(
72
85
  () =>
73
- JSON.stringify([
74
- target,
75
- inventory,
76
- effectiveSelections,
77
- tagSelections,
78
- collapsed,
79
- auto,
80
- ]),
81
- [target, inventory, effectiveSelections, tagSelections, collapsed, auto],
86
+ buildScheme({
87
+ cards,
88
+ wires,
89
+ ctx: {
90
+ recipeMap: dataRecipeMap,
91
+ getRecipesForItem,
92
+ tagMembers,
93
+ tagSelections,
94
+ recipesResolved: (id) => dataOutMap.has(id),
95
+ deadIds: dataDeadIds,
96
+ },
97
+ }),
98
+ [
99
+ cards,
100
+ wires,
101
+ dataRecipeMap,
102
+ getRecipesForItem,
103
+ tagMembers,
104
+ tagSelections,
105
+ dataOutMap,
106
+ dataDeadIds,
107
+ ],
108
+ );
109
+
110
+ const summary = useMemo(() => schemeSummary(nodes), [nodes]);
111
+
112
+ const inputKey = useMemo(
113
+ () => JSON.stringify([cards, wires, tagSelections]),
114
+ [cards, wires, tagSelections],
82
115
  );
83
116
 
84
117
  const worker = useCalcWorker({
85
118
  dataset,
86
119
  catalog,
87
120
  activeTabId,
88
- inputKey,
89
121
  applyMaps,
90
122
  resetMaps,
91
123
  });
92
- const workerDriven = worker.state === 'ready';
93
- const { getRecipesForItem, goals, dataSettled, summary, ideal } =
94
- useCalcDerived({
95
- catalog,
96
- target,
97
- inventory,
98
- auto,
99
- effectiveSelections,
100
- tagSelections,
101
- collapsedSet,
102
- data,
103
- workerDriven,
104
- workerGoals: worker.goals,
105
- workerSummary: worker.summary,
106
- workerSettled: worker.settled,
107
- });
108
- const settled = dataSettled && !sharePending;
109
124
 
110
125
  useCalcResolver({
111
126
  catalog,
112
- dataset,
113
127
  inputKey,
114
- dataSettled,
115
- activeTabId,
116
- target,
117
- inventory,
118
- effectiveSelections,
119
- tagSelections,
120
- collapsed,
121
- collapsedSet,
122
- auto,
123
- maps,
124
- applyMaps,
125
- worker,
126
- });
127
- const fillTree = useFillTree({
128
- catalog,
129
- dataset,
130
- target,
131
- inventory,
132
- effectiveSelections,
133
- tagSelections,
134
- collapsed,
135
- auto,
136
- maps,
137
- applyMaps,
128
+ cards,
129
+ recipeMap: dataRecipeMap,
138
130
  worker,
139
131
  });
140
132
 
141
- const encodeShare = useCallback(
142
- (next?: CalculatorState) => {
143
- const state = next ?? {
144
- target,
145
- inventory,
146
- selections,
147
- tagSelections,
148
- collapsed,
149
- auto,
150
- };
151
- const byPath = new Map<string, CalcNode>();
152
- const nodeAncestors = new Map<CalcNode, ReadonlySet<string>>();
153
- const materials = new Set<string>();
154
- const walk = (n: CalcNode, ancestors: Set<string>): void => {
155
- if (n.path) {
156
- byPath.set(n.path, n);
157
- nodeAncestors.set(n, ancestors);
158
- }
159
- materials.add(n.materialId);
160
- const next =
161
- n.recipe && n.need > 0
162
- ? new Set(ancestors).add(`${n.kind}:${n.materialId}`)
163
- : ancestors;
164
- for (const child of n.children) walk(child, next);
165
- };
166
- for (const goal of goals) walk(goal.node, new Set());
167
- const pins: Record<string, string> = {};
168
- for (const id of materials) {
169
- const pin = effectiveSelections[id];
170
- if (pin) pins[id] = pin;
133
+ const dataSettled = useMemo(() => {
134
+ for (const card of cards) {
135
+ if (!dataOutMap.has(card.materialId)) return false;
136
+ if (
137
+ card.recipeId &&
138
+ !dataRecipeMap.has(card.recipeId) &&
139
+ !dataDeadIds.has(card.recipeId)
140
+ ) {
141
+ return false;
171
142
  }
172
- return encodeCalcShare({
173
- state,
174
- autoRoots: state.auto ?? [],
175
- pins,
176
- livePaths: new Set(byPath.keys()),
177
- derivablePick: (path) => {
178
- const node = byPath.get(path);
179
- if (!node?.auto || !node.availableRecipes.length) return undefined;
180
- return pickAutoRecipe(
181
- node,
182
- effectiveSelections,
183
- nodeAncestors.get(node) ?? new Set(),
184
- {
185
- recipeMap: dataRecipeMap,
186
- getRecipesForItem,
187
- recipesResolved: (id) => dataOutMap.has(id),
188
- deadIds: dataDeadIds,
189
- },
190
- ).pick;
191
- },
192
- });
193
- },
194
- [
195
- goals,
196
- target,
197
- inventory,
198
- selections,
199
- tagSelections,
200
- collapsed,
201
- auto,
202
- effectiveSelections,
203
- dataRecipeMap,
204
- dataOutMap,
205
- dataDeadIds,
206
- getRecipesForItem,
207
- ],
208
- );
209
-
210
- const autoUpgraded = useRef<string | null>(null);
211
- useEffect(() => {
212
- const upgradeKey = `${activeTabId}:${auto.join(',')}`;
213
- if (
214
- autoUpgraded.current === upgradeKey ||
215
- !auto.length ||
216
- !settled ||
217
- !activeTabId
218
- ) {
219
- return;
220
143
  }
221
- autoUpgraded.current = upgradeKey;
222
- const tabId = activeTabId;
223
- void fillTree(auto).then((picked) => {
144
+ return true;
145
+ }, [cards, dataOutMap, dataRecipeMap, dataDeadIds]);
146
+ const settled = dataSettled && !sharePending;
224
147
 
225
- updateCalcTab(storageKey, tabId, (tab) => {
226
- const current = tab.state;
227
- const liveRoot = (path: string) => /^g0(\/|$)/.test(path);
228
- const underRoot = (key: string) =>
229
- auto.some((root) => key === root || key.startsWith(`${root}/`));
230
- return {
231
- ...tab,
232
- savedAt: Date.now(),
233
- state: {
234
- target: current.target,
235
- inventory: current.inventory,
236
- selections: {
237
- ...Object.fromEntries(
238
- Object.entries(current.selections).filter(
239
- ([key]) => !underRoot(key),
240
- ),
241
- ),
242
- ...picked,
243
- },
244
- tagSelections: current.tagSelections,
245
- collapsed: current.collapsed,
246
- auto: [
247
- ...new Set([...(current.auto ?? []), ...auto.filter(liveRoot)]),
248
- ],
249
- },
250
- };
251
- });
252
- });
253
- }, [auto, settled, fillTree, storageKey, activeTabId]);
148
+ const encodeShare = useCallback(
149
+ () =>
150
+ encodeCalcState({
151
+ cards,
152
+ wires,
153
+ tagSelections,
154
+ }),
155
+ [cards, wires, tagSelections],
156
+ );
254
157
 
255
158
  const recipeBody = useCallback(
256
159
  (recipeId: string) => bodyMap.get(recipeId),
257
160
  [bodyMap],
258
161
  );
259
162
 
163
+ const ensureMaterial = useCallback(
164
+ (materialId: string) => {
165
+ if (dataOutMap.has(materialId)) return;
166
+ void worker
167
+ .call((api) => api.resolve({ materials: [materialId] }))
168
+ .catch(() => {});
169
+ },
170
+ [dataOutMap, worker],
171
+ );
172
+
260
173
  return {
261
- target,
262
- inventory,
263
- selections,
174
+ cards,
175
+ wires,
264
176
  tagSelections,
265
- collapsed,
266
- auto,
267
177
  tabs,
268
178
  activeTabId,
269
179
  history,
@@ -276,14 +186,18 @@ export function useCalcData(session: RecipeSession) {
276
186
  removeHistory,
277
187
  recipeDefaults: defaults,
278
188
  setRecipeDefault,
279
- goals,
189
+ getRecipesForItem,
190
+ ensureMaterial,
191
+ tagMembers,
192
+ nodes,
193
+ flows,
280
194
  summary,
281
- ideal,
282
195
  persist,
283
- fillTree,
284
196
  encodeShare,
285
197
  recipeBody,
286
198
  settled,
287
199
  bodiesLoaded: maps.bodyMap.size,
200
+ workerSettled: worker.settled,
288
201
  };
289
202
  }
203
+
@@ -1,4 +1,5 @@
1
1
  'use client';
2
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
2
3
 
3
4
  import { useCallback, useEffect, useState } from 'react';
4
5
  import {
@@ -7,9 +8,9 @@ import {
7
8
  writeRecipeDefault,
8
9
  } from '@terrafirmagreg-team/recipe/lib/calc/defaults';
9
10
 
10
- export function useRecipeDefaults(dataset: string) {
11
+ export function useRecipeDefaults(dataset: DatasetRef) {
11
12
  const [defaultsState, setDefaultsState] = useState<{
12
- dataset: string;
13
+ dataset: DatasetRef;
13
14
  map: Record<string, string>;
14
15
  }>(() => ({ dataset, map: readRecipeDefaults(dataset) }));
15
16
  const defaults =
@@ -36,3 +37,4 @@ export function useRecipeDefaults(dataset: string) {
36
37
 
37
38
  return { defaults, setRecipeDefault };
38
39
  }
40
+
@@ -34,3 +34,4 @@ export function useCalcFarMode() {
34
34
  }, [setStored]);
35
35
  return [mode, setMode] as const;
36
36
  }
37
+
@@ -2,9 +2,9 @@
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
4
  import { onCalcFocusRequest } from '@terrafirmagreg-team/recipe/lib/calc/focus';
5
- import type { CalculatorTarget } from '@terrafirmagreg-team/recipe/types/calc';
5
+ import type { CalcCard } from '@terrafirmagreg-team/recipe/types/calc';
6
6
 
7
- export function useCalcFocus(target: CalculatorTarget | null) {
7
+ export function useCalcFocus(cards: CalcCard[]) {
8
8
  const focusNodeRef = useRef<((materialId: string) => void) | null>(null);
9
9
  const onFocusNode = useCallback(
10
10
  (materialId: string) => focusNodeRef.current?.(materialId),
@@ -13,18 +13,19 @@ export function useCalcFocus(target: CalculatorTarget | null) {
13
13
  const [focusNodeId, setFocusNodeId] = useState<string | null>(null);
14
14
  const [pendingFocus, setPendingFocus] = useState<{
15
15
  id: string;
16
- seen: CalculatorTarget | null;
16
+ seen: CalcCard[];
17
17
  } | null>(null);
18
18
 
19
19
  useEffect(
20
- () => onCalcFocusRequest((id) => setPendingFocus({ id, seen: target })),
21
- [target],
20
+ () => onCalcFocusRequest((id) => setPendingFocus({ id, seen: cards })),
21
+ [cards],
22
22
  );
23
23
 
24
- if (pendingFocus && pendingFocus.seen !== target) {
25
- setFocusNodeId('g0');
24
+ if (pendingFocus && pendingFocus.seen !== cards) {
25
+ setFocusNodeId(cards[cards.length - 1]?.id ?? null);
26
26
  setPendingFocus(null);
27
27
  }
28
28
 
29
29
  return { focusNodeRef, onFocusNode, focusNodeId, setFocusNodeId };
30
30
  }
31
+
@@ -73,3 +73,4 @@ export function useCalcMaps() {
73
73
  resetMaps,
74
74
  };
75
75
  }
76
+
@@ -12,3 +12,4 @@ export function useCalcReset(activeTabId: string | null) {
12
12
  }
13
13
  return { resetGen, setResetGen };
14
14
  }
15
+