@eveshipfit/ui-ingame 1.13.0 → 1.14.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 (3) hide show
  1. package/dist/index.mjs +951 -596
  2. package/dist/style.css +1310 -1254
  3. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import './style.css';
2
2
  import { c } from "react/compiler-runtime";
3
- import { Activity, Fragment, createContext, useContext, useDeferredValue, useEffect, useEffectEvent, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
3
+ import { Activity, Fragment, createContext, useContext, useDeferredValue, useEffect, useEffectEvent, useId, useLayoutEffect, useRef, useState } from "react";
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { UNIFORM, formatAttribute, formatClock, formatDuration, formatNumber, useAttribute, useAttributeTooltip, useBayContents, useBayUsage, useBoosters, useBrowse, useCanFit, useChargeSearch, useChargeTree, useChargedModules, useCharges, useDamageProfiles, useDrag, useDroneRoom, useEngine, useFighterTubeUsage, useFighterTubes, useFit, useFitHistory, useFitPrice, useFitStore, useHardpoints, useHasRoom, useHullRefuses, useHullTree, useImages, useImplantSearch, useImplantTree, useImplants, useInfo, useLocalFits, useMissingSkills, useModes, useModuleSearch, useModuleTree, useMutate, usePersonalFits, usePlacement, usePreview, useRackUsage, useRefusal, useSde, useShowInfo, useShownSnapshot, useSlots, useSnapshot, useStats, useType, useTypeBonuses, useTypePrice } from "@eveshipfit/react-hooks";
6
- import { baseValue, canMutate, mutaplasmidsOf, mutationRanges, mutationRollOf, parseItemLink, parseMutationText, rollFits, rollMutation, squadronSize, tubeTakes } from "@eveshipfit/fitting";
6
+ import { baseValue, canMutate, clampToRange, mutaplasmidsOf, mutatedDronesOf, mutationRanges, mutationRollOf, parseItemLink, parseMutationText, rollFits, rollMutation, squadronSize, tubeTakes, withMutaplasmid } from "@eveshipfit/fitting";
7
7
  // src/primitives/Dialog/Dialog.module.css
8
8
  var Dialog_module_default = {
9
9
  "close": "kwi1cG_close",
@@ -978,7 +978,7 @@ function SlotPress(t0) {
978
978
  className,
979
979
  "aria-label": label,
980
980
  onClick: onPress,
981
- onKeyDown: _temp$23
981
+ onKeyDown: _temp$24
982
982
  });
983
983
  $[0] = className;
984
984
  $[1] = label;
@@ -987,7 +987,7 @@ function SlotPress(t0) {
987
987
  } else t1 = $[3];
988
988
  return t1;
989
989
  }
990
- function _temp$23(event) {
990
+ function _temp$24(event) {
991
991
  if (event.key !== "Enter" && event.key !== " ") return;
992
992
  event.preventDefault();
993
993
  event.currentTarget.dispatchEvent(new MouseEvent("click", {
@@ -1403,7 +1403,7 @@ function useDecoded(src) {
1403
1403
  image.decode().then(() => {
1404
1404
  decoded.add(src);
1405
1405
  setReady(src);
1406
- }, _temp$22);
1406
+ }, _temp$23);
1407
1407
  };
1408
1408
  t1 = [src];
1409
1409
  $[0] = src;
@@ -1423,7 +1423,7 @@ function useDecoded(src) {
1423
1423
  } else t2 = $[5];
1424
1424
  return t2;
1425
1425
  }
1426
- function _temp$22() {}
1426
+ function _temp$23() {}
1427
1427
  function WheelGauge(t0) {
1428
1428
  const $ = c(15);
1429
1429
  const { resource, used, total, valueText } = t0;
@@ -1898,7 +1898,7 @@ function Menu(t0) {
1898
1898
  role: "menu",
1899
1899
  tabIndex: -1,
1900
1900
  onToggle: t4,
1901
- onKeyDown: _temp$21,
1901
+ onKeyDown: _temp$22,
1902
1902
  onClick: stopped,
1903
1903
  onDoubleClick: stopped,
1904
1904
  onPointerDown: stopped,
@@ -1908,6 +1908,7 @@ function Menu(t0) {
1908
1908
  type: "button",
1909
1909
  role: "menuitem",
1910
1910
  tabIndex: -1,
1911
+ disabled: entry.disabled,
1911
1912
  onClick: () => select(entry),
1912
1913
  onPointerMove: _temp3$6,
1913
1914
  children: [/* @__PURE__ */ jsx("span", {
@@ -1929,12 +1930,12 @@ function _temp2$11(event_1) {
1929
1930
  event_1.preventDefault();
1930
1931
  event_1.stopPropagation();
1931
1932
  }
1932
- function _temp$21(event_0) {
1933
+ function _temp$22(event_0) {
1933
1934
  event_0.stopPropagation();
1934
1935
  walk(event_0);
1935
1936
  }
1936
1937
  function walk(event) {
1937
- const items = [...event.currentTarget.querySelectorAll("[role=menuitem]")];
1938
+ const items = [...event.currentTarget.querySelectorAll("[role=menuitem]:enabled")];
1938
1939
  const index = items.indexOf(document.activeElement);
1939
1940
  let next;
1940
1941
  switch (event.key) {
@@ -2827,7 +2828,7 @@ function SensorStrengths(t0) {
2827
2828
  if ($[0] !== strengths) {
2828
2829
  t4 = Symbol.for("react.early_return_sentinel");
2829
2830
  bb0: {
2830
- const shown = strengths.filter(_temp$20);
2831
+ const shown = strengths.filter(_temp$21);
2831
2832
  if (shown.length === 0) {
2832
2833
  t4 = null;
2833
2834
  break bb0;
@@ -2882,7 +2883,7 @@ function _temp2$10(strength) {
2882
2883
  strength.displayName
2883
2884
  ] }, strength.name);
2884
2885
  }
2885
- function _temp$20(t0) {
2886
+ function _temp$21(t0) {
2886
2887
  const { value } = t0;
2887
2888
  return value;
2888
2889
  }
@@ -2929,14 +2930,14 @@ function Cloak(t0) {
2929
2930
  itemRef,
2930
2931
  name: "maxVelocityModifier",
2931
2932
  decimals: 0,
2932
- format: _temp$19
2933
+ format: _temp$20
2933
2934
  });
2934
2935
  $[0] = itemRef;
2935
2936
  $[1] = t1;
2936
2937
  } else t1 = $[1];
2937
2938
  return t1;
2938
2939
  }
2939
- function _temp$19(value, format) {
2940
+ function _temp$20(value, format) {
2940
2941
  return percent$1((value - 1) * 100, format);
2941
2942
  }
2942
2943
  // src/components/FittingWheel/ModuleLines/CommandBonus.tsx
@@ -3683,9 +3684,9 @@ function Resistance$1(t0) {
3683
3684
  /** The resistances a module gives, for every layer. */
3684
3685
  function _temp2$9(t0) {
3685
3686
  const { resistances } = t0;
3686
- return resistances.some(_temp$18);
3687
+ return resistances.some(_temp$19);
3687
3688
  }
3688
- function _temp$18(t0) {
3689
+ function _temp$19(t0) {
3689
3690
  const { value } = t0;
3690
3691
  return value !== 1;
3691
3692
  }
@@ -3892,7 +3893,7 @@ function ResistanceBonus(t0) {
3892
3893
  t3,
3893
3894
  t4,
3894
3895
  t5
3895
- ].filter(_temp$17);
3896
+ ].filter(_temp$18);
3896
3897
  const [first] = bonuses;
3897
3898
  if (first === void 0) {
3898
3899
  t6 = null;
@@ -3942,7 +3943,7 @@ function _temp2$8(t0) {
3942
3943
  text
3943
3944
  }, name);
3944
3945
  }
3945
- function _temp$17(bonus) {
3946
+ function _temp$18(bonus) {
3946
3947
  return bonus.value;
3947
3948
  }
3948
3949
  // src/components/FittingWheel/ModuleLines/SensorBooster.tsx
@@ -4043,14 +4044,14 @@ function SignatureSuppressor(t0) {
4043
4044
  itemRef,
4044
4045
  name: "signatureSuppressorSignatureRadiusBonusPassive",
4045
4046
  decimals: 0,
4046
- format: _temp$16
4047
+ format: _temp$17
4047
4048
  });
4048
4049
  $[0] = itemRef;
4049
4050
  $[1] = t1;
4050
4051
  } else t1 = $[1];
4051
4052
  return t1;
4052
4053
  }
4053
- function _temp$16(value, format) {
4054
+ function _temp$17(value, format) {
4054
4055
  return percent$1((1 - value) * 100, format);
4055
4056
  }
4056
4057
  // src/components/FittingWheel/ModuleLines/Smartbomb.tsx
@@ -4151,7 +4152,7 @@ function StasisWebifier(props) {
4151
4152
  t0 = {
4152
4153
  of: props.itemRef,
4153
4154
  decimals: 0,
4154
- format: _temp$15
4155
+ format: _temp$16
4155
4156
  };
4156
4157
  $[0] = props.itemRef;
4157
4158
  $[1] = t0;
@@ -4181,7 +4182,7 @@ function StasisWebifier(props) {
4181
4182
  } else t3 = $[8];
4182
4183
  return t3;
4183
4184
  }
4184
- function _temp$15(value, format) {
4185
+ function _temp$16(value, format) {
4185
4186
  return percent$1(-value, format);
4186
4187
  }
4187
4188
  // src/components/FittingWheel/ModuleLines/TrackingComputer.tsx
@@ -5211,7 +5212,7 @@ function FittingAugmentations(t0) {
5211
5212
  const boosters = useBoosters();
5212
5213
  let t1;
5213
5214
  if ($[0] !== implants || $[1] !== readOnly) {
5214
- t1 = !readOnly || implants.some(_temp$14);
5215
+ t1 = !readOnly || implants.some(_temp$15);
5215
5216
  $[0] = implants;
5216
5217
  $[1] = readOnly;
5217
5218
  $[2] = t1;
@@ -5266,7 +5267,7 @@ function FittingAugmentations(t0) {
5266
5267
  } else t5 = $[15];
5267
5268
  return t5;
5268
5269
  }
5269
- function _temp$14(slot) {
5270
+ function _temp$15(slot) {
5270
5271
  return slot.item !== void 0;
5271
5272
  }
5272
5273
  function FittingAugmentation(t0) {
@@ -5540,6 +5541,21 @@ function FittingAugmentation(t0) {
5540
5541
  } else t20 = $[82];
5541
5542
  return t20;
5542
5543
  }
5544
+ // src/components/FittingWheel/fitLink.ts
5545
+ /** The eveship.fit link that opens the current fit. */
5546
+ function useFitLink() {
5547
+ const $ = c(3);
5548
+ const engine = useEngine();
5549
+ const fit = useFit();
5550
+ let t0;
5551
+ if ($[0] !== engine || $[1] !== fit) {
5552
+ t0 = engine.saveLink(fit);
5553
+ $[0] = engine;
5554
+ $[1] = fit;
5555
+ $[2] = t0;
5556
+ } else t0 = $[2];
5557
+ return `https://eveship.fit/?fit=${t0}`;
5558
+ }
5543
5559
  // src/components/FittingWheel/FittingWheel.module.css
5544
5560
  var FittingWheel_module_default = { "centre": "GK_wGG_centre" };
5545
5561
  // src/components/FittingWheel/FittingWheel.tsx
@@ -5605,11 +5621,8 @@ function onEveShipFit() {
5605
5621
  return location.hostname === "eveship.fit" || location.hostname.endsWith(".eveship.fit");
5606
5622
  }
5607
5623
  function EveShipFitLink({ text = "open on eveship.fit" }) {
5608
- const engine = useEngine();
5609
- const fit = useFit();
5610
- const href = useMemo(() => `https://eveship.fit/?fit=${engine.saveLink(fit)}`, [engine, fit]);
5611
5624
  return /* @__PURE__ */ jsx(WheelLink, {
5612
- href,
5625
+ href: useFitLink(),
5613
5626
  text
5614
5627
  });
5615
5628
  }
@@ -5706,7 +5719,7 @@ function FittingCentre() {
5706
5719
  })
5707
5720
  },
5708
5721
  "separator",
5709
- fit.items.some(_temp$13) && {
5722
+ fit.items.some(_temp$14) && {
5710
5723
  label: "Strip Fitting",
5711
5724
  onSelect: () => store.remove(...store.getSnapshot().fit.items.flatMap(_temp2$7))
5712
5725
  }
@@ -5803,7 +5816,7 @@ function FittingCentre() {
5803
5816
  function _temp2$7(item_0, ref) {
5804
5817
  return keptOnStrip.has(item_0.slot.type) ? [] : [ref];
5805
5818
  }
5806
- function _temp$13(item_1) {
5819
+ function _temp$14(item_1) {
5807
5820
  return !keptOnStrip.has(item_1.slot.type);
5808
5821
  }
5809
5822
  const copiedRacks = [
@@ -6103,6 +6116,195 @@ function ServiceSlot({ typeId, typeName, state = "online", available = true, pre
6103
6116
  })]
6104
6117
  });
6105
6118
  }
6119
+ // src/components/ItemBrowser/ItemBrowser.module.css
6120
+ var ItemBrowser_module_default = {
6121
+ "action": "xFSZwa_action",
6122
+ "actions": "xFSZwa_actions",
6123
+ "browser": "xFSZwa_browser",
6124
+ "collapse": "xFSZwa_collapse",
6125
+ "confirm": "xFSZwa_confirm",
6126
+ "copy": "xFSZwa_copy",
6127
+ "copyAnchor": "xFSZwa_copyAnchor",
6128
+ "count": "xFSZwa_count",
6129
+ "counts": "xFSZwa_counts",
6130
+ "dialogButtons": "xFSZwa_dialogButtons",
6131
+ "dragImage": "xFSZwa_dragImage",
6132
+ "empty": "xFSZwa_empty",
6133
+ "field": "xFSZwa_field",
6134
+ "filters": "xFSZwa_filters",
6135
+ "flyable": "xFSZwa_flyable",
6136
+ "form": "xFSZwa_form",
6137
+ "hull": "xFSZwa_hull",
6138
+ "importError": "xFSZwa_importError",
6139
+ "info": "xFSZwa_info",
6140
+ "kind": "xFSZwa_kind",
6141
+ "menu": "xFSZwa_menu",
6142
+ "panel": "xFSZwa_panel",
6143
+ "search": "xFSZwa_search",
6144
+ "simulate": "xFSZwa_simulate",
6145
+ "tab": "xFSZwa_tab",
6146
+ "tabs": "xFSZwa_tabs",
6147
+ "tree": "xFSZwa_tree",
6148
+ "unseen": "xFSZwa_unseen",
6149
+ "views": "xFSZwa_views"
6150
+ };
6151
+ // src/components/ItemBrowser/copyFit.tsx
6152
+ const FLASH_MS = 2e3;
6153
+ /** Copies a fit to the clipboard, or shows it in `dialog` when the browser refuses; render `dialog` once. */
6154
+ function useCopyFit() {
6155
+ const $ = c(6);
6156
+ const engine = useEngine();
6157
+ const { copy, dialog } = useCopyText("Copy Fit", "fit", 12);
6158
+ let t0;
6159
+ if ($[0] !== copy || $[1] !== engine) {
6160
+ t0 = (fit, format, onCopied) => copy(engine.saveText(fit, format), onCopied);
6161
+ $[0] = copy;
6162
+ $[1] = engine;
6163
+ $[2] = t0;
6164
+ } else t0 = $[2];
6165
+ let t1;
6166
+ if ($[3] !== dialog || $[4] !== t0) {
6167
+ t1 = {
6168
+ copy: t0,
6169
+ dialog
6170
+ };
6171
+ $[3] = dialog;
6172
+ $[4] = t0;
6173
+ $[5] = t1;
6174
+ } else t1 = $[5];
6175
+ return t1;
6176
+ }
6177
+ /** Copies text to the clipboard, or shows it in `dialog` when the browser refuses; render `dialog` once. */
6178
+ function useCopyText(title, what, rows) {
6179
+ const $ = c(10);
6180
+ const [refused, setRefused] = useState();
6181
+ let t0;
6182
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6183
+ t0 = (text, onCopied) => {
6184
+ Promise.resolve().then(() => navigator.clipboard.writeText(text)).then(onCopied, () => setRefused(text));
6185
+ };
6186
+ $[0] = t0;
6187
+ } else t0 = $[0];
6188
+ const copy = t0;
6189
+ const t1 = refused !== void 0;
6190
+ let t2;
6191
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
6192
+ t2 = () => setRefused(void 0);
6193
+ $[1] = t2;
6194
+ } else t2 = $[1];
6195
+ const t3 = refused ?? "";
6196
+ let t4;
6197
+ if ($[2] !== rows || $[3] !== t3 || $[4] !== what) {
6198
+ t4 = /* @__PURE__ */ jsx(CopyForm, {
6199
+ text: t3,
6200
+ what,
6201
+ rows
6202
+ });
6203
+ $[2] = rows;
6204
+ $[3] = t3;
6205
+ $[4] = what;
6206
+ $[5] = t4;
6207
+ } else t4 = $[5];
6208
+ let t5;
6209
+ if ($[6] !== t1 || $[7] !== t4 || $[8] !== title) {
6210
+ t5 = {
6211
+ copy,
6212
+ dialog: /* @__PURE__ */ jsx(Dialog, {
6213
+ open: t1,
6214
+ title,
6215
+ onClose: t2,
6216
+ children: t4
6217
+ })
6218
+ };
6219
+ $[6] = t1;
6220
+ $[7] = t4;
6221
+ $[8] = title;
6222
+ $[9] = t5;
6223
+ } else t5 = $[9];
6224
+ return t5;
6225
+ }
6226
+ /** `true` for a moment after calling the returned function. */
6227
+ function useFlash() {
6228
+ const $ = c(6);
6229
+ const [shown, setShown] = useState(0);
6230
+ let t0;
6231
+ let t1;
6232
+ if ($[0] !== shown) {
6233
+ t0 = () => {
6234
+ if (shown === 0) return;
6235
+ const timer = setTimeout(() => setShown(0), FLASH_MS);
6236
+ return () => clearTimeout(timer);
6237
+ };
6238
+ t1 = [shown];
6239
+ $[0] = shown;
6240
+ $[1] = t0;
6241
+ $[2] = t1;
6242
+ } else {
6243
+ t0 = $[1];
6244
+ t1 = $[2];
6245
+ }
6246
+ useEffect(t0, t1);
6247
+ const t2 = shown > 0;
6248
+ let t3;
6249
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
6250
+ t3 = () => setShown(Date.now());
6251
+ $[3] = t3;
6252
+ } else t3 = $[3];
6253
+ let t4;
6254
+ if ($[4] !== t2) {
6255
+ t4 = [t2, t3];
6256
+ $[4] = t2;
6257
+ $[5] = t4;
6258
+ } else t4 = $[5];
6259
+ return t4;
6260
+ }
6261
+ function CopyForm(t0) {
6262
+ const $ = c(10);
6263
+ const { text, what, rows } = t0;
6264
+ const id = useId();
6265
+ let t1;
6266
+ if ($[0] !== id || $[1] !== what) {
6267
+ t1 = /* @__PURE__ */ jsxs("label", {
6268
+ htmlFor: id,
6269
+ children: [
6270
+ "The browser blocked the clipboard. Copy the ",
6271
+ what,
6272
+ " from here."
6273
+ ]
6274
+ });
6275
+ $[0] = id;
6276
+ $[1] = what;
6277
+ $[2] = t1;
6278
+ } else t1 = $[2];
6279
+ let t2;
6280
+ if ($[3] !== id || $[4] !== rows || $[5] !== text) {
6281
+ t2 = /* @__PURE__ */ jsx("textarea", {
6282
+ id,
6283
+ rows,
6284
+ readOnly: true,
6285
+ value: text,
6286
+ onFocus: _temp$13
6287
+ });
6288
+ $[3] = id;
6289
+ $[4] = rows;
6290
+ $[5] = text;
6291
+ $[6] = t2;
6292
+ } else t2 = $[6];
6293
+ let t3;
6294
+ if ($[7] !== t1 || $[8] !== t2) {
6295
+ t3 = /* @__PURE__ */ jsxs("div", {
6296
+ className: ItemBrowser_module_default.form,
6297
+ children: [t1, t2]
6298
+ });
6299
+ $[7] = t1;
6300
+ $[8] = t2;
6301
+ $[9] = t3;
6302
+ } else t3 = $[9];
6303
+ return t3;
6304
+ }
6305
+ function _temp$13(event) {
6306
+ return event.currentTarget.select();
6307
+ }
6106
6308
  // src/components/ItemInfo/anchoredCard.ts
6107
6309
  /** Opens a popover card next to `anchor`; closes it when the anchor goes away or the page scrolls under it. */
6108
6310
  function useAnchoredCard(anchor, onClose) {
@@ -6735,6 +6937,9 @@ var Mutate_module_default = {
6735
6937
  "chartRoll": "yNZdnG_chartRoll",
6736
6938
  "chartRow": "yNZdnG_chartRow",
6737
6939
  "chartTitle": "yNZdnG_chartTitle",
6940
+ "chip": "yNZdnG_chip",
6941
+ "chipBar": "yNZdnG_chipBar",
6942
+ "chips": "yNZdnG_chips",
6738
6943
  "dice": "yNZdnG_dice",
6739
6944
  "error": "yNZdnG_error",
6740
6945
  "field": "yNZdnG_field",
@@ -7160,119 +7365,382 @@ function span(at, from, to) {
7160
7365
  function upIsGood(range) {
7161
7366
  return range.highIsGood === range.base >= 0;
7162
7367
  }
7163
- /** The names without the words they all end in, like "Large Shield Extender Mutaplasmid". */
7368
+ /** The names without the words they all have, like "Large Shield Extender Mutaplasmid". */
7164
7369
  function shortNames(names) {
7165
7370
  const words = names.map((name) => name.split(" "));
7166
- let shared = 0;
7167
- while (words.every((name) => name.length > shared + 1) && words.every((name) => name.at(-1 - shared) === words[0].at(-1 - shared))) shared++;
7168
- if (names.length === 1) shared = words[0].at(-1) === "Mutaplasmid" ? 1 : 0;
7169
- return words.map((name) => name.slice(0, name.length - shared).join(" "));
7371
+ if (words.length === 1) return [words[0].filter((word) => word !== "Mutaplasmid").join(" ")];
7372
+ const shared = words[0].filter((word) => words.every((name) => name.includes(word)));
7373
+ const short = words.map((name) => name.filter((word) => !shared.includes(word)).join(" "));
7374
+ return short.every((name) => name !== "") ? short : [...names];
7170
7375
  }
7171
7376
  // src/components/Mutate/Mutate.tsx
7172
7377
  const PREVIEW_TARGET = "mutate";
7173
- /** The window to roll a fitted module's mutation in, next to what asked for it. */
7378
+ /** The window to roll a fitted module's or the drones' mutation in, next to what asked for it. */
7174
7379
  function Mutate() {
7175
- const $ = c(20);
7380
+ const $ = c(9);
7176
7381
  const { shown, close } = useMutate();
7177
- const fit = useFit();
7178
- const sde = useSde();
7382
+ if (shown === void 0) return null;
7383
+ if (shown.slot.type === "drone_bay") {
7384
+ let t0;
7385
+ if ($[0] !== close || $[1] !== shown) {
7386
+ t0 = /* @__PURE__ */ jsx(MutateDrones, {
7387
+ shown,
7388
+ onClose: close
7389
+ }, shown.base);
7390
+ $[0] = close;
7391
+ $[1] = shown;
7392
+ $[2] = t0;
7393
+ } else t0 = $[2];
7394
+ return t0;
7395
+ }
7396
+ const t0 = shown.slot.type;
7397
+ let t1;
7398
+ if ($[3] !== shown.slot) {
7399
+ t1 = slotIndex(shown.slot);
7400
+ $[3] = shown.slot;
7401
+ $[4] = t1;
7402
+ } else t1 = $[4];
7403
+ const t2 = `${t0} ${t1}`;
7404
+ let t3;
7405
+ if ($[5] !== close || $[6] !== shown || $[7] !== t2) {
7406
+ t3 = /* @__PURE__ */ jsx(MutateModule, {
7407
+ shown,
7408
+ onClose: close
7409
+ }, t2);
7410
+ $[5] = close;
7411
+ $[6] = shown;
7412
+ $[7] = t2;
7413
+ $[8] = t3;
7414
+ } else t3 = $[8];
7415
+ return t3;
7416
+ }
7417
+ function useCloseWhenGone(gone, onClose) {
7418
+ const $ = c(5);
7419
+ const closeWhenGone = useEffectEvent(onClose);
7179
7420
  let t0;
7180
- if ($[0] !== fit || $[1] !== shown) {
7181
- t0 = shown === void 0 ? -1 : refIn(fit, shown.slot);
7182
- $[0] = fit;
7183
- $[1] = shown;
7421
+ if ($[0] !== closeWhenGone || $[1] !== gone) {
7422
+ t0 = () => {
7423
+ if (gone) closeWhenGone();
7424
+ };
7425
+ $[0] = closeWhenGone;
7426
+ $[1] = gone;
7184
7427
  $[2] = t0;
7185
7428
  } else t0 = $[2];
7186
- const ref = t0;
7429
+ let t1;
7430
+ if ($[3] !== gone) {
7431
+ t1 = [gone];
7432
+ $[3] = gone;
7433
+ $[4] = t1;
7434
+ } else t1 = $[4];
7435
+ useEffect(t0, t1);
7436
+ }
7437
+ function MutateModule(t0) {
7438
+ const $ = c(12);
7439
+ const { shown, onClose } = t0;
7440
+ const fit = useFit();
7441
+ const sde = useSde();
7442
+ const ref = refIn(fit, shown.slot);
7187
7443
  const item = fit.items[ref];
7188
7444
  let t1;
7189
- if ($[3] !== item || $[4] !== sde) {
7445
+ if ($[0] !== item || $[1] !== sde) {
7190
7446
  t1 = item && mutationRollOf(sde, item);
7191
- $[3] = item;
7192
- $[4] = sde;
7193
- $[5] = t1;
7194
- } else t1 = $[5];
7447
+ $[0] = item;
7448
+ $[1] = sde;
7449
+ $[2] = t1;
7450
+ } else t1 = $[2];
7195
7451
  const roll = t1;
7196
- const gone = shown !== void 0 && roll === void 0;
7197
- const closeWhenGone = useEffectEvent(close);
7452
+ useCloseWhenGone(roll === void 0, onClose);
7453
+ if (item === void 0 || roll === void 0) return null;
7198
7454
  let t2;
7199
- if ($[6] !== closeWhenGone || $[7] !== gone) {
7200
- t2 = () => {
7201
- if (gone) closeWhenGone();
7455
+ if ($[3] !== sde || $[4] !== shown.slot) {
7456
+ t2 = (store, change) => {
7457
+ const current = store.getSnapshot().fit;
7458
+ const target = refIn(current, shown.slot);
7459
+ const before = current.items[target] && mutationRollOf(sde, current.items[target]);
7460
+ if (before !== void 0) store.setMutation(target, change(before));
7202
7461
  };
7203
- $[6] = closeWhenGone;
7204
- $[7] = gone;
7205
- $[8] = t2;
7206
- } else t2 = $[8];
7462
+ $[3] = sde;
7463
+ $[4] = shown.slot;
7464
+ $[5] = t2;
7465
+ } else t2 = $[5];
7207
7466
  let t3;
7208
- if ($[9] !== gone) {
7209
- t3 = [gone];
7210
- $[9] = gone;
7211
- $[10] = t3;
7212
- } else t3 = $[10];
7213
- useEffect(t2, t3);
7214
- if (shown === void 0 || item === void 0 || roll === void 0) return null;
7215
- const t4 = shown.slot.type;
7216
- let t5;
7217
- if ($[11] !== shown.slot) {
7218
- t5 = slotIndex(shown.slot);
7219
- $[11] = shown.slot;
7220
- $[12] = t5;
7221
- } else t5 = $[12];
7222
- const t6 = `${t4} ${t5}`;
7223
- let t7;
7224
- if ($[13] !== close || $[14] !== item.type_id || $[15] !== ref || $[16] !== roll || $[17] !== shown || $[18] !== t6) {
7225
- t7 = /* @__PURE__ */ jsx(MutateCard, {
7467
+ if ($[6] !== item.type_id || $[7] !== onClose || $[8] !== roll || $[9] !== shown || $[10] !== t2) {
7468
+ t3 = /* @__PURE__ */ jsx(MutateCard, {
7226
7469
  shown,
7227
- itemRef: ref,
7228
7470
  typeId: item.type_id,
7229
7471
  roll,
7230
- onClose: close
7231
- }, t6);
7232
- $[13] = close;
7233
- $[14] = item.type_id;
7234
- $[15] = ref;
7235
- $[16] = roll;
7236
- $[17] = shown;
7237
- $[18] = t6;
7238
- $[19] = t7;
7239
- } else t7 = $[19];
7240
- return t7;
7472
+ apply: t2,
7473
+ onClose
7474
+ });
7475
+ $[6] = item.type_id;
7476
+ $[7] = onClose;
7477
+ $[8] = roll;
7478
+ $[9] = shown;
7479
+ $[10] = t2;
7480
+ $[11] = t3;
7481
+ } else t3 = $[11];
7482
+ return t3;
7241
7483
  }
7242
- function MutateCard(t0) {
7243
- const $ = c(42);
7244
- const { shown: t1, itemRef: ref, typeId, roll: fitted, onClose } = t0;
7245
- const { slot, anchor } = t1;
7484
+ function MutateDrones(t0) {
7485
+ const $ = c(9);
7486
+ const { shown, onClose } = t0;
7487
+ const fit = useFit();
7246
7488
  const sde = useSde();
7247
- const store = useFitStore();
7248
- const preview = usePreview();
7249
- const { card, style } = useAnchoredCard(anchor, onClose);
7250
- const { open: openMenu, menu } = useContextMenu();
7251
- const tabId = useId();
7252
- const [tab, setTab] = useState("attributes");
7253
- const [chosen, setChosen] = useState();
7254
- const [dragged, setDragged] = useState();
7255
- let t2;
7256
- if ($[0] !== fitted.base || $[1] !== sde) {
7257
- t2 = mutaplasmidsOf(sde, fitted.base);
7258
- $[0] = fitted.base;
7489
+ let t1;
7490
+ if ($[0] !== fit || $[1] !== sde || $[2] !== shown.base) {
7491
+ t1 = shown.base === void 0 ? void 0 : mutatedDronesOf(sde, fit, shown.base);
7492
+ $[0] = fit;
7259
7493
  $[1] = sde;
7260
- $[2] = t2;
7261
- } else t2 = $[2];
7262
- const mutaplasmids = t2;
7494
+ $[2] = shown.base;
7495
+ $[3] = t1;
7496
+ } else t1 = $[3];
7497
+ const drones = t1;
7498
+ useCloseWhenGone(drones === void 0, onClose);
7499
+ if (drones === void 0) return null;
7500
+ const t2 = fit.items[drones.refs[0]];
7263
7501
  let t3;
7264
- if ($[3] !== chosen || $[4] !== fitted || $[5] !== sde) {
7265
- t3 = chosen !== void 0 && rollFits(sde, {
7266
- ...fitted,
7267
- mutaplasmid: chosen
7268
- }) ? chosen : fitted.mutaplasmid;
7269
- $[3] = chosen;
7270
- $[4] = fitted;
7271
- $[5] = sde;
7502
+ if ($[4] !== drones || $[5] !== onClose || $[6] !== shown || $[7] !== t2.type_id) {
7503
+ t3 = /* @__PURE__ */ jsx(DronesCard, {
7504
+ shown,
7505
+ typeId: t2.type_id,
7506
+ drones,
7507
+ onClose
7508
+ });
7509
+ $[4] = drones;
7510
+ $[5] = onClose;
7511
+ $[6] = shown;
7512
+ $[7] = t2.type_id;
7513
+ $[8] = t3;
7514
+ } else t3 = $[8];
7515
+ return t3;
7516
+ }
7517
+ /** The mutate window for the drones of a row; what is changed goes for the selected ones. */
7518
+ function DronesCard(t0) {
7519
+ const $ = c(27);
7520
+ const { shown, typeId, drones: t1, onClose } = t0;
7521
+ const { rolls, active } = t1;
7522
+ const sde = useSde();
7523
+ const store = useFitStore();
7524
+ let t2;
7525
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
7526
+ t2 = /* @__PURE__ */ new Set();
7527
+ $[0] = t2;
7528
+ } else t2 = $[0];
7529
+ const [unselected, setUnselected] = useState(t2);
7530
+ const base = rolls[0].base;
7531
+ let T0;
7532
+ let t3;
7533
+ let t4;
7534
+ let t5;
7535
+ let t6;
7536
+ let t7;
7537
+ let t8;
7538
+ if ($[1] !== active || $[2] !== base || $[3] !== rolls || $[4] !== sde || $[5] !== shown || $[6] !== store || $[7] !== typeId || $[8] !== unselected) {
7539
+ const all = rolls.map(_temp$10);
7540
+ let t9;
7541
+ if ($[16] !== unselected) {
7542
+ t9 = (index_0) => !unselected.has(index_0);
7543
+ $[16] = unselected;
7544
+ $[17] = t9;
7545
+ } else t9 = $[17];
7546
+ const picked = all.filter(t9);
7547
+ const selected = picked.length > 0 ? picked : all;
7548
+ const select = (index_1, adding) => {
7549
+ const only = selected.length === 1 && selected[0] === index_1;
7550
+ if (adding) {
7551
+ if (!only) setUnselected(new Set(all.filter((other) => selected.includes(other) === (other === index_1))));
7552
+ } else setUnselected(new Set(only ? [] : all.filter((other_0) => other_0 !== index_1)));
7553
+ };
7554
+ T0 = MutateCard;
7555
+ t3 = shown;
7556
+ t4 = typeId;
7557
+ t5 = rolls[selected[0]];
7558
+ t6 = rolls.length > 1 ? {
7559
+ disabled: selected.length > 1,
7560
+ set: (roll) => store.setMutatedDrones(base, rolls.map(() => roll))
7561
+ } : void 0;
7562
+ t7 = (target, change) => target.setMutatedDrones(base, (mutatedDronesOf(sde, target.getSnapshot().fit, base)?.rolls ?? []).map((roll_0, index_2) => selected.includes(index_2) ? change(roll_0) : roll_0));
7563
+ t8 = rolls.length > 1 && /* @__PURE__ */ jsx("div", {
7564
+ className: Mutate_module_default.chips,
7565
+ children: rolls.map((roll_1, index_3) => /* @__PURE__ */ jsx(DroneChip, {
7566
+ index: index_3,
7567
+ roll: roll_1,
7568
+ selected: selected.includes(index_3),
7569
+ launched: index_3 < active,
7570
+ onSelect: (adding_0) => select(index_3, adding_0)
7571
+ }, index_3))
7572
+ });
7573
+ $[1] = active;
7574
+ $[2] = base;
7575
+ $[3] = rolls;
7576
+ $[4] = sde;
7577
+ $[5] = shown;
7578
+ $[6] = store;
7579
+ $[7] = typeId;
7580
+ $[8] = unselected;
7581
+ $[9] = T0;
7582
+ $[10] = t3;
7583
+ $[11] = t4;
7584
+ $[12] = t5;
7585
+ $[13] = t6;
7586
+ $[14] = t7;
7587
+ $[15] = t8;
7588
+ } else {
7589
+ T0 = $[9];
7590
+ t3 = $[10];
7591
+ t4 = $[11];
7592
+ t5 = $[12];
7593
+ t6 = $[13];
7594
+ t7 = $[14];
7595
+ t8 = $[15];
7596
+ }
7597
+ let t9;
7598
+ if ($[18] !== T0 || $[19] !== onClose || $[20] !== t3 || $[21] !== t4 || $[22] !== t5 || $[23] !== t6 || $[24] !== t7 || $[25] !== t8) {
7599
+ t9 = /* @__PURE__ */ jsx(T0, {
7600
+ shown: t3,
7601
+ typeId: t4,
7602
+ roll: t5,
7603
+ setAll: t6,
7604
+ apply: t7,
7605
+ above: t8,
7606
+ onClose
7607
+ });
7608
+ $[18] = T0;
7609
+ $[19] = onClose;
7610
+ $[20] = t3;
7611
+ $[21] = t4;
7612
+ $[22] = t5;
7613
+ $[23] = t6;
7614
+ $[24] = t7;
7615
+ $[25] = t8;
7616
+ $[26] = t9;
7617
+ } else t9 = $[26];
7618
+ return t9;
7619
+ }
7620
+ function _temp$10(_, index) {
7621
+ return index;
7622
+ }
7623
+ /** One drone of a row, with how it rolled the stat that matters most. */
7624
+ function DroneChip(t0) {
7625
+ const $ = c(20);
7626
+ const { index, roll, selected, launched, onSelect } = t0;
7627
+ const sde = useSde();
7628
+ let t1;
7629
+ if ($[0] !== roll.base || $[1] !== roll.mutaplasmid || $[2] !== sde) {
7630
+ const ranges = mutationRanges(sde, roll.base, roll.mutaplasmid);
7631
+ t1 = ranges.find((t2) => {
7632
+ const { attributeId } = t2;
7633
+ return attributeId === sde.attributeId("damageMultiplier");
7634
+ }) ?? ranges[0];
7635
+ $[0] = roll.base;
7636
+ $[1] = roll.mutaplasmid;
7637
+ $[2] = sde;
7638
+ $[3] = t1;
7639
+ } else t1 = $[3];
7640
+ const range = t1;
7641
+ const value = range && (roll.attributes[range.attributeId] ?? range.base);
7642
+ const change = range && value !== void 0 && range.base !== 0 ? value / range.base - 1 : 0;
7643
+ const width = range && value !== void 0 && range.max > range.min ? (value - range.min) / (range.max - range.min) : 0;
7644
+ const t2 = Math.abs(change) * 100;
7645
+ let t3;
7646
+ if ($[4] !== t2) {
7647
+ t3 = formatNumber(t2, { decimals: 1 });
7648
+ $[4] = t2;
7649
+ $[5] = t3;
7650
+ } else t3 = $[5];
7651
+ const percent = t3;
7652
+ const better = change > 0 === (range?.highIsGood ?? true);
7653
+ const t4 = launched || void 0;
7654
+ let t5;
7655
+ if ($[6] !== onSelect) {
7656
+ t5 = (event) => onSelect(event.ctrlKey || event.metaKey || event.shiftKey);
7657
+ $[6] = onSelect;
7658
+ $[7] = t5;
7659
+ } else t5 = $[7];
7660
+ const t6 = index + 1;
7661
+ const t7 = Number(percent) === 0 ? void 0 : better ? "better" : "worse";
7662
+ const t8 = Number(percent) === 0 ? "0%" : `${change > 0 ? "+" : "-"}${percent}%`;
7663
+ let t9;
7664
+ if ($[8] !== t7 || $[9] !== t8) {
7665
+ t9 = /* @__PURE__ */ jsx("span", {
7666
+ className: Mutate_module_default.change,
7667
+ "data-change": t7,
7668
+ children: t8
7669
+ });
7670
+ $[8] = t7;
7671
+ $[9] = t8;
7672
+ $[10] = t9;
7673
+ } else t9 = $[10];
7674
+ const t10 = `${width * 100}%`;
7675
+ let t11;
7676
+ if ($[11] !== t10) {
7677
+ t11 = /* @__PURE__ */ jsx("span", {
7678
+ className: Mutate_module_default.chipBar,
7679
+ children: /* @__PURE__ */ jsx("span", { style: { width: t10 } })
7680
+ });
7681
+ $[11] = t10;
7682
+ $[12] = t11;
7683
+ } else t11 = $[12];
7684
+ let t12;
7685
+ if ($[13] !== selected || $[14] !== t11 || $[15] !== t4 || $[16] !== t5 || $[17] !== t6 || $[18] !== t9) {
7686
+ t12 = /* @__PURE__ */ jsxs("button", {
7687
+ type: "button",
7688
+ className: Mutate_module_default.chip,
7689
+ "aria-pressed": selected,
7690
+ "data-launched": t4,
7691
+ title: "Click for only this drone, Ctrl+click to add or remove it",
7692
+ onClick: t5,
7693
+ children: [
7694
+ "Drone ",
7695
+ t6,
7696
+ t9,
7697
+ t11
7698
+ ]
7699
+ });
7700
+ $[13] = selected;
7701
+ $[14] = t11;
7702
+ $[15] = t4;
7703
+ $[16] = t5;
7704
+ $[17] = t6;
7705
+ $[18] = t9;
7706
+ $[19] = t12;
7707
+ } else t12 = $[19];
7708
+ return t12;
7709
+ }
7710
+ function MutateCard(t0) {
7711
+ const $ = c(42);
7712
+ const { shown: t1, typeId, roll: fitted, setAll, apply, above, onClose } = t0;
7713
+ const { slot, anchor } = t1;
7714
+ const sde = useSde();
7715
+ const store = useFitStore();
7716
+ const preview = usePreview();
7717
+ const { card, style } = useAnchoredCard(anchor, onClose);
7718
+ const { open: openMenu, menu } = useContextMenu();
7719
+ const tabId = useId();
7720
+ const [tab, setTab] = useState("attributes");
7721
+ const [chosen, setChosen] = useState();
7722
+ const [dragged, setDragged] = useState();
7723
+ let t2;
7724
+ if ($[0] !== fitted.base || $[1] !== sde) {
7725
+ t2 = mutaplasmidsOf(sde, fitted.base);
7726
+ $[0] = fitted.base;
7727
+ $[1] = sde;
7728
+ $[2] = t2;
7729
+ } else t2 = $[2];
7730
+ const mutaplasmids = t2;
7731
+ let t3;
7732
+ if ($[3] !== chosen || $[4] !== fitted || $[5] !== sde) {
7733
+ t3 = chosen !== void 0 && rollFits(sde, {
7734
+ ...fitted,
7735
+ mutaplasmid: chosen
7736
+ }) ? chosen : fitted.mutaplasmid;
7737
+ $[3] = chosen;
7738
+ $[4] = fitted;
7739
+ $[5] = sde;
7272
7740
  $[6] = t3;
7273
7741
  } else t3 = $[6];
7274
7742
  const mutaplasmid = t3;
7275
- const roll = dragged ?? {
7743
+ const roll = dragged?.roll ?? {
7276
7744
  ...fitted,
7277
7745
  mutaplasmid
7278
7746
  };
@@ -7298,57 +7766,54 @@ function MutateCard(t0) {
7298
7766
  } else t6 = $[11];
7299
7767
  useEffect(t5, t6);
7300
7768
  let t7;
7301
- if ($[12] !== preview || $[13] !== ref || $[14] !== store) {
7302
- t7 = (next) => {
7769
+ if ($[12] !== apply || $[13] !== preview || $[14] !== store) {
7770
+ t7 = (change, picked) => {
7303
7771
  preview.clear(PREVIEW_TARGET);
7304
7772
  setDragged(void 0);
7305
- setChosen(next.mutaplasmid);
7306
- store.setMutation(ref, next);
7773
+ setChosen(picked);
7774
+ apply(store, change);
7307
7775
  };
7308
- $[12] = preview;
7309
- $[13] = ref;
7776
+ $[12] = apply;
7777
+ $[13] = preview;
7310
7778
  $[14] = store;
7311
7779
  $[15] = t7;
7312
7780
  } else t7 = $[15];
7313
7781
  const commit = t7;
7782
+ const setValue = (range, value) => {
7783
+ const clamped = clampToRange(value, range);
7784
+ const change_0 = (before) => ({
7785
+ ...before,
7786
+ mutaplasmid,
7787
+ attributes: {
7788
+ ...before.attributes,
7789
+ [range.attributeId]: clamped
7790
+ }
7791
+ });
7792
+ setDragged({
7793
+ roll: change_0(roll),
7794
+ change: change_0
7795
+ });
7796
+ preview.show((draft) => apply(draft, change_0), PREVIEW_TARGET);
7797
+ };
7314
7798
  let t8;
7315
- if ($[16] !== preview || $[17] !== ref) {
7316
- t8 = (next_0) => {
7317
- setDragged(next_0);
7318
- preview.show((draft) => draft.setMutation(ref, next_0), PREVIEW_TARGET);
7799
+ if ($[16] !== commit || $[17] !== dragged) {
7800
+ t8 = () => {
7801
+ if (dragged !== void 0) commit(dragged.change, dragged.roll.mutaplasmid);
7319
7802
  };
7320
- $[16] = preview;
7321
- $[17] = ref;
7803
+ $[16] = commit;
7804
+ $[17] = dragged;
7322
7805
  $[18] = t8;
7323
7806
  } else t8 = $[18];
7324
- const drag = t8;
7325
- const setValue = (range, value) => drag({
7326
- ...roll,
7327
- attributes: {
7328
- ...roll.attributes,
7329
- [range.attributeId]: clamp(value, range)
7330
- }
7331
- });
7807
+ const finish = t8;
7808
+ const reroll = (kind) => commit(() => rollMutation(sde, roll.base, roll.mutaplasmid, kind), roll.mutaplasmid);
7332
7809
  let t9;
7333
- if ($[19] !== commit || $[20] !== dragged) {
7334
- t9 = () => {
7335
- if (dragged !== void 0) commit(dragged);
7336
- };
7810
+ if ($[19] !== commit || $[20] !== sde) {
7811
+ t9 = (picked_0) => commit((before_0) => withMutaplasmid(sde, before_0, picked_0), picked_0);
7337
7812
  $[19] = commit;
7338
- $[20] = dragged;
7813
+ $[20] = sde;
7339
7814
  $[21] = t9;
7340
7815
  } else t9 = $[21];
7341
- const finish = t9;
7342
- const reroll = (kind) => commit(rollMutation(sde, roll.base, roll.mutaplasmid, kind));
7343
- const choose = (picked) => {
7344
- const attributes = {};
7345
- for (const range_0 of mutationRanges(sde, roll.base, picked)) attributes[range_0.attributeId] = clamp(roll.attributes[range_0.attributeId] ?? range_0.base, range_0);
7346
- commit({
7347
- base: roll.base,
7348
- mutaplasmid: picked,
7349
- attributes
7350
- });
7351
- };
7816
+ const choose = t9;
7352
7817
  let t10;
7353
7818
  if ($[22] !== onClose) {
7354
7819
  t10 = (event) => {
@@ -7447,30 +7912,39 @@ function MutateCard(t0) {
7447
7912
  className: Mutate_module_default.more,
7448
7913
  "aria-label": "More Rolls",
7449
7914
  "aria-haspopup": "menu",
7450
- onClick: (event_0) => openMenu(event_0, [{
7451
- label: "Best Roll",
7452
- onSelect: () => reroll("best")
7453
- }, {
7454
- label: "Worst Roll",
7455
- onSelect: () => reroll("worst")
7456
- }]),
7915
+ onClick: (event_0) => openMenu(event_0, [
7916
+ {
7917
+ label: "Best Roll",
7918
+ onSelect: () => reroll("best")
7919
+ },
7920
+ {
7921
+ label: "Worst Roll",
7922
+ onSelect: () => reroll("worst")
7923
+ },
7924
+ setAll && {
7925
+ label: "Set All Drones to Selected",
7926
+ disabled: setAll.disabled,
7927
+ onSelect: () => setAll.set(roll)
7928
+ }
7929
+ ]),
7457
7930
  children: "▾"
7458
7931
  })]
7459
7932
  })]
7460
7933
  }),
7461
7934
  menu,
7935
+ above,
7462
7936
  /* @__PURE__ */ jsx("div", {
7463
7937
  className: Mutate_module_default.stats,
7464
- children: ranges.map((range_1) => /* @__PURE__ */ jsx(Stat$1, {
7465
- range: range_1,
7466
- value: roll.attributes[range_1.attributeId] ?? range_1.base,
7467
- onChange: (value_0) => setValue(range_1, value_0),
7938
+ children: ranges.map((range_0) => /* @__PURE__ */ jsx(Stat$1, {
7939
+ range: range_0,
7940
+ value: roll.attributes[range_0.attributeId] ?? range_0.base,
7941
+ onChange: (value_0) => setValue(range_0, value_0),
7468
7942
  onFinish: finish
7469
- }, range_1.attributeId))
7943
+ }, range_0.attributeId))
7470
7944
  })
7471
7945
  ] }) : /* @__PURE__ */ jsx(Import, {
7472
- slot,
7473
7946
  current: fitted,
7947
+ apply: (next) => apply(store, () => next),
7474
7948
  onFound: (found) => {
7475
7949
  setChosen(found.mutaplasmid);
7476
7950
  setTab("attributes");
@@ -7712,12 +8186,11 @@ function Stat$1(t0) {
7712
8186
  } else t22 = $[48];
7713
8187
  return t22;
7714
8188
  }
7715
- /** Rolls this module like one pasted from Pyfa, or one in game looked up by its link or IDs. */
8189
+ /** Rolls this module or drone like one pasted from Pyfa, or one in game looked up by its link or IDs. */
7716
8190
  function Import(t0) {
7717
8191
  const $ = c(39);
7718
- const { slot, current, onFound } = t0;
8192
+ const { current, apply: applyRoll, onFound } = t0;
7719
8193
  const engine = useEngine();
7720
- const store = useFitStore();
7721
8194
  const sde = useSde();
7722
8195
  const fieldId = useId();
7723
8196
  const [text, setText] = useState("");
@@ -7739,24 +8212,21 @@ function Import(t0) {
7739
8212
  } else t2 = $[5];
7740
8213
  const ids = t2;
7741
8214
  let t3;
7742
- if ($[6] !== onFound || $[7] !== sde || $[8] !== slot || $[9] !== store) {
8215
+ if ($[6] !== applyRoll || $[7] !== current.base || $[8] !== onFound || $[9] !== sde) {
7743
8216
  t3 = (roll) => {
7744
- const { fit } = store.getSnapshot();
7745
- const ref = refIn(fit, slot);
7746
- const base = fit.items[ref]?.mutation?.base;
7747
- if (base !== roll.base) {
7748
- const name = (typeId) => typeId === void 0 ? "module" : sde.type(typeId)?.name;
7749
- setStatus({ error: `That is a ${name(roll.base)}, not a ${name(base)}` });
8217
+ if (current.base !== roll.base) {
8218
+ const name = (typeId) => sde.type(typeId)?.name;
8219
+ setStatus({ error: `That is a ${name(roll.base)}, not a ${name(current.base)}` });
7750
8220
  return;
7751
8221
  }
7752
- store.setMutation(ref, roll);
8222
+ applyRoll(roll);
7753
8223
  setStatus(void 0);
7754
8224
  onFound(roll);
7755
8225
  };
7756
- $[6] = onFound;
7757
- $[7] = sde;
7758
- $[8] = slot;
7759
- $[9] = store;
8226
+ $[6] = applyRoll;
8227
+ $[7] = current.base;
8228
+ $[8] = onFound;
8229
+ $[9] = sde;
7760
8230
  $[10] = t3;
7761
8231
  } else t3 = $[10];
7762
8232
  const apply = t3;
@@ -7792,7 +8262,7 @@ function Import(t0) {
7792
8262
  $[16] = lookUp;
7793
8263
  $[17] = t5;
7794
8264
  } else t5 = $[17];
7795
- const t6 = engine.esi === void 0 ? "Paste the module from Pyfa." : "Paste the module from Pyfa or its item link from EVE, or type its type ID and item ID.";
8265
+ const t6 = engine.esi === void 0 ? "Paste the item from Pyfa." : "Paste the item from Pyfa or its item link from EVE, or type its type ID and item ID.";
7796
8266
  let t7;
7797
8267
  if ($[18] !== fieldId || $[19] !== t6) {
7798
8268
  t7 = /* @__PURE__ */ jsx("label", {
@@ -7876,7 +8346,7 @@ function Import(t0) {
7876
8346
  } else t14 = $[38];
7877
8347
  return t14;
7878
8348
  }
7879
- /** A roll as Pyfa copies a mutated module. */
8349
+ /** A roll as Pyfa copies a mutated module or drone. */
7880
8350
  function pyfaText(sde, roll) {
7881
8351
  const values = Object.entries(roll.attributes).map(([id, value]) => `${sde.attribute(Number(id))?.name ?? id} ${Number(value.toFixed(4))}`).join(", ");
7882
8352
  return `${sde.type(roll.base)?.name ?? roll.base}\n${sde.type(roll.mutaplasmid)?.name ?? roll.mutaplasmid}\n${values}`;
@@ -7887,9 +8357,6 @@ function refIn(fit, slot) {
7887
8357
  function slotIndex(slot) {
7888
8358
  return "index" in slot ? slot.index : void 0;
7889
8359
  }
7890
- function clamp(value, range) {
7891
- return Math.min(range.max, Math.max(range.min, value));
7892
- }
7893
8360
  function Dice() {
7894
8361
  const $ = c(1);
7895
8362
  let t0;
@@ -7968,7 +8435,7 @@ function ShipBonuses(t0) {
7968
8435
  title: "Misc bonus:",
7969
8436
  bonuses: bonuses?.misc ?? []
7970
8437
  }
7971
- ].filter(_temp$10);
8438
+ ].filter(_temp$9);
7972
8439
  let t2;
7973
8440
  if ($[6] !== sde || $[7] !== typeId) {
7974
8441
  t2 = sde.type(typeId)?.name;
@@ -8004,7 +8471,7 @@ function ShipBonuses(t0) {
8004
8471
  } else t1 = $[5];
8005
8472
  return t1;
8006
8473
  }
8007
- function _temp$10(section) {
8474
+ function _temp$9(section) {
8008
8475
  return section.bonuses.length > 0;
8009
8476
  }
8010
8477
  function formatBonus(sde, bonus) {
@@ -8103,8 +8570,8 @@ var BayContents_module_default = {
8103
8570
  // src/components/FittingWindow/DroneTooltip.tsx
8104
8571
  /** What EVE shows when hovering a drone in the drone bay. */
8105
8572
  function DroneTooltip(t0) {
8106
- const $ = c(32);
8107
- const { itemRef, typeId } = t0;
8573
+ const $ = c(35);
8574
+ const { itemRef, typeId, mutatedFrom } = t0;
8108
8575
  const sde = useSde();
8109
8576
  const type = useType(typeId);
8110
8577
  const effectId = type?.defaultEffectId;
@@ -8152,55 +8619,61 @@ function DroneTooltip(t0) {
8152
8619
  $[9] = t5;
8153
8620
  } else t5 = $[9];
8154
8621
  let t6;
8155
- if ($[10] !== effectId || $[11] !== itemRef) {
8156
- t6 = effectId !== void 0 && /* @__PURE__ */ jsx(EffectRange, {
8622
+ if ($[10] !== mutatedFrom) {
8623
+ t6 = mutatedFrom !== void 0 && /* @__PURE__ */ jsx(MutatedFrom, { typeId: mutatedFrom });
8624
+ $[10] = mutatedFrom;
8625
+ $[11] = t6;
8626
+ } else t6 = $[11];
8627
+ let t7;
8628
+ if ($[12] !== effectId || $[13] !== itemRef) {
8629
+ t7 = effectId !== void 0 && /* @__PURE__ */ jsx(EffectRange, {
8157
8630
  itemRef,
8158
8631
  effectId
8159
8632
  });
8160
- $[10] = effectId;
8161
- $[11] = itemRef;
8162
- $[12] = t6;
8163
- } else t6 = $[12];
8164
- let t7;
8165
- if ($[13] !== dps.text) {
8166
- t7 = /* @__PURE__ */ jsxs(Attribute, {
8167
- name: "damageMultiplier",
8168
- children: ["Damage Per Second ", dps.text]
8169
- });
8170
- $[13] = dps.text;
8633
+ $[12] = effectId;
8634
+ $[13] = itemRef;
8171
8635
  $[14] = t7;
8172
8636
  } else t7 = $[14];
8173
8637
  let t8;
8174
- if ($[15] !== itemRef) {
8175
- t8 = /* @__PURE__ */ jsx(DamageTypes, { itemRef });
8176
- $[15] = itemRef;
8638
+ if ($[15] !== dps.text) {
8639
+ t8 = /* @__PURE__ */ jsxs(Attribute, {
8640
+ name: "damageMultiplier",
8641
+ children: ["Damage Per Second ", dps.text]
8642
+ });
8643
+ $[15] = dps.text;
8177
8644
  $[16] = t8;
8178
8645
  } else t8 = $[16];
8179
8646
  let t9;
8180
- if ($[17] !== itemRef || $[18] !== mining) {
8181
- t9 = mining && /* @__PURE__ */ jsx(MiningAmount, { itemRef });
8647
+ if ($[17] !== itemRef) {
8648
+ t9 = /* @__PURE__ */ jsx(DamageTypes, { itemRef });
8182
8649
  $[17] = itemRef;
8183
- $[18] = mining;
8184
- $[19] = t9;
8185
- } else t9 = $[19];
8650
+ $[18] = t9;
8651
+ } else t9 = $[18];
8186
8652
  let t10;
8187
- if ($[20] !== itemRef) {
8188
- t10 = /* @__PURE__ */ jsx(Tracking, { itemRef });
8189
- $[20] = itemRef;
8653
+ if ($[19] !== itemRef || $[20] !== mining) {
8654
+ t10 = mining && /* @__PURE__ */ jsx(MiningAmount, { itemRef });
8655
+ $[19] = itemRef;
8656
+ $[20] = mining;
8190
8657
  $[21] = t10;
8191
8658
  } else t10 = $[21];
8192
8659
  let t11;
8193
- if ($[22] !== bandwidth.text) {
8194
- t11 = /* @__PURE__ */ jsxs(Attribute, {
8195
- name: "droneBandwidthUsed",
8196
- children: ["Bandwidth Needed ", bandwidth.text]
8197
- });
8198
- $[22] = bandwidth.text;
8660
+ if ($[22] !== itemRef) {
8661
+ t11 = /* @__PURE__ */ jsx(Tracking, { itemRef });
8662
+ $[22] = itemRef;
8199
8663
  $[23] = t11;
8200
8664
  } else t11 = $[23];
8201
8665
  let t12;
8202
- if ($[24] !== t10 || $[25] !== t11 || $[26] !== t5 || $[27] !== t6 || $[28] !== t7 || $[29] !== t8 || $[30] !== t9) {
8203
- t12 = /* @__PURE__ */ jsxs("span", {
8666
+ if ($[24] !== bandwidth.text) {
8667
+ t12 = /* @__PURE__ */ jsxs(Attribute, {
8668
+ name: "droneBandwidthUsed",
8669
+ children: ["Bandwidth Needed ", bandwidth.text]
8670
+ });
8671
+ $[24] = bandwidth.text;
8672
+ $[25] = t12;
8673
+ } else t12 = $[25];
8674
+ let t13;
8675
+ if ($[26] !== t10 || $[27] !== t11 || $[28] !== t12 || $[29] !== t5 || $[30] !== t6 || $[31] !== t7 || $[32] !== t8 || $[33] !== t9) {
8676
+ t13 = /* @__PURE__ */ jsxs("span", {
8204
8677
  className: ModuleTooltip_module_default.tooltip,
8205
8678
  children: [
8206
8679
  t5,
@@ -8209,19 +8682,21 @@ function DroneTooltip(t0) {
8209
8682
  t8,
8210
8683
  t9,
8211
8684
  t10,
8212
- t11
8685
+ t11,
8686
+ t12
8213
8687
  ]
8214
8688
  });
8215
- $[24] = t10;
8216
- $[25] = t11;
8217
- $[26] = t5;
8218
- $[27] = t6;
8219
- $[28] = t7;
8220
- $[29] = t8;
8221
- $[30] = t9;
8222
- $[31] = t12;
8223
- } else t12 = $[31];
8224
- return t12;
8689
+ $[26] = t10;
8690
+ $[27] = t11;
8691
+ $[28] = t12;
8692
+ $[29] = t5;
8693
+ $[30] = t6;
8694
+ $[31] = t7;
8695
+ $[32] = t8;
8696
+ $[33] = t9;
8697
+ $[34] = t13;
8698
+ } else t13 = $[34];
8699
+ return t13;
8225
8700
  }
8226
8701
  // src/primitives/FighterTube/FighterTube.module.css
8227
8702
  var FighterTube_module_default = {
@@ -8446,7 +8921,7 @@ function FighterTooltip(t0) {
8446
8921
  } else t7 = $[10];
8447
8922
  let t8;
8448
8923
  if ($[11] !== itemRef || $[12] !== quantity || $[13] !== type?.fighterAbilities) {
8449
- t8 = type?.fighterAbilities.filter(_temp$9).map((ability) => /* @__PURE__ */ jsx(AbilityLines, {
8924
+ t8 = type?.fighterAbilities.filter(_temp$8).map((ability) => /* @__PURE__ */ jsx(AbilityLines, {
8450
8925
  itemRef,
8451
8926
  ability,
8452
8927
  quantity
@@ -8504,7 +8979,7 @@ function FighterTooltip(t0) {
8504
8979
  } else t12 = $[26];
8505
8980
  return t12;
8506
8981
  }
8507
- function _temp$9(t0) {
8982
+ function _temp$8(t0) {
8508
8983
  const { slot } = t0;
8509
8984
  return slot !== 1;
8510
8985
  }
@@ -8856,10 +9331,13 @@ const emptyText = {
8856
9331
  };
8857
9332
  /** EVE's list of what is in a bay, as a popover anchored to `--bay-anchor`; the fighter bay's has its tubes above. */
8858
9333
  function BayContents(t0) {
8859
- const $ = c(42);
9334
+ const $ = c(34);
8860
9335
  const { id, bay, label } = t0;
8861
9336
  const store = useFitStore();
9337
+ const sde = useSde();
8862
9338
  const { start, end } = useDrag();
9339
+ const { show: showMutate } = useMutate();
9340
+ const { open, menu } = useContextMenu();
8863
9341
  const contents = useBayContents(bay);
8864
9342
  const panel = useRef(null);
8865
9343
  const drones = bay === "droneBay";
@@ -8874,7 +9352,7 @@ function BayContents(t0) {
8874
9352
  const maxActive = t1;
8875
9353
  let t2;
8876
9354
  if ($[2] !== contents || $[3] !== fighters || $[4] !== fit) {
8877
- const launched = fighters ? fit.items.flatMap(_temp$8) : [];
9355
+ const launched = fighters ? fit.items.flatMap(_temp$7) : [];
8878
9356
  t2 = [...contents.flatMap(_temp2$5), ...launched];
8879
9357
  $[2] = contents;
8880
9358
  $[3] = fighters;
@@ -8901,8 +9379,11 @@ function BayContents(t0) {
8901
9379
  }
8902
9380
  let t3;
8903
9381
  if ($[9] !== drones || $[10] !== fighters || $[11] !== store) {
8904
- t3 = (typeId, quantity) => {
8905
- if (drones) store.setDroneQuantity(typeId, quantity);
9382
+ t3 = (t4, quantity) => {
9383
+ const { type: t5, mutatedFrom } = t4;
9384
+ const { id: typeId } = t5;
9385
+ if (mutatedFrom) store.setMutatedDroneQuantity(mutatedFrom.id, quantity);
9386
+ else if (drones) store.setDroneQuantity(typeId, quantity);
8906
9387
  else if (fighters) store.setFighterBayQuantity(typeId, quantity);
8907
9388
  else store.setCargoQuantity(typeId, quantity);
8908
9389
  };
@@ -8912,11 +9393,32 @@ function BayContents(t0) {
8912
9393
  $[12] = t3;
8913
9394
  } else t3 = $[12];
8914
9395
  const setQuantity = t3;
8915
- const t4 = drones || void 0;
8916
- const t5 = fighters || void 0;
8917
- let t6;
9396
+ const openMenu = (event, t4) => {
9397
+ const { type, mutatedFrom: mutatedFrom_0, refs: refs_0 } = t4;
9398
+ const unmutated = mutatedFrom_0 ?? type;
9399
+ if (!canMutate(sde, unmutated) || mutatedFrom_0 && !mutatedDronesOf(sde, fit, mutatedFrom_0.id)) return;
9400
+ const mutate = () => {
9401
+ if (!mutatedFrom_0) store.setDronesMutation(refs_0, rollMutation(sde, type.id, mutaplasmidsOf(sde, type.id)[0].id, "base"));
9402
+ showMutate({ type: "drone_bay" }, {
9403
+ element: panel.current.parentElement,
9404
+ side: "right"
9405
+ }, unmutated.id);
9406
+ };
9407
+ open(event, [{
9408
+ label: mutatedFrom_0 ? "Edit Mutation" : "Mutate",
9409
+ onSelect: mutate
9410
+ }, mutatedFrom_0 && {
9411
+ label: "Remove Mutation",
9412
+ onSelect: () => store.setDronesMutation(refs_0, void 0)
9413
+ }]);
9414
+ };
9415
+ const t5 = BayContents_module_default;
9416
+ const t6 = "auto";
9417
+ const t7 = drones || void 0;
9418
+ const t8 = fighters || void 0;
9419
+ let t9;
8918
9420
  if ($[13] !== drones || $[14] !== maxActive || $[15] !== stats.ship) {
8919
- t6 = drones && /* @__PURE__ */ jsxs("div", {
9421
+ t9 = drones && /* @__PURE__ */ jsxs("div", {
8920
9422
  className: BayContents_module_default.activeDrones,
8921
9423
  children: [
8922
9424
  "Active drones: ",
@@ -8928,102 +9430,91 @@ function BayContents(t0) {
8928
9430
  $[13] = drones;
8929
9431
  $[14] = maxActive;
8930
9432
  $[15] = stats.ship;
8931
- $[16] = t6;
8932
- } else t6 = $[16];
8933
- let t7;
9433
+ $[16] = t9;
9434
+ } else t9 = $[16];
9435
+ let t10;
8934
9436
  if ($[17] !== fighters) {
8935
- t7 = fighters && /* @__PURE__ */ jsx(FighterTubes, {});
9437
+ t10 = fighters && /* @__PURE__ */ jsx(FighterTubes, {});
8936
9438
  $[17] = fighters;
8937
- $[18] = t7;
8938
- } else t7 = $[18];
8939
- let t8;
8940
- if ($[19] !== bay || $[20] !== contents || $[21] !== drones || $[22] !== end || $[23] !== fighters || $[24] !== fit || $[25] !== label || $[26] !== maxActive || $[27] !== setQuantity || $[28] !== start || $[29] !== store) {
8941
- t8 = contents.length === 0 ? /* @__PURE__ */ jsx("div", {
8942
- className: BayContents_module_default.none,
8943
- children: emptyText[bay]
8944
- }) : /* @__PURE__ */ jsx("ul", {
8945
- className: BayContents_module_default.list,
8946
- "aria-label": label,
8947
- children: contents.map((content) => {
8948
- const { type, quantity: quantity_0, refs: refs_0 } = content;
8949
- const drag = {
8950
- draggable: true,
8951
- onDragStart: (event) => {
8952
- const icon = event.currentTarget.closest("li").querySelector(`.${BayContents_module_default.icon}`);
8953
- event.dataTransfer.setDragImage(icon, 0, 0);
8954
- event.dataTransfer.effectAllowed = "copy";
8955
- event.dataTransfer.setData("text/plain", type.name);
8956
- start({
8957
- type: "type",
8958
- typeId: type.id
8959
- });
8960
- },
8961
- onDragEnd: end
8962
- };
8963
- const shown = refs_0.find((ref_0) => fit.items[ref_0]?.state === "active") ?? refs_0[0];
8964
- return /* @__PURE__ */ jsxs("li", {
8965
- className: BayContents_module_default.row,
8966
- children: [
8967
- /* @__PURE__ */ jsx(Quantity, {
8968
- name: type.name,
8969
- value: quantity_0,
8970
- onChange: (value) => setQuantity(type.id, value)
8971
- }),
8972
- /* @__PURE__ */ jsx(Tooltip, {
8973
- label: drones ? /* @__PURE__ */ jsx(DroneTooltip, {
8974
- itemRef: shown,
8975
- typeId: type.id
8976
- }) : void 0,
8977
- children: /* @__PURE__ */ jsx("span", {
8978
- className: BayContents_module_default.icon,
8979
- ...drag,
8980
- children: /* @__PURE__ */ jsx(TypeIcon, { typeId: type.id })
8981
- })
8982
- }),
8983
- /* @__PURE__ */ jsxs("span", {
8984
- className: BayContents_module_default.middle,
9439
+ $[18] = t10;
9440
+ } else t10 = $[18];
9441
+ const t11 = contents.length === 0 ? /* @__PURE__ */ jsx("div", {
9442
+ className: BayContents_module_default.none,
9443
+ children: emptyText[bay]
9444
+ }) : /* @__PURE__ */ jsx("ul", {
9445
+ className: BayContents_module_default.list,
9446
+ "aria-label": label,
9447
+ children: contents.map((content) => {
9448
+ const { type: type_0, quantity: quantity_0, refs: refs_1, key, mutatedFrom: mutatedFrom_1 } = content;
9449
+ const drag = {
9450
+ draggable: mutatedFrom_1 === void 0,
9451
+ onDragStart: (event_0) => {
9452
+ const icon = event_0.currentTarget.closest("li").querySelector(`.${BayContents_module_default.icon}`);
9453
+ event_0.dataTransfer.setDragImage(icon, 0, 0);
9454
+ event_0.dataTransfer.effectAllowed = "copy";
9455
+ event_0.dataTransfer.setData("text/plain", type_0.name);
9456
+ start({
9457
+ type: "type",
9458
+ typeId: type_0.id
9459
+ });
9460
+ },
9461
+ onDragEnd: end
9462
+ };
9463
+ const shown = refs_1.find((ref_0) => fit.items[ref_0]?.state === "active") ?? refs_1[0];
9464
+ const name = mutatedFrom_1 ? `Mutated ${mutatedFrom_1.name}` : type_0.name;
9465
+ return /* @__PURE__ */ jsxs("li", {
9466
+ className: BayContents_module_default.row,
9467
+ onContextMenu: drones ? (event_1) => openMenu(event_1, content) : void 0,
9468
+ children: [
9469
+ /* @__PURE__ */ jsx(Quantity, {
9470
+ name,
9471
+ value: quantity_0,
9472
+ onChange: (value) => setQuantity(content, value)
9473
+ }),
9474
+ /* @__PURE__ */ jsx(Tooltip, {
9475
+ label: drones ? /* @__PURE__ */ jsx(DroneTooltip, {
9476
+ itemRef: shown,
9477
+ typeId: type_0.id,
9478
+ mutatedFrom: mutatedFrom_1?.id
9479
+ }) : void 0,
9480
+ children: /* @__PURE__ */ jsx("span", {
9481
+ className: BayContents_module_default.icon,
8985
9482
  ...drag,
8986
- children: [/* @__PURE__ */ jsx("span", {
8987
- className: BayContents_module_default.name,
8988
- children: type.name
8989
- }), drones && /* @__PURE__ */ jsx(DroneSelection, {
8990
- content,
8991
- max: maxActive
8992
- })]
8993
- }),
8994
- /* @__PURE__ */ jsx("button", {
8995
- type: "button",
8996
- className: BayContents_module_default.remove,
8997
- "aria-label": `Remove ${type.name}`,
8998
- onClick: (event_0) => {
8999
- const row = event_0.currentTarget.closest("li");
9000
- const next = row.nextElementSibling ?? row.previousElementSibling;
9001
- store.remove(...refs_0);
9002
- if (next !== null) next.querySelector(`.${BayContents_module_default.remove}`)?.focus();
9003
- else if (!fighters) panel.current?.hidePopover();
9004
- },
9005
- children: /* @__PURE__ */ jsx(Icon, { name: "close" })
9483
+ children: /* @__PURE__ */ jsx(TypeIcon, { typeId: type_0.id })
9006
9484
  })
9007
- ]
9008
- }, type.id);
9009
- })
9010
- });
9011
- $[19] = bay;
9012
- $[20] = contents;
9013
- $[21] = drones;
9014
- $[22] = end;
9015
- $[23] = fighters;
9016
- $[24] = fit;
9017
- $[25] = label;
9018
- $[26] = maxActive;
9019
- $[27] = setQuantity;
9020
- $[28] = start;
9021
- $[29] = store;
9022
- $[30] = t8;
9023
- } else t8 = $[30];
9024
- let t9;
9025
- if ($[31] !== all || $[32] !== store) {
9026
- t9 = all.length > 0 && /* @__PURE__ */ jsx("button", {
9485
+ }),
9486
+ /* @__PURE__ */ jsxs("span", {
9487
+ className: BayContents_module_default.middle,
9488
+ ...drag,
9489
+ children: [/* @__PURE__ */ jsx("span", {
9490
+ className: BayContents_module_default.name,
9491
+ "data-mutated": mutatedFrom_1 !== void 0 || void 0,
9492
+ children: name
9493
+ }), drones && /* @__PURE__ */ jsx(DroneSelection, {
9494
+ content,
9495
+ max: maxActive
9496
+ })]
9497
+ }),
9498
+ /* @__PURE__ */ jsx("button", {
9499
+ type: "button",
9500
+ className: BayContents_module_default.remove,
9501
+ "aria-label": `Remove ${name}`,
9502
+ onClick: (event_2) => {
9503
+ const row = event_2.currentTarget.closest("li");
9504
+ const next = row.nextElementSibling ?? row.previousElementSibling;
9505
+ store.remove(...refs_1);
9506
+ if (next !== null) next.querySelector(`.${BayContents_module_default.remove}`)?.focus();
9507
+ else if (!fighters) panel.current?.hidePopover();
9508
+ },
9509
+ children: /* @__PURE__ */ jsx(Icon, { name: "close" })
9510
+ })
9511
+ ]
9512
+ }, key);
9513
+ })
9514
+ });
9515
+ let t12;
9516
+ if ($[19] !== all || $[20] !== panel || $[21] !== store) {
9517
+ t12 = all.length > 0 && /* @__PURE__ */ jsx("button", {
9027
9518
  type: "button",
9028
9519
  className: BayContents_module_default.removeAll,
9029
9520
  onClick: () => {
@@ -9032,99 +9523,114 @@ function BayContents(t0) {
9032
9523
  },
9033
9524
  children: "Remove All"
9034
9525
  });
9035
- $[31] = all;
9036
- $[32] = store;
9037
- $[33] = t9;
9038
- } else t9 = $[33];
9039
- let t10;
9040
- if ($[34] !== id || $[35] !== t4 || $[36] !== t5 || $[37] !== t6 || $[38] !== t7 || $[39] !== t8 || $[40] !== t9) {
9041
- t10 = /* @__PURE__ */ jsxs("div", {
9526
+ $[19] = all;
9527
+ $[20] = panel;
9528
+ $[21] = store;
9529
+ $[22] = t12;
9530
+ } else t12 = $[22];
9531
+ let t13;
9532
+ if ($[23] !== id || $[24] !== menu || $[25] !== panel || $[26] !== t10 || $[27] !== t11 || $[28] !== t12 || $[29] !== t5.panel || $[30] !== t7 || $[31] !== t8 || $[32] !== t9) {
9533
+ t13 = /* @__PURE__ */ jsxs("div", {
9042
9534
  ref: panel,
9043
9535
  id,
9044
- className: BayContents_module_default.panel,
9045
- popover: "auto",
9046
- "data-drones": t4,
9047
- "data-fighters": t5,
9536
+ className: t5.panel,
9537
+ popover: t6,
9538
+ "data-drones": t7,
9539
+ "data-fighters": t8,
9048
9540
  children: [
9049
- t6,
9050
- t7,
9051
- t8,
9052
- t9
9541
+ t9,
9542
+ t10,
9543
+ menu,
9544
+ t11,
9545
+ t12
9053
9546
  ]
9054
9547
  });
9055
- $[34] = id;
9056
- $[35] = t4;
9057
- $[36] = t5;
9058
- $[37] = t6;
9059
- $[38] = t7;
9060
- $[39] = t8;
9061
- $[40] = t9;
9062
- $[41] = t10;
9063
- } else t10 = $[41];
9064
- return t10;
9548
+ $[23] = id;
9549
+ $[24] = menu;
9550
+ $[25] = panel;
9551
+ $[26] = t10;
9552
+ $[27] = t11;
9553
+ $[28] = t12;
9554
+ $[29] = t5.panel;
9555
+ $[30] = t7;
9556
+ $[31] = t8;
9557
+ $[32] = t9;
9558
+ $[33] = t13;
9559
+ } else t13 = $[33];
9560
+ return t13;
9065
9561
  }
9066
9562
  /** One box per drone the character can launch. */
9067
9563
  function _temp2$5(t0) {
9068
9564
  const { refs } = t0;
9069
9565
  return refs;
9070
9566
  }
9071
- function _temp$8(item, ref) {
9567
+ function _temp$7(item, ref) {
9072
9568
  return item.slot.type === "fighter_tube" ? [ref] : [];
9073
9569
  }
9074
9570
  function DroneSelection(t0) {
9075
- const $ = c(16);
9571
+ const $ = c(18);
9076
9572
  const { content: t1, max } = t0;
9077
- const { type, quantity, active } = t1;
9573
+ const { type, quantity, active, mutatedFrom } = t1;
9078
9574
  const store = useFitStore();
9079
- const room = useDroneRoom(type);
9080
- const t2 = `Active ${type.name}`;
9081
- let t3;
9082
- if ($[0] !== active || $[1] !== max || $[2] !== quantity || $[3] !== room || $[4] !== store || $[5] !== type.id) {
9083
- let t4;
9084
- if ($[7] !== active || $[8] !== quantity || $[9] !== room || $[10] !== store || $[11] !== type.id) {
9085
- t4 = (_, index) => {
9086
- const count = index + 1;
9087
- const state = count <= active ? "active" : count > quantity ? "none" : count <= active + room ? "open" : "over";
9575
+ const room = useDroneRoom(mutatedFrom ?? type);
9576
+ let t2;
9577
+ if ($[0] !== mutatedFrom || $[1] !== store || $[2] !== type) {
9578
+ t2 = (count) => {
9579
+ if (mutatedFrom) store.setActiveMutatedDrones(mutatedFrom.id, count);
9580
+ else store.setActiveDrones(type.id, count);
9581
+ };
9582
+ $[0] = mutatedFrom;
9583
+ $[1] = store;
9584
+ $[2] = type;
9585
+ $[3] = t2;
9586
+ } else t2 = $[3];
9587
+ const select = t2;
9588
+ const t3 = `Active ${mutatedFrom ? `Mutated ${mutatedFrom.name}` : type.name}`;
9589
+ let t4;
9590
+ if ($[4] !== active || $[5] !== max || $[6] !== quantity || $[7] !== room || $[8] !== select) {
9591
+ let t5;
9592
+ if ($[10] !== active || $[11] !== quantity || $[12] !== room || $[13] !== select) {
9593
+ t5 = (_, index) => {
9594
+ const count_0 = index + 1;
9595
+ const state = count_0 <= active ? "active" : count_0 > quantity ? "none" : count_0 <= active + room ? "open" : "over";
9088
9596
  return /* @__PURE__ */ jsx("button", {
9089
9597
  type: "button",
9090
9598
  className: BayContents_module_default.box,
9091
- "aria-label": `${count} active`,
9092
- "aria-pressed": count === active,
9599
+ "aria-label": `${count_0} active`,
9600
+ "aria-pressed": count_0 === active,
9093
9601
  "data-state": state,
9094
9602
  disabled: state === "over" || state === "none",
9095
- onClick: () => store.setActiveDrones(type.id, count === active ? count - 1 : count),
9096
- children: count <= active && "×"
9097
- }, count);
9603
+ onClick: () => select(count_0 === active ? count_0 - 1 : count_0),
9604
+ children: count_0 <= active && "×"
9605
+ }, count_0);
9098
9606
  };
9099
- $[7] = active;
9100
- $[8] = quantity;
9101
- $[9] = room;
9102
- $[10] = store;
9103
- $[11] = type.id;
9104
- $[12] = t4;
9105
- } else t4 = $[12];
9106
- t3 = Array.from({ length: Math.max(max, active) }, t4);
9107
- $[0] = active;
9108
- $[1] = max;
9109
- $[2] = quantity;
9110
- $[3] = room;
9111
- $[4] = store;
9112
- $[5] = type.id;
9113
- $[6] = t3;
9114
- } else t3 = $[6];
9115
- let t4;
9116
- if ($[13] !== t2 || $[14] !== t3) {
9117
- t4 = /* @__PURE__ */ jsxs("span", {
9607
+ $[10] = active;
9608
+ $[11] = quantity;
9609
+ $[12] = room;
9610
+ $[13] = select;
9611
+ $[14] = t5;
9612
+ } else t5 = $[14];
9613
+ t4 = Array.from({ length: Math.max(max, active) }, t5);
9614
+ $[4] = active;
9615
+ $[5] = max;
9616
+ $[6] = quantity;
9617
+ $[7] = room;
9618
+ $[8] = select;
9619
+ $[9] = t4;
9620
+ } else t4 = $[9];
9621
+ let t5;
9622
+ if ($[15] !== t3 || $[16] !== t4) {
9623
+ t5 = /* @__PURE__ */ jsxs("span", {
9118
9624
  className: BayContents_module_default.selection,
9119
9625
  role: "group",
9120
- "aria-label": t2,
9121
- children: ["Selected:", t3]
9626
+ "aria-label": t3,
9627
+ children: ["Selected:", t4]
9122
9628
  });
9123
- $[13] = t2;
9124
- $[14] = t3;
9125
- $[15] = t4;
9126
- } else t4 = $[15];
9127
- return t4;
9629
+ $[15] = t3;
9630
+ $[16] = t4;
9631
+ $[17] = t5;
9632
+ } else t5 = $[17];
9633
+ return t5;
9128
9634
  }
9129
9635
  /** EVE's count of a row, which turns into a spinner on hover and focus. */
9130
9636
  function Quantity(t0) {
@@ -9777,11 +10283,7 @@ function FitName() {
9777
10283
  } else t7 = $[16];
9778
10284
  let t8;
9779
10285
  if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
9780
- t8 = /* @__PURE__ */ jsx(NotImplementedButton, {
9781
- className: FittingWindow_module_default.icon,
9782
- icon: "link",
9783
- label: "Link Fit"
9784
- });
10286
+ t8 = /* @__PURE__ */ jsx(LinkFitButton, {});
9785
10287
  $[17] = t8;
9786
10288
  } else t8 = $[17];
9787
10289
  let t9;
@@ -9792,7 +10294,7 @@ function FitName() {
9792
10294
  defaultValue: fit.name,
9793
10295
  placeholder: ship?.name,
9794
10296
  ref: input,
9795
- onFocus: _temp$7,
10297
+ onFocus: _temp$6,
9796
10298
  onBlur: (event_1) => rename(event_1.currentTarget.value),
9797
10299
  onKeyDown: (event_2) => {
9798
10300
  if (event_2.key === "Escape") event_2.currentTarget.value = fit.name ?? "";
@@ -9835,7 +10337,7 @@ function FitName() {
9835
10337
  } else t10 = $[27];
9836
10338
  return t10;
9837
10339
  }
9838
- function _temp$7(event_0) {
10340
+ function _temp$6(event_0) {
9839
10341
  return event_0.currentTarget.select();
9840
10342
  }
9841
10343
  function PreviewName() {
@@ -9988,41 +10490,55 @@ function _temp2$4(rule) {
9988
10490
  rule
9989
10491
  };
9990
10492
  }
9991
- function NotImplementedButton(t0) {
9992
- const $ = c(9);
9993
- const { className, icon, label } = t0;
9994
- const t1 = `${label} (not implemented yet)`;
10493
+ function LinkFitButton() {
10494
+ const $ = c(13);
10495
+ const link = useFitLink();
10496
+ const { copy, dialog } = useCopyText("Link Fit", "link", 4);
10497
+ const [copied, flashCopied] = useFlash();
10498
+ const t0 = copied ? "Link copied" : "Link Fit";
10499
+ let t1;
10500
+ if ($[0] !== copy || $[1] !== flashCopied || $[2] !== link) {
10501
+ t1 = () => copy(link, flashCopied);
10502
+ $[0] = copy;
10503
+ $[1] = flashCopied;
10504
+ $[2] = link;
10505
+ $[3] = t1;
10506
+ } else t1 = $[3];
9995
10507
  let t2;
9996
- if ($[0] !== icon) {
9997
- t2 = /* @__PURE__ */ jsx(Icon, { name: icon });
9998
- $[0] = icon;
9999
- $[1] = t2;
10000
- } else t2 = $[1];
10508
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
10509
+ t2 = /* @__PURE__ */ jsx(Icon, { name: "link" });
10510
+ $[4] = t2;
10511
+ } else t2 = $[4];
10001
10512
  let t3;
10002
- if ($[2] !== className || $[3] !== label || $[4] !== t2) {
10513
+ if ($[5] !== t1) {
10003
10514
  t3 = /* @__PURE__ */ jsx("button", {
10004
10515
  type: "button",
10005
- className,
10006
- "aria-label": label,
10007
- "aria-disabled": true,
10516
+ className: FittingWindow_module_default.icon,
10517
+ "aria-label": "Link Fit",
10518
+ onClick: t1,
10008
10519
  children: t2
10009
10520
  });
10010
- $[2] = className;
10011
- $[3] = label;
10012
- $[4] = t2;
10013
- $[5] = t3;
10014
- } else t3 = $[5];
10521
+ $[5] = t1;
10522
+ $[6] = t3;
10523
+ } else t3 = $[6];
10015
10524
  let t4;
10016
- if ($[6] !== t1 || $[7] !== t3) {
10525
+ if ($[7] !== t0 || $[8] !== t3) {
10017
10526
  t4 = /* @__PURE__ */ jsx(Tooltip, {
10018
- label: t1,
10527
+ label: t0,
10019
10528
  children: t3
10020
10529
  });
10021
- $[6] = t1;
10022
- $[7] = t3;
10023
- $[8] = t4;
10024
- } else t4 = $[8];
10025
- return t4;
10530
+ $[7] = t0;
10531
+ $[8] = t3;
10532
+ $[9] = t4;
10533
+ } else t4 = $[9];
10534
+ let t5;
10535
+ if ($[10] !== dialog || $[11] !== t4) {
10536
+ t5 = /* @__PURE__ */ jsxs(Fragment$1, { children: [t4, dialog] });
10537
+ $[10] = dialog;
10538
+ $[11] = t4;
10539
+ $[12] = t5;
10540
+ } else t5 = $[12];
10541
+ return t5;
10026
10542
  }
10027
10543
  function Bay({ bay, icon, label, unlimited = false, id: givenId, readOnly = false }) {
10028
10544
  const { used, total } = useBayUsage(bay);
@@ -10453,38 +10969,6 @@ function SimulationHistory() {
10453
10969
  } else t1 = $[9];
10454
10970
  return t1;
10455
10971
  }
10456
- // src/components/ItemBrowser/ItemBrowser.module.css
10457
- var ItemBrowser_module_default = {
10458
- "action": "xFSZwa_action",
10459
- "actions": "xFSZwa_actions",
10460
- "browser": "xFSZwa_browser",
10461
- "collapse": "xFSZwa_collapse",
10462
- "confirm": "xFSZwa_confirm",
10463
- "copy": "xFSZwa_copy",
10464
- "copyAnchor": "xFSZwa_copyAnchor",
10465
- "count": "xFSZwa_count",
10466
- "counts": "xFSZwa_counts",
10467
- "dialogButtons": "xFSZwa_dialogButtons",
10468
- "dragImage": "xFSZwa_dragImage",
10469
- "empty": "xFSZwa_empty",
10470
- "field": "xFSZwa_field",
10471
- "filters": "xFSZwa_filters",
10472
- "flyable": "xFSZwa_flyable",
10473
- "form": "xFSZwa_form",
10474
- "hull": "xFSZwa_hull",
10475
- "importError": "xFSZwa_importError",
10476
- "info": "xFSZwa_info",
10477
- "kind": "xFSZwa_kind",
10478
- "menu": "xFSZwa_menu",
10479
- "panel": "xFSZwa_panel",
10480
- "search": "xFSZwa_search",
10481
- "simulate": "xFSZwa_simulate",
10482
- "tab": "xFSZwa_tab",
10483
- "tabs": "xFSZwa_tabs",
10484
- "tree": "xFSZwa_tree",
10485
- "unseen": "xFSZwa_unseen",
10486
- "views": "xFSZwa_views"
10487
- };
10488
10972
  // src/components/ItemBrowser/Search.tsx
10489
10973
  /** The search field above a list of the `ItemBrowser`, after a button that collapses every group. */
10490
10974
  function Search(t0) {
@@ -10708,7 +11192,7 @@ function useTypeActions(noHullSelected) {
10708
11192
  if (slot !== void 0) showMutate(slot, {
10709
11193
  element: anchor,
10710
11194
  side: "right"
10711
- });
11195
+ }, type_1.id);
10712
11196
  }
10713
11197
  }
10714
11198
  ]);
@@ -11202,102 +11686,7 @@ function Charges(t0) {
11202
11686
  } else t12 = $[47];
11203
11687
  return t12;
11204
11688
  }
11205
- // src/components/ItemBrowser/copyFit.tsx
11206
- /** Copies a fit to the clipboard, or shows it in `dialog` when the browser refuses; render `dialog` once. */
11207
- function useCopyFit() {
11208
- const $ = c(11);
11209
- const engine = useEngine();
11210
- const [refused, setRefused] = useState();
11211
- let t0;
11212
- if ($[0] !== engine) {
11213
- t0 = (fit, format, onCopied) => {
11214
- const text = engine.saveText(fit, format);
11215
- Promise.resolve().then(() => navigator.clipboard.writeText(text)).then(onCopied, () => setRefused(text));
11216
- };
11217
- $[0] = engine;
11218
- $[1] = t0;
11219
- } else t0 = $[1];
11220
- const copy = t0;
11221
- const t1 = refused !== void 0;
11222
- let t2;
11223
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
11224
- t2 = () => setRefused(void 0);
11225
- $[2] = t2;
11226
- } else t2 = $[2];
11227
- const t3 = refused ?? "";
11228
- let t4;
11229
- if ($[3] !== t3) {
11230
- t4 = /* @__PURE__ */ jsx(CopyForm, { text: t3 });
11231
- $[3] = t3;
11232
- $[4] = t4;
11233
- } else t4 = $[4];
11234
- let t5;
11235
- if ($[5] !== t1 || $[6] !== t4) {
11236
- t5 = /* @__PURE__ */ jsx(Dialog, {
11237
- open: t1,
11238
- title: "Copy Fit",
11239
- onClose: t2,
11240
- children: t4
11241
- });
11242
- $[5] = t1;
11243
- $[6] = t4;
11244
- $[7] = t5;
11245
- } else t5 = $[7];
11246
- let t6;
11247
- if ($[8] !== copy || $[9] !== t5) {
11248
- t6 = {
11249
- copy,
11250
- dialog: t5
11251
- };
11252
- $[8] = copy;
11253
- $[9] = t5;
11254
- $[10] = t6;
11255
- } else t6 = $[10];
11256
- return t6;
11257
- }
11258
- function CopyForm(t0) {
11259
- const $ = c(8);
11260
- const { text } = t0;
11261
- const id = useId();
11262
- let t1;
11263
- if ($[0] !== id) {
11264
- t1 = /* @__PURE__ */ jsx("label", {
11265
- htmlFor: id,
11266
- children: "The browser blocked the clipboard. Copy the fit from here."
11267
- });
11268
- $[0] = id;
11269
- $[1] = t1;
11270
- } else t1 = $[1];
11271
- let t2;
11272
- if ($[2] !== id || $[3] !== text) {
11273
- t2 = /* @__PURE__ */ jsx("textarea", {
11274
- id,
11275
- rows: 12,
11276
- readOnly: true,
11277
- value: text,
11278
- onFocus: _temp$6
11279
- });
11280
- $[2] = id;
11281
- $[3] = text;
11282
- $[4] = t2;
11283
- } else t2 = $[4];
11284
- let t3;
11285
- if ($[5] !== t1 || $[6] !== t2) {
11286
- t3 = /* @__PURE__ */ jsxs("div", {
11287
- className: ItemBrowser_module_default.form,
11288
- children: [t1, t2]
11289
- });
11290
- $[5] = t1;
11291
- $[6] = t2;
11292
- $[7] = t3;
11293
- } else t3 = $[7];
11294
- return t3;
11295
- }
11296
- function _temp$6(event) {
11297
- return event.currentTarget.select();
11298
- }
11299
11689
  // src/components/ItemBrowser/FitActions.tsx
11300
- const FLASH_MS = 2e3;
11301
11690
  /** The buttons under the `ItemBrowser`: save the fit in the browser, import one, or copy it out. */
11302
11691
  function FitActions(t0) {
11303
11692
  const $ = c(80);
@@ -11943,45 +12332,11 @@ function ImportForm(t0) {
11943
12332
  } else t14 = $[32];
11944
12333
  return t14;
11945
12334
  }
12335
+ /** Fits a mutated item from the game in the first free slot of its rack, rolled as it is. */
11946
12336
  function _temp3$1() {}
11947
12337
  function _temp2$3() {
11948
12338
  return navigator.clipboard.readText();
11949
12339
  }
11950
- function useFlash() {
11951
- const $ = c(6);
11952
- const [shown, setShown] = useState(0);
11953
- let t0;
11954
- let t1;
11955
- if ($[0] !== shown) {
11956
- t0 = () => {
11957
- if (shown === 0) return;
11958
- const timer = setTimeout(() => setShown(0), FLASH_MS);
11959
- return () => clearTimeout(timer);
11960
- };
11961
- t1 = [shown];
11962
- $[0] = shown;
11963
- $[1] = t0;
11964
- $[2] = t1;
11965
- } else {
11966
- t0 = $[1];
11967
- t1 = $[2];
11968
- }
11969
- useEffect(t0, t1);
11970
- const t2 = shown > 0;
11971
- let t3;
11972
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
11973
- t3 = () => setShown(Date.now());
11974
- $[3] = t3;
11975
- } else t3 = $[3];
11976
- let t4;
11977
- if ($[4] !== t2) {
11978
- t4 = [t2, t3];
11979
- $[4] = t2;
11980
- $[5] = t4;
11981
- } else t4 = $[5];
11982
- return t4;
11983
- }
11984
- /** Fits a mutated item from the game in the first free slot of its rack, rolled as it is. */
11985
12340
  async function fitMutated(engine, store, typeId, itemId) {
11986
12341
  const roll = await engine.loadMutation(typeId, itemId);
11987
12342
  if (store.fitMutated(roll) === void 0) throw new Error("This item does not fit on the ship");