dirk-cfx-react 1.1.62 → 1.1.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,9 +7,9 @@ var zustand = require('zustand');
7
7
  var axios = require('axios');
8
8
  var reactFontawesome = require('@fortawesome/react-fontawesome');
9
9
  var framerMotion = require('framer-motion');
10
+ var lucideReact = require('lucide-react');
10
11
  var clickSoundUrl = require('./click_sound-PNCRRTM4.mp3');
11
12
  var hoverSoundUrl = require('./hover_sound-NBUA222C.mp3');
12
- var lucideReact = require('lucide-react');
13
13
  var reactQuery = require('@tanstack/react-query');
14
14
  require('@mantine/core/styles.css');
15
15
  require('@mantine/notifications/styles.css');
@@ -1079,6 +1079,31 @@ function BlipColorSelect({ value, onChange, label: label2 = "Blip Color", size =
1079
1079
  }
1080
1080
  );
1081
1081
  }
1082
+ var BLIP_DISPLAY_DATA = [
1083
+ { value: "2", label: "2 \u2014 Main map + minimap (selectable)" },
1084
+ { value: "3", label: "3 \u2014 Main map only (selectable)" },
1085
+ { value: "4", label: "4 \u2014 Main map only (selectable)" },
1086
+ { value: "5", label: "5 \u2014 Minimap only" },
1087
+ { value: "6", label: "6 \u2014 Main map + minimap (selectable)" },
1088
+ { value: "8", label: "8 \u2014 Main map + minimap (not selectable)" },
1089
+ { value: "9", label: "9 \u2014 Minimap only" },
1090
+ { value: "10", label: "10 \u2014 Main map + minimap (not selectable)" }
1091
+ ];
1092
+ function BlipDisplaySelect({ value, onChange, label: label2 = "Blip Display", size = "xs", ...rest }) {
1093
+ return /* @__PURE__ */ jsxRuntime.jsx(
1094
+ core.Select,
1095
+ {
1096
+ label: label2,
1097
+ size,
1098
+ ...rest,
1099
+ data: BLIP_DISPLAY_DATA,
1100
+ value: value != null ? String(value) : null,
1101
+ onChange: (val) => val != null && onChange(Number(val)),
1102
+ allowDeselect: false,
1103
+ maxDropdownHeight: 300
1104
+ }
1105
+ );
1106
+ }
1082
1107
 
1083
1108
  // src/utils/colorWithAlpha.ts
1084
1109
  var colorNames = {
@@ -1225,11 +1250,11 @@ var colorNames = {
1225
1250
  Yellow: { r: 255, g: 255, b: 0 },
1226
1251
  YellowGreen: { r: 154, g: 205, b: 50 }
1227
1252
  };
1228
- function colorWithAlpha(color, alpha8) {
1253
+ function colorWithAlpha(color, alpha9) {
1229
1254
  const lowerCasedColor = color.toLowerCase();
1230
1255
  if (colorNames[lowerCasedColor]) {
1231
1256
  const rgb = colorNames[lowerCasedColor];
1232
- return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha8})`;
1257
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha9})`;
1233
1258
  }
1234
1259
  if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
1235
1260
  const hex = color.slice(1);
@@ -1237,12 +1262,12 @@ function colorWithAlpha(color, alpha8) {
1237
1262
  const r = bigint >> 16 & 255;
1238
1263
  const g = bigint >> 8 & 255;
1239
1264
  const b = bigint & 255;
1240
- return `rgba(${r}, ${g}, ${b}, ${alpha8})`;
1265
+ return `rgba(${r}, ${g}, ${b}, ${alpha9})`;
1241
1266
  }
1242
1267
  if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
1243
1268
  const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
1244
1269
  if (result) {
1245
- return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha8})`;
1270
+ return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha9})`;
1246
1271
  }
1247
1272
  }
1248
1273
  return color;
@@ -1315,8 +1340,12 @@ async function fetchNui(eventName, data, mockData) {
1315
1340
  }
1316
1341
  const overrideResourceName = useSettings.getState().overideResourceName;
1317
1342
  const resourceName = window.GetParentResourceName ? window.GetParentResourceName() : overrideResourceName ? overrideResourceName : "dirk-cfx-react";
1318
- const resp = await fetch(`https://${resourceName}/${eventName}`, options);
1319
- return await resp.json();
1343
+ try {
1344
+ const resp = await fetch(`https://${resourceName}/${eventName}`, options);
1345
+ return await resp.json();
1346
+ } catch {
1347
+ return mockData ?? {};
1348
+ }
1320
1349
  }
1321
1350
  var initialFetches = {};
1322
1351
  async function registerInitialFetch(eventName, data, mockData) {
@@ -1363,6 +1392,13 @@ var internalEvent = (events, timer = 1e3) => {
1363
1392
  }
1364
1393
  }
1365
1394
  };
1395
+ var reportedMissing = /* @__PURE__ */ new Set();
1396
+ function reportMissingLocale(key) {
1397
+ if (!key || reportedMissing.has(key)) return;
1398
+ reportedMissing.add(key);
1399
+ fetchNui("REPORT_MISSING_LOCALE", { key }).catch(() => {
1400
+ });
1401
+ }
1366
1402
  var localeStore = zustand.create((set, get) => {
1367
1403
  return {
1368
1404
  locales: {
@@ -1370,6 +1406,7 @@ var localeStore = zustand.create((set, get) => {
1370
1406
  },
1371
1407
  locale: (key, ...args) => {
1372
1408
  const exists = get().locales[key];
1409
+ if (!exists) reportMissingLocale(key);
1373
1410
  let translation = exists || key;
1374
1411
  if (args.length) {
1375
1412
  translation = translation.replace(/%s/g, () => String(args.shift() || ""));
@@ -1383,6 +1420,14 @@ registerInitialFetch("GET_LOCALES", void 0).then((data) => {
1383
1420
  localeStore.setState({ locales: data });
1384
1421
  }).catch(() => {
1385
1422
  });
1423
+ if (typeof window !== "undefined") {
1424
+ window.addEventListener("message", (event) => {
1425
+ const msg = event.data;
1426
+ if (!msg || msg.action !== "UPDATE_DIRK_LIB_LOCALES") return;
1427
+ if (!msg.data || typeof msg.data !== "object") return;
1428
+ localeStore.setState({ locales: msg.data });
1429
+ });
1430
+ }
1386
1431
 
1387
1432
  // src/utils/map.ts
1388
1433
  var mapCenter = [-119.43, 58.84];
@@ -2545,8 +2590,8 @@ function InputContainer(props) {
2545
2590
  (props.title || props.description) && /* @__PURE__ */ jsxRuntime.jsxs(
2546
2591
  core.Flex,
2547
2592
  {
2548
- direction: "column",
2549
- gap: "xxs",
2593
+ align: "center",
2594
+ flex: 1,
2550
2595
  p: props.p == "0" ? "sm" : 0,
2551
2596
  children: [
2552
2597
  props.title && /* @__PURE__ */ jsxRuntime.jsx(
@@ -2563,12 +2608,26 @@ function InputContainer(props) {
2563
2608
  }
2564
2609
  ),
2565
2610
  props.description && /* @__PURE__ */ jsxRuntime.jsx(
2566
- core.Text,
2611
+ core.Tooltip,
2567
2612
  {
2568
- size: "xs",
2569
- c: "rgba(255, 255, 255, 0.8)",
2570
- fw: 400,
2571
- children: props.description
2613
+ label: props.description,
2614
+ position: "top-end",
2615
+ withArrow: true,
2616
+ multiline: true,
2617
+ maw: "22vh",
2618
+ styles: {
2619
+ tooltip: {
2620
+ background: core.alpha(theme2.colors.dark[7], 0.95),
2621
+ border: `0.1vh solid rgba(255,255,255,0.1)`,
2622
+ color: "rgba(255,255,255,0.75)",
2623
+ fontFamily: "Akrobat Bold",
2624
+ fontSize: "1.3vh",
2625
+ lineHeight: 1.3,
2626
+ padding: "0.6vh 0.8vh",
2627
+ letterSpacing: "0.03em"
2628
+ }
2629
+ },
2630
+ children: /* @__PURE__ */ jsxRuntime.jsx(core.Flex, { align: "center", justify: "center", style: { marginLeft: "auto", cursor: "help" }, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { size: "1.6vh", color: core.alpha(theme2.colors[theme2.primaryColor][5], 0.45) }) })
2572
2631
  }
2573
2632
  )
2574
2633
  ]
@@ -2585,13 +2644,7 @@ function InputContainer(props) {
2585
2644
  children: props.error
2586
2645
  }
2587
2646
  ),
2588
- /* @__PURE__ */ jsxRuntime.jsx(
2589
- core.Flex,
2590
- {
2591
- ml: "auto",
2592
- children: props.rightSection
2593
- }
2594
- )
2647
+ props.rightSection && /* @__PURE__ */ jsxRuntime.jsx(core.Flex, { children: props.rightSection })
2595
2648
  ]
2596
2649
  }
2597
2650
  ),
@@ -4724,6 +4777,219 @@ function SelectItem(props) {
4724
4777
  }
4725
4778
  );
4726
4779
  }
4780
+ var ZERO = { x: 0, y: 0, z: 0, w: 0 };
4781
+ function PositionPicker(props) {
4782
+ const {
4783
+ label: label2,
4784
+ value,
4785
+ onChange,
4786
+ relativeTo,
4787
+ fetchEvent = "GET_POSITION",
4788
+ previewEvent = "PREVIEW_POSITION",
4789
+ stopPreviewEvent = "STOP_PREVIEW_POSITION",
4790
+ description: description2,
4791
+ showHeading = true
4792
+ } = props;
4793
+ const theme2 = core.useMantineTheme();
4794
+ const color = theme2.colors[theme2.primaryColor][5];
4795
+ const [previewing, setPreviewing] = React5.useState(false);
4796
+ const previewingRef = React5.useRef(false);
4797
+ React5.useEffect(() => {
4798
+ return () => {
4799
+ if (previewingRef.current) {
4800
+ fetchNui(stopPreviewEvent, { relativeTo }).catch(() => {
4801
+ });
4802
+ }
4803
+ };
4804
+ }, [stopPreviewEvent, relativeTo]);
4805
+ const set = (key, val) => {
4806
+ const next = { ...value, [key]: val };
4807
+ onChange(next);
4808
+ if (previewingRef.current) {
4809
+ fetchNui(previewEvent, { value: next, relativeTo }).catch(() => {
4810
+ });
4811
+ }
4812
+ };
4813
+ const grab = async () => {
4814
+ try {
4815
+ const resp = await fetchNui(fetchEvent, { relativeTo }, value);
4816
+ if (resp && typeof resp === "object") {
4817
+ const next = {
4818
+ x: Number(resp.x ?? 0),
4819
+ y: Number(resp.y ?? 0),
4820
+ z: Number(resp.z ?? 0),
4821
+ w: Number(resp.w ?? 0)
4822
+ };
4823
+ onChange(next);
4824
+ if (previewingRef.current) {
4825
+ fetchNui(previewEvent, { value: next, relativeTo }).catch(() => {
4826
+ });
4827
+ }
4828
+ }
4829
+ } catch {
4830
+ }
4831
+ };
4832
+ const togglePreview = async () => {
4833
+ const nextState = !previewing;
4834
+ setPreviewing(nextState);
4835
+ previewingRef.current = nextState;
4836
+ if (nextState) {
4837
+ await fetchNui(previewEvent, { value, relativeTo }).catch(() => {
4838
+ });
4839
+ } else {
4840
+ await fetchNui(stopPreviewEvent, { relativeTo }).catch(() => {
4841
+ });
4842
+ }
4843
+ };
4844
+ const reset = () => {
4845
+ onChange({ ...ZERO });
4846
+ if (previewingRef.current) {
4847
+ fetchNui(previewEvent, { value: ZERO, relativeTo }).catch(() => {
4848
+ });
4849
+ }
4850
+ };
4851
+ const numberStyles = {
4852
+ input: { textAlign: "right", fontFamily: "monospace" }
4853
+ };
4854
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4855
+ core.Flex,
4856
+ {
4857
+ direction: "column",
4858
+ gap: "xxs",
4859
+ p: "xs",
4860
+ style: {
4861
+ background: core.alpha(theme2.colors.dark[5], 0.35),
4862
+ border: "0.1vh solid rgba(255,255,255,0.05)",
4863
+ borderRadius: theme2.radius.xs
4864
+ },
4865
+ children: [
4866
+ (label2 || description2) && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { justify: "space-between", align: "center", gap: "xs", children: [
4867
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { direction: "column", gap: 0, style: { minWidth: 0 }, children: [
4868
+ label2 && /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { align: "center", gap: "xxs", children: [
4869
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { size: "1.4vh", color: core.alpha(color, 0.7) }),
4870
+ /* @__PURE__ */ jsxRuntime.jsx(
4871
+ core.Text,
4872
+ {
4873
+ ff: "Akrobat Bold",
4874
+ size: "xxs",
4875
+ tt: "uppercase",
4876
+ lts: "0.05em",
4877
+ c: "rgba(255,255,255,0.75)",
4878
+ children: locale(label2)
4879
+ }
4880
+ ),
4881
+ relativeTo && /* @__PURE__ */ jsxRuntime.jsxs(core.Text, { ff: "Akrobat Bold", size: "xxs", c: core.alpha(color, 0.5), lts: "0.05em", children: [
4882
+ "\xB7 ",
4883
+ locale("RelativeTo"),
4884
+ " ",
4885
+ relativeTo
4886
+ ] })
4887
+ ] }),
4888
+ description2 && /* @__PURE__ */ jsxRuntime.jsx(core.Text, { ff: "Akrobat Bold", size: "xxs", c: "dimmed", lh: 1.3, children: locale(description2) })
4889
+ ] }),
4890
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xxs", style: { flexShrink: 0 }, children: [
4891
+ /* @__PURE__ */ jsxRuntime.jsx(PickerButton, { tooltip: locale("GrabMyPosition"), onClick: grab, color, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crosshair, { size: "1.4vh", color }) }),
4892
+ /* @__PURE__ */ jsxRuntime.jsx(
4893
+ PickerButton,
4894
+ {
4895
+ tooltip: previewing ? locale("StopPreview") : locale("PreviewInWorld"),
4896
+ onClick: togglePreview,
4897
+ color,
4898
+ active: previewing,
4899
+ children: previewing ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { size: "1.4vh", color }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { size: "1.4vh", color: core.alpha(color, 0.7) })
4900
+ }
4901
+ ),
4902
+ /* @__PURE__ */ jsxRuntime.jsx(PickerButton, { tooltip: locale("Reset"), onClick: reset, color: "#ef4444", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { size: "1.4vh", color: "#ef4444" }) })
4903
+ ] })
4904
+ ] }),
4905
+ /* @__PURE__ */ jsxRuntime.jsxs(core.Flex, { gap: "xxs", children: [
4906
+ /* @__PURE__ */ jsxRuntime.jsx(
4907
+ core.NumberInput,
4908
+ {
4909
+ size: "xs",
4910
+ label: "X",
4911
+ value: value.x,
4912
+ onChange: (v) => set("x", Number(v)),
4913
+ decimalScale: 4,
4914
+ step: 0.1,
4915
+ style: { flex: 1 },
4916
+ styles: numberStyles
4917
+ }
4918
+ ),
4919
+ /* @__PURE__ */ jsxRuntime.jsx(
4920
+ core.NumberInput,
4921
+ {
4922
+ size: "xs",
4923
+ label: "Y",
4924
+ value: value.y,
4925
+ onChange: (v) => set("y", Number(v)),
4926
+ decimalScale: 4,
4927
+ step: 0.1,
4928
+ style: { flex: 1 },
4929
+ styles: numberStyles
4930
+ }
4931
+ ),
4932
+ /* @__PURE__ */ jsxRuntime.jsx(
4933
+ core.NumberInput,
4934
+ {
4935
+ size: "xs",
4936
+ label: "Z",
4937
+ value: value.z,
4938
+ onChange: (v) => set("z", Number(v)),
4939
+ decimalScale: 4,
4940
+ step: 0.1,
4941
+ style: { flex: 1 },
4942
+ styles: numberStyles
4943
+ }
4944
+ ),
4945
+ showHeading && /* @__PURE__ */ jsxRuntime.jsx(
4946
+ core.NumberInput,
4947
+ {
4948
+ size: "xs",
4949
+ label: "W",
4950
+ value: value.w,
4951
+ onChange: (v) => set("w", Number(v)),
4952
+ decimalScale: 2,
4953
+ step: 1,
4954
+ min: 0,
4955
+ max: 360,
4956
+ style: { flex: 1 },
4957
+ styles: numberStyles
4958
+ }
4959
+ )
4960
+ ] })
4961
+ ]
4962
+ }
4963
+ );
4964
+ }
4965
+ function PickerButton({
4966
+ children,
4967
+ onClick,
4968
+ tooltip,
4969
+ color,
4970
+ active
4971
+ }) {
4972
+ const theme2 = core.useMantineTheme();
4973
+ return /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { label: tooltip, position: "top", withArrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4974
+ framerMotion.motion.button,
4975
+ {
4976
+ onClick,
4977
+ whileHover: { background: core.alpha(color, 0.18) },
4978
+ whileTap: { scale: 0.95 },
4979
+ style: {
4980
+ background: active ? core.alpha(color, 0.22) : core.alpha(color, 0.08),
4981
+ border: `0.1vh solid ${core.alpha(color, active ? 0.5 : 0.3)}`,
4982
+ borderRadius: theme2.radius.xs,
4983
+ padding: "0.4vh 0.6vh",
4984
+ cursor: "pointer",
4985
+ display: "flex",
4986
+ alignItems: "center",
4987
+ justifyContent: "center"
4988
+ },
4989
+ children
4990
+ }
4991
+ ) });
4992
+ }
4727
4993
  var KeyBindContext = React5.createContext(null);
4728
4994
  function useKeyBindContext() {
4729
4995
  const ctx = React5.useContext(KeyBindContext);
@@ -5186,6 +5452,11 @@ function mergeMantineThemeSafe(base, custom, override) {
5186
5452
  const colors = { ...base.colors };
5187
5453
  if (custom && isValidColorScale(custom)) {
5188
5454
  colors["custom"] = custom;
5455
+ } else if (!colors["custom"]) {
5456
+ const fallback = base.colors && base.colors.dirk;
5457
+ if (fallback && isValidColorScale(fallback)) {
5458
+ colors["custom"] = fallback;
5459
+ }
5189
5460
  }
5190
5461
  return {
5191
5462
  ...base,
@@ -5259,6 +5530,7 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
5259
5530
  customTheme,
5260
5531
  game
5261
5532
  } = useSettings();
5533
+ localeStore((s) => s.locales);
5262
5534
  React5.useLayoutEffect(() => {
5263
5535
  useSettings.setState({
5264
5536
  overideResourceName
@@ -5279,6 +5551,10 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
5279
5551
  console.error("Failed to fetch initial settings within dirk-cfx-react:", err);
5280
5552
  });
5281
5553
  }, []);
5554
+ useNuiEvent("UPDATE_DIRK_LIB_SETTINGS", (data) => {
5555
+ if (!data || typeof data !== "object") return;
5556
+ useSettings.setState(data);
5557
+ });
5282
5558
  const mergedTheme = React5.useMemo(
5283
5559
  () => mergeMantineThemeSafe(
5284
5560
  { ...theme_default, primaryColor, primaryShade },
@@ -5305,6 +5581,7 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
5305
5581
  exports.AdminPageTitle = AdminPageTitle;
5306
5582
  exports.AsyncSaveButton = AsyncSaveButton;
5307
5583
  exports.BlipColorSelect = BlipColorSelect;
5584
+ exports.BlipDisplaySelect = BlipDisplaySelect;
5308
5585
  exports.BlipIconSelect = BlipIconSelect;
5309
5586
  exports.BorderedIcon = BorderedIcon;
5310
5587
  exports.ConfigPanel = ConfigPanel;
@@ -5330,6 +5607,7 @@ exports.MotionText = MotionText;
5330
5607
  exports.NavBar = NavBar;
5331
5608
  exports.NavigationContext = NavigationContext;
5332
5609
  exports.NavigationProvider = NavigationProvider;
5610
+ exports.PositionPicker = PositionPicker;
5333
5611
  exports.PromptModal = PromptModal;
5334
5612
  exports.SegmentedControl = SegmentedControl;
5335
5613
  exports.SegmentedProgress = SegmentedProgress;