@terrafirmagreg-team/recipe 0.1.0 → 1.2.0

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
@@ -1,6 +1,13 @@
1
1
  'use client';
2
2
 
3
- import { memo, useCallback, useRef, useState } from 'react';
3
+ import {
4
+ memo,
5
+ useCallback,
6
+ useEffect,
7
+ useMemo,
8
+ useRef,
9
+ useState,
10
+ } from 'react';
4
11
  import {
5
12
  ReactFlowProvider,
6
13
  useReactFlow,
@@ -22,55 +29,83 @@ import { CalcEdge } from '@terrafirmagreg-team/recipe/components/views/calc/edge
22
29
  import { CalcSessionProvider } from '@terrafirmagreg-team/recipe/hooks/calc/use-session';
23
30
  import { CalcFarProvider } from '@terrafirmagreg-team/recipe/hooks/calc/use-far-mode';
24
31
  import { CalcTierProvider } from '@terrafirmagreg-team/recipe/hooks/calc/use-tier';
25
- import { useFlowPickers } from '@terrafirmagreg-team/recipe/hooks/calc/flow/pickers';
26
- import { useFlowLayout } from '@terrafirmagreg-team/recipe/hooks/calc/flow/layout';
27
- import { useFlowNodes } from '@terrafirmagreg-team/recipe/hooks/calc/flow/nodes';
28
- import { useFlowViewport } from '@terrafirmagreg-team/recipe/hooks/calc/flow/viewport';
32
+ import { useFlowPickers } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-pickers';
33
+ import { useFlowLayout } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-layout';
34
+ import { useFlowNodes } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-nodes';
35
+ import { useFlowViewport } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-viewport';
29
36
  import { CalcToolbar } from '@terrafirmagreg-team/recipe/components/views/calc/flow/toolbar';
30
37
  import { CalcPickers } from '@terrafirmagreg-team/recipe/components/views/calc/flow/picker-dialogs';
31
- import { useFlowHandlers } from '@terrafirmagreg-team/recipe/hooks/calc/flow/handlers';
32
- import type { CalcFlowProps } from '@terrafirmagreg-team/recipe/hooks/calc/flow/props';
38
+ import { useFlowHandlers } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-handlers';
39
+ import type { CalcFlowProps } from '@terrafirmagreg-team/recipe/types/calc-flow-props';
33
40
 
34
41
  const nodeTypes = { calcMaterial: CalcNodeCard };
35
42
  const edgeTypes = { calcEdge: CalcEdge };
36
43
  const EMPTY_FLOW: AnyCalcFlowNode[] = [];
37
44
  const EMPTY_EDGES: Edge[] = [];
38
45
 
46
+ function useShiftHeld() {
47
+ const [held, setHeld] = useState(false);
48
+ useEffect(() => {
49
+ const down = (e: KeyboardEvent) => {
50
+ if (e.key === 'Shift') setHeld(true);
51
+ };
52
+ const up = (e: KeyboardEvent) => {
53
+ if (e.key === 'Shift') setHeld(false);
54
+ };
55
+ const blur = () => setHeld(false);
56
+ window.addEventListener('keydown', down);
57
+ window.addEventListener('keyup', up);
58
+ window.addEventListener('blur', blur);
59
+ return () => {
60
+ window.removeEventListener('keydown', down);
61
+ window.removeEventListener('keyup', up);
62
+ window.removeEventListener('blur', blur);
63
+ };
64
+ }, []);
65
+ return held;
66
+ }
67
+
39
68
  function CalcFlowInner({
40
- goals,
69
+ nodes: schemeNodes,
70
+ wires,
71
+ flows,
72
+ cards,
41
73
  dataset,
42
74
  session,
43
75
  data,
44
76
  mode,
45
77
  onModeChange,
46
- direction,
47
- onDirectionChange,
48
- edgeStyle,
49
- onEdgeStyleChange,
50
78
  farCards,
51
79
  onFarCardsChange,
52
- density,
53
- onDensityChange,
54
80
  treeReady = true,
55
81
  resetGen = 0,
56
82
  canvasId,
57
83
  actions,
58
- panel,
59
84
  empty,
60
85
  focusRef,
61
86
  focusNodeId,
62
87
  onFocusedNode,
88
+ onRelayout,
63
89
  }: CalcFlowProps) {
64
90
  const t = useTranslations();
65
91
  const { zoomIn, zoomOut } = useReactFlow();
92
+ const shiftHeld = useShiftHeld();
66
93
  const {
67
94
  pickerNode,
68
95
  setPickerNode,
69
96
  memberNode,
70
97
  setMemberNode,
98
+ supply,
99
+ setSupply,
71
100
  onRequestPicker,
72
101
  onRequestMemberPicker,
73
- } = useFlowPickers(goals);
102
+ onRequestSupply,
103
+ } = useFlowPickers(schemeNodes);
104
+
105
+ const flowData = useMemo(
106
+ () => ({ ...data, onRequestSupply }),
107
+ [data, onRequestSupply],
108
+ );
74
109
 
75
110
  const tier = useStore((s) =>
76
111
  s.transform[2] < CALC_LOD_DOT
@@ -79,18 +114,17 @@ function CalcFlowInner({
79
114
  ? ('far' as const)
80
115
  : ('near' as const),
81
116
  );
82
- const { rawFlow, layout, layoutKey, positioned, shift, resetLayout } =
83
- useFlowLayout({
84
- goals,
85
- data,
86
- mode,
87
- direction,
88
- density,
89
- edgeStyle,
90
- treeReady,
91
- onRequestPicker,
92
- onRequestMemberPicker,
93
- });
117
+ const { rawFlow, positioned, relayout } = useFlowLayout({
118
+ nodes: schemeNodes,
119
+ wires,
120
+ flows,
121
+ cards,
122
+ data,
123
+ mode,
124
+ onRequestPicker,
125
+ onRequestMemberPicker,
126
+ onRequestSupply,
127
+ });
94
128
  const focusIdRef = useRef<string | null>(null);
95
129
  const [focusId, setFocusId] = useState<string | null>(null);
96
130
  const applyFocus = useCallback((id: string | null) => {
@@ -104,22 +138,18 @@ function CalcFlowInner({
104
138
  edges,
105
139
  mergedFlow,
106
140
  extraRects,
107
- movedNodes,
108
- clearMoved,
109
- setMovedNodes,
110
141
  onNodesChange,
142
+ onEdgesChange,
111
143
  applyEngaged,
112
144
  resetNodes,
113
145
  } = useFlowNodes({
114
146
  positioned,
115
- shift,
116
- data,
147
+ shift: null,
148
+ data: flowData,
117
149
  focusId,
118
150
  focusIdRef,
119
151
  rawFlow,
120
152
  mode,
121
- direction,
122
- edgeStyle,
123
153
  canvasId,
124
154
  });
125
155
  const {
@@ -129,16 +159,11 @@ function CalcFlowInner({
129
159
  viewportConfig,
130
160
  shellProps,
131
161
  } = useFlowViewport({
132
- goals,
133
162
  mergedNodes: mergedFlow.nodes,
134
163
  dataset,
135
- direction,
136
164
  resetGen,
137
165
  treeReady,
138
- layoutKey,
139
- layout,
140
166
  mode,
141
- density,
142
167
  applyFocus,
143
168
  focusSeqRef,
144
169
  focusRef,
@@ -150,10 +175,10 @@ function CalcFlowInner({
150
175
  const [prevCanvasId, setPrevCanvasId] = useState(canvasId);
151
176
  if (prevCanvasId !== canvasId) {
152
177
  setPrevCanvasId(canvasId);
153
- resetLayout();
154
178
  resetNodes();
155
179
  setPickerNode(null);
156
180
  setMemberNode(null);
181
+ setSupply(null);
157
182
  }
158
183
 
159
184
  const {
@@ -164,17 +189,24 @@ function CalcFlowInner({
164
189
  handlePaneClick,
165
190
  handleDragOver,
166
191
  handleDrop,
192
+ handleConnect,
193
+ handleReconnect,
194
+ handleEdgesDelete,
195
+ handleEdgeClick,
167
196
  fitRecipeNodes,
168
197
  } = useFlowHandlers({
169
- data,
198
+ data: flowData,
170
199
  applyFocus,
171
200
  applyEngaged,
172
201
  centerOnNode,
173
202
  setPickerNode,
174
- setMovedNodes,
175
203
  });
176
204
  const closePicker = useCallback(() => setPickerNode(null), [setPickerNode]);
177
205
  const closeMember = useCallback(() => setMemberNode(null), [setMemberNode]);
206
+ const closeSupply = useCallback(() => setSupply(null), [setSupply]);
207
+ const runRelayout = useCallback(() => {
208
+ onRelayout?.(relayout());
209
+ }, [onRelayout, relayout]);
178
210
 
179
211
  return (
180
212
  <CalcSessionProvider value={session}>
@@ -185,6 +217,7 @@ function CalcFlowInner({
185
217
  className={cn(
186
218
  'calc-flow h-full min-h-0 flex-1',
187
219
  tier === 'dot' && 'calc-flow--dots',
220
+ shiftHeld && 'calc-flow--shift',
188
221
  )}
189
222
 
190
223
  nodes={tier === 'dot' ? EMPTY_FLOW : nodes}
@@ -199,10 +232,20 @@ function CalcFlowInner({
199
232
  onNodeDoubleClick={handleNodeDoubleClick}
200
233
  onPaneClick={handlePaneClick}
201
234
  onNodesChange={onNodesChange}
235
+ onEdgesChange={onEdgesChange}
202
236
  onMoveStart={handleMoveStart}
203
237
  onDragOver={handleDragOver}
204
238
  onDrop={handleDrop}
239
+ onConnect={handleConnect}
240
+ onReconnect={handleReconnect}
241
+ edgesReconnectable={tier === 'near'}
242
+ onEdgeClick={handleEdgeClick}
243
+ onEdgesDelete={handleEdgesDelete}
244
+ deleteKeyCode={['Backspace', 'Delete']}
205
245
  nodesDraggable={tier !== 'dot'}
246
+ nodesConnectable={tier === 'near'}
247
+ selectionKeyCode="Shift"
248
+ multiSelectionKeyCode={['Meta', 'Control']}
206
249
  onlyRenderVisibleElements
207
250
  minZoom={0.02}
208
251
  viewportConfig={viewportConfig}
@@ -214,27 +257,19 @@ function CalcFlowInner({
214
257
  ) : null}
215
258
  <CalcToolbar
216
259
  onFit={onFit}
217
- moved={Boolean(movedNodes?.size)}
218
- onRelayout={clearMoved}
260
+ onRelayout={runRelayout}
219
261
  onZoomIn={() => void zoomIn({ duration: 150 })}
220
262
  onZoomOut={() => void zoomOut({ duration: 150 })}
221
263
  actions={actions}
222
264
  mode={mode}
223
265
  onModeChange={onModeChange}
224
- direction={direction}
225
- onDirectionChange={onDirectionChange}
226
- edgeStyle={edgeStyle}
227
- onEdgeStyleChange={onEdgeStyleChange}
228
266
  farCards={farCards}
229
267
  onFarCardsChange={onFarCardsChange}
230
- density={density}
231
- onDensityChange={onDensityChange}
232
268
  />
233
- {panel}
234
- {goals.length ? (
269
+ {schemeNodes.length ? (
235
270
  ready ? null : (
236
271
  <div className="pointer-events-none absolute inset-x-0 bottom-4 z-10 flex justify-center">
237
- <EmptyState variant="loading">{t('recipe.loading')}</EmptyState>
272
+ <EmptyState variant="loading">{t('Loading recipe…', { note: 'recipe.loading' })}</EmptyState>
238
273
  </div>
239
274
  )
240
275
  ) : (
@@ -246,11 +281,13 @@ function CalcFlowInner({
246
281
  <CalcPickers
247
282
  pickerNode={pickerNode}
248
283
  memberNode={memberNode}
284
+ supply={supply}
249
285
  session={session}
250
286
  dataset={dataset}
251
287
  data={data}
252
288
  onClosePicker={closePicker}
253
289
  onCloseMember={closeMember}
290
+ onCloseSupply={closeSupply}
254
291
  />
255
292
  </CalcTierProvider>
256
293
  </CalcFarProvider>
@@ -265,3 +302,4 @@ export const CalcFlow = memo(function CalcFlow(props: CalcFlowProps) {
265
302
  </ReactFlowProvider>
266
303
  );
267
304
  });
305
+
@@ -1,30 +1,102 @@
1
1
  'use client';
2
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
2
3
 
4
+ import { Mountain } from 'lucide-react';
5
+ import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
6
+ import { Button } from '@terrafirmagreg-team/ui/components/ui/button';
3
7
  import { CalcRecipePicker } from '@terrafirmagreg-team/recipe/components/views/calc/recipe-picker';
4
8
  import { CalcMemberPicker } from '@terrafirmagreg-team/recipe/components/views/calc/member-picker';
5
9
  import type { CalcFlowData } from '@terrafirmagreg-team/recipe/lib/calc/flow';
10
+ import type { SupplyRequest } from '@terrafirmagreg-team/recipe/hooks/calc/flow/use-pickers';
6
11
  import type { RecipeSession } from '@terrafirmagreg-team/recipe/types';
7
12
  import type { CalcNode } from '@terrafirmagreg-team/recipe/types/calc';
8
13
 
14
+ function SupplyPicker({
15
+ supply,
16
+ session,
17
+ data,
18
+ onClose,
19
+ }: {
20
+ supply: SupplyRequest;
21
+ session: RecipeSession;
22
+ data: Omit<
23
+ CalcFlowData,
24
+ 'node' | 'mode' | 'onRequestPicker' | 'onRequestMemberPicker' | 'onRequestSupply'
25
+ >;
26
+ onClose: () => void;
27
+ }) {
28
+ const t = useTranslations();
29
+ const { node, input } = supply;
30
+ const slot = node.inputs[input];
31
+ if (!slot?.id) return null;
32
+ const materialId = slot.id;
33
+ const recipes = data.getRecipesForItem(materialId, slot.kind);
34
+ const supplyNode: CalcNode = {
35
+ ...node,
36
+ materialId,
37
+ kind: slot.kind,
38
+ recipe: null,
39
+ availableRecipes: recipes,
40
+ tagId: undefined,
41
+ members: undefined,
42
+ inputs: [],
43
+ };
44
+ return (
45
+ <CalcRecipePicker
46
+ open
47
+ onOpenChange={(open) => {
48
+ if (!open) onClose();
49
+ }}
50
+ node={supplyNode}
51
+ session={session}
52
+ onSelectRecipe={(_cardId, recipeId) => {
53
+ const row = recipes.find((r) => r.recipeId === recipeId);
54
+ data.onSupplyInput(node.id, input, recipeId, row?.outputAmount);
55
+ }}
56
+ onSelectTagMember={data.onSelectTagMember}
57
+ recipeDefaults={data.recipeDefaults}
58
+ onSetRecipeDefault={data.onSetRecipeDefault}
59
+ actions={
60
+ <Button
61
+ size="xs"
62
+ variant="outline"
63
+ className={supplyNode.availableRecipes.length ? 'shrink-0' : 'ms-auto shrink-0'}
64
+ onClick={() => {
65
+ data.onSupplyInput(node.id, input, null);
66
+ onClose();
67
+ }}
68
+ >
69
+ <Mountain className="size-3.5" />
70
+ {t('Keep as external source', { note: 'recipe.calc.supply.source' })}
71
+ </Button>
72
+ }
73
+ />
74
+ );
75
+ }
76
+
9
77
  export function CalcPickers({
10
78
  pickerNode,
11
79
  memberNode,
80
+ supply,
12
81
  session,
13
82
  dataset,
14
83
  data,
15
84
  onClosePicker,
16
85
  onCloseMember,
86
+ onCloseSupply,
17
87
  }: {
18
88
  pickerNode: CalcNode | null;
19
89
  memberNode: CalcNode | null;
90
+ supply: SupplyRequest | null;
20
91
  session: RecipeSession;
21
- dataset: string;
92
+ dataset: DatasetRef;
22
93
  data: Omit<
23
94
  CalcFlowData,
24
- 'node' | 'mode' | 'direction' | 'onRequestPicker' | 'onRequestMemberPicker'
95
+ 'node' | 'mode' | 'onRequestPicker' | 'onRequestMemberPicker' | 'onRequestSupply'
25
96
  >;
26
97
  onClosePicker: () => void;
27
98
  onCloseMember: () => void;
99
+ onCloseSupply: () => void;
28
100
  }) {
29
101
  return (
30
102
  <>
@@ -37,10 +109,7 @@ export function CalcPickers({
37
109
  node={pickerNode}
38
110
  session={session}
39
111
  onSelectRecipe={(_materialId, recipeId) =>
40
- data.onSelectRecipe(
41
- pickerNode.path ?? pickerNode.materialId,
42
- recipeId,
43
- )
112
+ data.onSelectRecipe(pickerNode.id, recipeId)
44
113
  }
45
114
  onSelectTagMember={data.onSelectTagMember}
46
115
  recipeDefaults={data.recipeDefaults}
@@ -63,6 +132,15 @@ export function CalcPickers({
63
132
  onSelect={data.onSelectTagMember}
64
133
  />
65
134
  ) : null}
135
+ {supply ? (
136
+ <SupplyPicker
137
+ supply={supply}
138
+ session={session}
139
+ data={data}
140
+ onClose={onCloseSupply}
141
+ />
142
+ ) : null}
66
143
  </>
67
144
  );
68
145
  }
146
+
@@ -10,16 +10,12 @@ import {
10
10
  import { IconButton } from '@terrafirmagreg-team/ui/components/blocks/button/icon-button';
11
11
  import { CalcViewMenu } from './view-menu';
12
12
  import type {
13
- CalcDensity,
14
- CalcDirection,
15
- CalcEdgeStyle,
16
13
  CalcFarMode,
17
14
  CalcViewMode,
18
15
  } from '@terrafirmagreg-team/recipe/lib/calc/flow';
19
16
 
20
17
  export function CalcToolbar({
21
18
  onFit,
22
- moved,
23
19
  onRelayout,
24
20
  onZoomIn,
25
21
  onZoomOut,
@@ -27,21 +23,14 @@ export function CalcToolbar({
27
23
  ...view
28
24
  }: {
29
25
  onFit: () => void;
30
- moved: boolean;
31
26
  onRelayout: () => void;
32
27
  onZoomIn: () => void;
33
28
  onZoomOut: () => void;
34
29
  actions?: ReactNode;
35
30
  mode: CalcViewMode;
36
31
  onModeChange: (mode: CalcViewMode) => void;
37
- direction: CalcDirection;
38
- onDirectionChange: (direction: CalcDirection) => void;
39
- edgeStyle: CalcEdgeStyle;
40
- onEdgeStyleChange: (style: CalcEdgeStyle) => void;
41
32
  farCards: CalcFarMode;
42
33
  onFarCardsChange: (mode: CalcFarMode) => void;
43
- density: CalcDensity;
44
- onDensityChange: (density: CalcDensity) => void;
45
34
  }) {
46
35
  const t = useTranslations();
47
36
  return (
@@ -49,16 +38,14 @@ export function CalcToolbar({
49
38
  <ViewerControls
50
39
  start={[
51
40
  <CalcViewMenu key="view" {...view} />,
52
- moved ? (
53
- <IconButton
54
- key="relayout"
55
- overlay
56
- label={t('recipe.calc.relayout')}
57
- onClick={onRelayout}
58
- >
59
- <RotateCcw className="size-3.5" />
60
- </IconButton>
61
- ) : null,
41
+ <IconButton
42
+ key="relayout"
43
+ overlay
44
+ label={t('Auto layout', { note: 'recipe.calc.relayout' })}
45
+ onClick={onRelayout}
46
+ >
47
+ <RotateCcw className="size-3.5" />
48
+ </IconButton>,
62
49
  ]}
63
50
  zoom={{
64
51
  onZoomIn,
@@ -70,3 +57,4 @@ export function CalcToolbar({
70
57
  </ViewerToolbar>
71
58
  );
72
59
  }
60
+