dirk-cfx-react 1.1.70 → 1.1.72

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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { AdminPageTitle, AdminPageTitleProps, AsyncSaveButton, BlipColorSelect, BlipColorSelectProps, BlipDisplaySelect, BlipDisplaySelectProps, BlipIconSelect, BlipIconSelectProps, BorderedIcon, BorderedIconProps, ButtonProps, ConfigPanel, ConfigPanelProps, ConfirmModal, ConfirmModalProps, ControlMultiSelect, ControlMultiSelectProps, ControlSelect, ControlSelectProps, Counter, FiveMControls, FiveMKeyBindInput, FloatingParticles, FloatingParticlesProps, GroupName, GroupNameProps, GroupRank, GroupRankProps, GroupSelect, GroupSelectProps, GroupType, GroupValue, InfoBox, InfoBoxProps, InputContainer, InputContainerProps, LevelBanner, LevelPanel, Modal, ModalContext, ModalProps, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavItem, NavigationContext, NavigationProvider, NavigationStore, ParticleState, PositionPicker, PositionPickerProps, ProgressProps, Prompt, PromptButton, PromptModal, SegmentProps, SegmentedControl, SegmentedControlProps, SegmentedProgress, SelectItem, SelectItemProps, StoreModalProps, TestBed, TestBedItem, TestBedProps, Title, TitleProps, Vector4Value, useModal, useModalActions, useNavigation, useNavigationStore } from './components/index.cjs';
1
+ export { AdminPageTitle, AdminPageTitleProps, AsyncSaveButton, BlipColorSelect, BlipColorSelectProps, BlipDisplaySelect, BlipDisplaySelectProps, BlipIconSelect, BlipIconSelectProps, BorderedIcon, BorderedIconProps, ButtonProps, ConfigPanel, ConfigPanelProps, ConfirmModal, ConfirmModalProps, ControlMultiSelect, ControlMultiSelectProps, ControlSelect, ControlSelectProps, Counter, FiveMControls, FiveMKeyBindInput, FloatingParticles, FloatingParticlesProps, GroupName, GroupNameProps, GroupRank, GroupRankProps, GroupSelect, GroupSelectProps, GroupType, GroupValue, InfoBox, InfoBoxProps, InputContainer, InputContainerProps, LevelBanner, LevelPanel, MissingItemsBanner, Modal, ModalContext, ModalProps, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavItem, NavigationContext, NavigationProvider, NavigationStore, ParticleState, PositionPicker, PositionPickerProps, ProgressProps, Prompt, PromptButton, PromptModal, SegmentProps, SegmentedControl, SegmentedControlProps, SegmentedProgress, SelectItem, SelectItemProps, StoreModalProps, TestBed, TestBedItem, TestBedProps, Title, TitleProps, Vector4DeleteButton, Vector4Display, Vector4Value, WorldPositionGotoButton, WorldPositionSetButton, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore } from './components/index.cjs';
2
2
  export { FrameworkGrade, FrameworkGroup, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GtaControl, GtaControlGroup, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, InitialFetch, InternalEvent, InventoryItem, InventoryItems, SettingsState, SkillSettings, UploadImageProps, colorWithAlpha, copyToClipboard, createSkill, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getGtaControl, getImageShape, getItemImageUrl, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAutoFetcher, useFrameworkGroups, useItems, useItemsList, useProfanityStore, useSettings } from './utils/index.cjs';
3
3
  export { FormProvider, FormState, NuiHandlerSignature, NuiMessageData, ScriptConfigHistoryChange, ScriptConfigHistoryEntry, ScriptConfigHistoryRequest, ScriptConfigHistoryResponse, ScriptConfigInstance, TornEdgeSVGFilter, ValidationRules, ValidatorFn, createFormStore, createScriptConfig, getScriptConfigInstance, useAudio, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useNuiEvent, useTornEdges } from './hooks/index.cjs';
4
4
  export { DirkProvider, DirkProviderProps } from './providers/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { AdminPageTitle, AdminPageTitleProps, AsyncSaveButton, BlipColorSelect, BlipColorSelectProps, BlipDisplaySelect, BlipDisplaySelectProps, BlipIconSelect, BlipIconSelectProps, BorderedIcon, BorderedIconProps, ButtonProps, ConfigPanel, ConfigPanelProps, ConfirmModal, ConfirmModalProps, ControlMultiSelect, ControlMultiSelectProps, ControlSelect, ControlSelectProps, Counter, FiveMControls, FiveMKeyBindInput, FloatingParticles, FloatingParticlesProps, GroupName, GroupNameProps, GroupRank, GroupRankProps, GroupSelect, GroupSelectProps, GroupType, GroupValue, InfoBox, InfoBoxProps, InputContainer, InputContainerProps, LevelBanner, LevelPanel, Modal, ModalContext, ModalProps, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavItem, NavigationContext, NavigationProvider, NavigationStore, ParticleState, PositionPicker, PositionPickerProps, ProgressProps, Prompt, PromptButton, PromptModal, SegmentProps, SegmentedControl, SegmentedControlProps, SegmentedProgress, SelectItem, SelectItemProps, StoreModalProps, TestBed, TestBedItem, TestBedProps, Title, TitleProps, Vector4Value, useModal, useModalActions, useNavigation, useNavigationStore } from './components/index.js';
1
+ export { AdminPageTitle, AdminPageTitleProps, AsyncSaveButton, BlipColorSelect, BlipColorSelectProps, BlipDisplaySelect, BlipDisplaySelectProps, BlipIconSelect, BlipIconSelectProps, BorderedIcon, BorderedIconProps, ButtonProps, ConfigPanel, ConfigPanelProps, ConfirmModal, ConfirmModalProps, ControlMultiSelect, ControlMultiSelectProps, ControlSelect, ControlSelectProps, Counter, FiveMControls, FiveMKeyBindInput, FloatingParticles, FloatingParticlesProps, GroupName, GroupNameProps, GroupRank, GroupRankProps, GroupSelect, GroupSelectProps, GroupType, GroupValue, InfoBox, InfoBoxProps, InputContainer, InputContainerProps, LevelBanner, LevelPanel, MissingItemsBanner, Modal, ModalContext, ModalProps, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavItem, NavigationContext, NavigationProvider, NavigationStore, ParticleState, PositionPicker, PositionPickerProps, ProgressProps, Prompt, PromptButton, PromptModal, SegmentProps, SegmentedControl, SegmentedControlProps, SegmentedProgress, SelectItem, SelectItemProps, StoreModalProps, TestBed, TestBedItem, TestBedProps, Title, TitleProps, Vector4DeleteButton, Vector4Display, Vector4Value, WorldPositionGotoButton, WorldPositionSetButton, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore } from './components/index.js';
2
2
  export { FrameworkGrade, FrameworkGroup, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GtaControl, GtaControlGroup, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, InitialFetch, InternalEvent, InventoryItem, InventoryItems, SettingsState, SkillSettings, UploadImageProps, colorWithAlpha, copyToClipboard, createSkill, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getGtaControl, getImageShape, getItemImageUrl, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAutoFetcher, useFrameworkGroups, useItems, useItemsList, useProfanityStore, useSettings } from './utils/index.js';
3
3
  export { FormProvider, FormState, NuiHandlerSignature, NuiMessageData, ScriptConfigHistoryChange, ScriptConfigHistoryEntry, ScriptConfigHistoryRequest, ScriptConfigHistoryResponse, ScriptConfigInstance, TornEdgeSVGFilter, ValidationRules, ValidatorFn, createFormStore, createScriptConfig, getScriptConfigInstance, useAudio, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useNuiEvent, useTornEdges } from './hooks/index.js';
4
4
  export { DirkProvider, DirkProviderProps } from './providers/index.js';
package/dist/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import { Flex, Text, Image as Image$1, createTheme, Box, Stack, Title as Title$1, Code, TextInput, Select, useMantineTheme, Tooltip, alpha, Progress, RingProgress, Portal, Button, NumberInput, MultiSelect, Loader, ActionIcon, MantineProvider, BackgroundImage, Group, JsonInput } from '@mantine/core';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import React6, { createContext, useContext, useEffect, useRef, useState, useMemo, useLayoutEffect } from 'react';
3
+ import React6, { createContext, useContext, useEffect, useRef, useState, useCallback, useMemo, useLayoutEffect } from 'react';
4
4
  import { create, useStore, createStore } from 'zustand';
5
5
  import axios from 'axios';
6
6
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
7
7
  import { motion, AnimatePresence, useMotionValue } from 'framer-motion';
8
- import { Info, X, AlertTriangle, Trash2, MapPin, Crosshair, EyeOff, Eye, RotateCcw, Check, FlaskConical, ChevronUp, ChevronDown, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, Search, Filter, User } from 'lucide-react';
8
+ import { Info, X, AlertTriangle, Trash2, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, ArrowLeft, Undo2, Redo2, Save, History, XCircle, Code2, Search, Filter, User } from 'lucide-react';
9
9
  import clickSoundUrl from './click_sound-PNCRRTM4.mp3';
10
10
  import hoverSoundUrl from './hover_sound-NBUA222C.mp3';
11
+ import { notifications } from '@mantine/notifications';
11
12
  import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
12
13
  import '@mantine/core/styles.css';
13
14
  import '@mantine/notifications/styles.css';
@@ -1241,11 +1242,11 @@ var colorNames = {
1241
1242
  Yellow: { r: 255, g: 255, b: 0 },
1242
1243
  YellowGreen: { r: 154, g: 205, b: 50 }
1243
1244
  };
1244
- function colorWithAlpha(color, alpha9) {
1245
+ function colorWithAlpha(color, alpha10) {
1245
1246
  const lowerCasedColor = color.toLowerCase();
1246
1247
  if (colorNames[lowerCasedColor]) {
1247
1248
  const rgb = colorNames[lowerCasedColor];
1248
- return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha9})`;
1249
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha10})`;
1249
1250
  }
1250
1251
  if (/^#([A-Fa-f0-9]{6})$/.test(color)) {
1251
1252
  const hex = color.slice(1);
@@ -1253,12 +1254,12 @@ function colorWithAlpha(color, alpha9) {
1253
1254
  const r = bigint >> 16 & 255;
1254
1255
  const g = bigint >> 8 & 255;
1255
1256
  const b = bigint & 255;
1256
- return `rgba(${r}, ${g}, ${b}, ${alpha9})`;
1257
+ return `rgba(${r}, ${g}, ${b}, ${alpha10})`;
1257
1258
  }
1258
1259
  if (/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.test(color)) {
1259
1260
  const result = color.match(/^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/);
1260
1261
  if (result) {
1261
- return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha9})`;
1262
+ return `rgba(${result[1]}, ${result[2]}, ${result[3]}, ${alpha10})`;
1262
1263
  }
1263
1264
  }
1264
1265
  return color;
@@ -3806,6 +3807,246 @@ function ConfirmModal({
3806
3807
  }
3807
3808
  ) });
3808
3809
  }
3810
+ var TABS = [
3811
+ { id: "ox", label: "ox_inventory" },
3812
+ { id: "qb", label: "qb-inventory" },
3813
+ { id: "esx", label: "ESX legacy SQL" }
3814
+ ];
3815
+ var useMissingItemsAudit = create((set, get) => ({
3816
+ data: null,
3817
+ loaded: false,
3818
+ inFlight: false,
3819
+ refresh: async () => {
3820
+ if (get().inFlight) return;
3821
+ set({ inFlight: true });
3822
+ try {
3823
+ const res = await fetchNui("GET_MISSING_ITEMS", void 0, {
3824
+ success: true,
3825
+ data: { missing: [], snippets: { ox: "", qb: "", esx: "" } }
3826
+ });
3827
+ if (res?.success && res.data) {
3828
+ set({ data: res.data, loaded: true });
3829
+ } else {
3830
+ set({ loaded: true });
3831
+ }
3832
+ } catch {
3833
+ set({ loaded: true });
3834
+ } finally {
3835
+ set({ inFlight: false });
3836
+ }
3837
+ }
3838
+ }));
3839
+ function MissingItemsBanner() {
3840
+ const theme2 = useMantineTheme();
3841
+ const audit = useMissingItemsAudit((s) => s.data);
3842
+ const loaded = useMissingItemsAudit((s) => s.loaded);
3843
+ const inFlight = useMissingItemsAudit((s) => s.inFlight);
3844
+ const refresh = useMissingItemsAudit((s) => s.refresh);
3845
+ const [expanded, setExpanded] = useState(false);
3846
+ const [activeTab, setActiveTab] = useState("ox");
3847
+ const [hoveredTab, setHoveredTab] = useState(null);
3848
+ const [copied, setCopied] = useState(null);
3849
+ useEffect(() => {
3850
+ if (!loaded) refresh();
3851
+ }, [loaded, refresh]);
3852
+ const handleCopy = useCallback((tab) => {
3853
+ if (!audit) return;
3854
+ const text = audit.snippets[tab] ?? "";
3855
+ navigator.clipboard.writeText(text).then(() => {
3856
+ setCopied(tab);
3857
+ setTimeout(() => setCopied((c) => c === tab ? null : c), 1500);
3858
+ }).catch(() => {
3859
+ });
3860
+ }, [audit]);
3861
+ const handleRefresh = useCallback((e) => {
3862
+ e.stopPropagation();
3863
+ refresh();
3864
+ }, [refresh]);
3865
+ if (!audit || audit.missing.length === 0) return null;
3866
+ const warnColor = "#f59e0b";
3867
+ const names = audit.missing.map((m) => m.name);
3868
+ return /* @__PURE__ */ jsxs(
3869
+ "div",
3870
+ {
3871
+ style: {
3872
+ background: alpha(warnColor, 0.06),
3873
+ border: `0.1vh solid ${alpha(warnColor, 0.35)}`,
3874
+ borderLeft: `0.3vh solid ${warnColor}`,
3875
+ borderRadius: theme2.radius.xs,
3876
+ margin: "0.6vh 1vh",
3877
+ overflow: "hidden"
3878
+ },
3879
+ children: [
3880
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "0.8vh", p: "0.8vh 1vh", style: { cursor: "pointer" }, onClick: () => setExpanded((e) => !e), children: [
3881
+ /* @__PURE__ */ jsx(AlertTriangle, { size: "1.8vh", color: warnColor, strokeWidth: 2.5 }),
3882
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minWidth: 0 }, children: [
3883
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", tt: "uppercase", lts: "0.07em", c: warnColor, children: audit.missing.length === 1 ? "1 item missing from your inventory" : `${audit.missing.length} items missing from your inventory` }),
3884
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.5)", lineClamp: 1, style: { fontFamily: "monospace" }, children: names.join(", ") })
3885
+ ] }),
3886
+ /* @__PURE__ */ jsx(
3887
+ "button",
3888
+ {
3889
+ onClick: handleRefresh,
3890
+ disabled: inFlight,
3891
+ style: {
3892
+ background: "transparent",
3893
+ border: "none",
3894
+ padding: "0.3vh",
3895
+ cursor: inFlight ? "wait" : "pointer",
3896
+ display: "flex",
3897
+ alignItems: "center",
3898
+ justifyContent: "center",
3899
+ opacity: inFlight ? 0.4 : 0.7
3900
+ },
3901
+ title: "Re-check",
3902
+ children: /* @__PURE__ */ jsx(
3903
+ motion.span,
3904
+ {
3905
+ animate: { rotate: inFlight ? 360 : 0 },
3906
+ transition: inFlight ? { duration: 1, repeat: Infinity, ease: "linear" } : { duration: 0 },
3907
+ style: { display: "flex", alignItems: "center", justifyContent: "center" },
3908
+ children: /* @__PURE__ */ jsx(RefreshCw, { size: "1.5vh", color: alpha(warnColor, 0.7) })
3909
+ }
3910
+ )
3911
+ }
3912
+ ),
3913
+ /* @__PURE__ */ jsx(
3914
+ motion.div,
3915
+ {
3916
+ animate: { rotate: expanded ? 180 : 0 },
3917
+ transition: { duration: 0.18 },
3918
+ style: { display: "flex", alignItems: "center", justifyContent: "center" },
3919
+ children: /* @__PURE__ */ jsx(ChevronDown, { size: "1.8vh", color: alpha(warnColor, 0.7) })
3920
+ }
3921
+ )
3922
+ ] }),
3923
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: expanded && /* @__PURE__ */ jsxs(
3924
+ motion.div,
3925
+ {
3926
+ initial: { height: 0, opacity: 0 },
3927
+ animate: { height: "auto", opacity: 1 },
3928
+ exit: { height: 0, opacity: 0 },
3929
+ transition: { duration: 0.18, ease: "easeOut" },
3930
+ style: { overflow: "hidden", borderTop: `0.1vh solid ${alpha(warnColor, 0.18)}` },
3931
+ children: [
3932
+ /* @__PURE__ */ jsx(Flex, { gap: "0", style: { borderBottom: `0.1vh solid ${alpha(warnColor, 0.18)}` }, children: TABS.map((tab) => {
3933
+ const active = tab.id === activeTab;
3934
+ const hovered = hoveredTab === tab.id;
3935
+ let bg = "transparent";
3936
+ if (active) bg = alpha(warnColor, 0.12);
3937
+ else if (hovered) bg = alpha(warnColor, 0.08);
3938
+ return /* @__PURE__ */ jsx(
3939
+ "button",
3940
+ {
3941
+ onClick: (e) => {
3942
+ e.stopPropagation();
3943
+ setActiveTab(tab.id);
3944
+ },
3945
+ onMouseEnter: () => setHoveredTab(tab.id),
3946
+ onMouseLeave: () => setHoveredTab((h) => h === tab.id ? null : h),
3947
+ style: {
3948
+ flex: 1,
3949
+ background: bg,
3950
+ border: "none",
3951
+ borderBottom: active ? `0.2vh solid ${warnColor}` : "0.2vh solid transparent",
3952
+ padding: "0.3vh 1vh",
3953
+ cursor: active ? "default" : "pointer",
3954
+ color: active ? warnColor : "rgba(255,255,255,0.5)",
3955
+ fontFamily: "Akrobat Bold",
3956
+ fontSize: "var(--mantine-font-size-xxs)",
3957
+ letterSpacing: "0.07em",
3958
+ textTransform: "uppercase",
3959
+ transition: "background 0.12s"
3960
+ },
3961
+ children: tab.label
3962
+ },
3963
+ tab.id
3964
+ );
3965
+ }) }),
3966
+ /* @__PURE__ */ jsx(
3967
+ CodeView,
3968
+ {
3969
+ code: audit.snippets[activeTab] ?? "",
3970
+ copied: copied === activeTab,
3971
+ onCopy: (e) => {
3972
+ e.stopPropagation();
3973
+ handleCopy(activeTab);
3974
+ },
3975
+ warnColor
3976
+ }
3977
+ )
3978
+ ]
3979
+ },
3980
+ "expanded"
3981
+ ) })
3982
+ ]
3983
+ }
3984
+ );
3985
+ }
3986
+ function CodeView({
3987
+ code,
3988
+ copied,
3989
+ onCopy,
3990
+ warnColor
3991
+ }) {
3992
+ const theme2 = useMantineTheme();
3993
+ const [hovered, setHovered] = useState(false);
3994
+ const lines = code === "" ? [""] : code.split("\n");
3995
+ const lineNumWidth = String(lines.length).length;
3996
+ const copyBg = copied ? alpha("#22c55e", 0.15) : hovered ? alpha(warnColor, 0.18) : alpha(warnColor, 0.1);
3997
+ return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
3998
+ /* @__PURE__ */ jsxs(
3999
+ "button",
4000
+ {
4001
+ onClick: onCopy,
4002
+ onMouseEnter: () => setHovered(true),
4003
+ onMouseLeave: () => setHovered(false),
4004
+ style: {
4005
+ position: "absolute",
4006
+ top: "0.6vh",
4007
+ right: "0.8vh",
4008
+ zIndex: 2,
4009
+ background: copyBg,
4010
+ border: `0.1vh solid ${alpha(copied ? "#22c55e" : warnColor, 0.35)}`,
4011
+ borderRadius: theme2.radius.xs,
4012
+ padding: "0.4vh 0.7vh",
4013
+ cursor: "pointer",
4014
+ display: "flex",
4015
+ alignItems: "center",
4016
+ gap: "0.4vh",
4017
+ transition: "background 0.12s"
4018
+ },
4019
+ children: [
4020
+ copied ? /* @__PURE__ */ jsx(Check, { size: "1.4vh", color: "#22c55e" }) : /* @__PURE__ */ jsx(Copy, { size: "1.4vh", color: warnColor }),
4021
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: copied ? "#22c55e" : warnColor, children: copied ? "Copied" : "Copy" })
4022
+ ]
4023
+ }
4024
+ ),
4025
+ /* @__PURE__ */ jsx("div", { style: {
4026
+ background: alpha(theme2.colors.dark[9], 0.6),
4027
+ maxHeight: "40vh",
4028
+ overflowY: "auto",
4029
+ overflowX: "auto",
4030
+ padding: "0.6vh 0"
4031
+ }, children: /* @__PURE__ */ jsx("table", { style: { borderCollapse: "collapse", width: "100%", fontFamily: "monospace", fontSize: "1.2vh", lineHeight: 1.5 }, children: /* @__PURE__ */ jsx("tbody", { children: lines.map((line, i) => /* @__PURE__ */ jsxs("tr", { children: [
4032
+ /* @__PURE__ */ jsx("td", { style: {
4033
+ width: `${lineNumWidth + 2}ch`,
4034
+ textAlign: "right",
4035
+ padding: "0 0.8vh 0 1vh",
4036
+ color: "rgba(255,255,255,0.25)",
4037
+ userSelect: "none",
4038
+ whiteSpace: "nowrap",
4039
+ verticalAlign: "top"
4040
+ }, children: i + 1 }),
4041
+ /* @__PURE__ */ jsx("td", { style: {
4042
+ padding: "0 1vh",
4043
+ color: "rgba(255,255,255,0.85)",
4044
+ whiteSpace: "pre",
4045
+ verticalAlign: "top"
4046
+ }, children: line || "\u200B" })
4047
+ ] }, i)) }) }) })
4048
+ ] });
4049
+ }
3809
4050
  function getNested(obj, path) {
3810
4051
  return path.split(".").reduce((acc, key) => acc ? acc[key] : void 0, obj);
3811
4052
  }
@@ -4532,7 +4773,8 @@ function ConfigPanelInner({
4532
4773
  resetConfirmText,
4533
4774
  defaultConfig,
4534
4775
  width,
4535
- height
4776
+ height,
4777
+ suppressMissingItemsBanner
4536
4778
  }) {
4537
4779
  const { updateConfig, resetConfig, getHistory } = getScriptConfigInstance();
4538
4780
  const form = useForm();
@@ -4755,18 +4997,21 @@ function ConfigPanelInner({
4755
4997
  ] })
4756
4998
  ] })
4757
4999
  ] }),
4758
- /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
4759
- motion.div,
4760
- {
4761
- initial: firstMountRef.current ? (firstMountRef.current = false, false) : { opacity: 0, y: 4 },
4762
- animate: { opacity: 1, y: 0 },
4763
- exit: { opacity: 0, y: -4 },
4764
- transition: { duration: 0.15 },
4765
- style: { flex: 1, display: "flex", flexDirection: "column", overflowY: "auto" },
4766
- children: children(activeTab)
4767
- },
4768
- activeTab
4769
- ) })
5000
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: [
5001
+ !suppressMissingItemsBanner && /* @__PURE__ */ jsx(MissingItemsBanner, {}),
5002
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
5003
+ motion.div,
5004
+ {
5005
+ initial: firstMountRef.current ? (firstMountRef.current = false, false) : { opacity: 0, y: 4 },
5006
+ animate: { opacity: 1, y: 0 },
5007
+ exit: { opacity: 0, y: -4 },
5008
+ transition: { duration: 0.15 },
5009
+ style: { flex: 1, display: "flex", flexDirection: "column", overflowY: "auto" },
5010
+ children: children(activeTab)
5011
+ },
5012
+ activeTab
5013
+ ) })
5014
+ ] })
4770
5015
  ]
4771
5016
  }
4772
5017
  )
@@ -4808,12 +5053,26 @@ function ConfigPanel(props) {
4808
5053
  if (result?.success) {
4809
5054
  form.reinitialize(cloneConfig(form.values));
4810
5055
  configPanelQueryClient.invalidateQueries({ queryKey: ["scriptConfigHistory"] });
5056
+ useMissingItemsAudit.getState().refresh();
5057
+ notifications.show({
5058
+ color: "green",
5059
+ title: locale("ConfigSaveSuccessTitle"),
5060
+ message: locale("ConfigSaveSuccessBody"),
5061
+ autoClose: 3e3
5062
+ });
4811
5063
  return;
4812
5064
  }
4813
5065
  form.reinitialize(cloneConfig(store.getState()));
4814
- if (result?._error) {
4815
- console.warn(`[ConfigPanel] config save failed: ${result._error}`);
4816
- }
5066
+ const err = result?._error || "Unknown";
5067
+ console.warn(`[ConfigPanel] config save failed: ${err}`);
5068
+ const titleKey = err === "NoPermission" ? "ConfigSaveNoPermissionTitle" : err === "VersionConflict" ? "ConfigSaveVersionConflictTitle" : err === "NotReady" ? "ConfigSaveNotReadyTitle" : "ConfigSaveFailedTitle";
5069
+ const bodyKey = err === "NoPermission" ? "ConfigSaveNoPermissionBody" : err === "VersionConflict" ? "ConfigSaveVersionConflictBody" : err === "NotReady" ? "ConfigSaveNotReadyBody" : "ConfigSaveFailedBody";
5070
+ notifications.show({
5071
+ color: "red",
5072
+ title: locale(titleKey),
5073
+ message: locale(bodyKey, err),
5074
+ autoClose: 6e3
5075
+ });
4817
5076
  } finally {
4818
5077
  setIsSaving(false);
4819
5078
  }
@@ -4832,6 +5091,7 @@ function ConfigPanel(props) {
4832
5091
  }
4833
5092
  ) });
4834
5093
  }
5094
+ var MISSING_COLOR = "#f59e0b";
4835
5095
  function LazyImage({ src, style }) {
4836
5096
  const [visible, setVisible] = useState(false);
4837
5097
  const ref = useRef(null);
@@ -4849,14 +5109,19 @@ function LazyImage({ src, style }) {
4849
5109
  }
4850
5110
  function SelectItem(props) {
4851
5111
  const invItems = useItems();
5112
+ const isMissing = !!props.value && !invItems[props.value];
4852
5113
  const formattedItems = useMemo(() => {
4853
5114
  const seen = /* @__PURE__ */ new Set();
4854
- return useItemsList(props.excludeItemNames ?? []).filter((item) => {
5115
+ const list = useItemsList(props.excludeItemNames ?? []).filter((item) => {
4855
5116
  if (seen.has(item.name)) return false;
4856
5117
  seen.add(item.name);
4857
5118
  return true;
4858
5119
  }).map((item) => ({ value: item.name, label: item.label, image: item.image }));
4859
- }, [invItems, props.excludeItemNames]);
5120
+ if (isMissing) {
5121
+ list.unshift({ value: props.value, label: props.value, image: "" });
5122
+ }
5123
+ return list;
5124
+ }, [invItems, props.excludeItemNames, props.value, isMissing]);
4860
5125
  return /* @__PURE__ */ jsx(
4861
5126
  Select,
4862
5127
  {
@@ -4871,10 +5136,11 @@ function SelectItem(props) {
4871
5136
  data: formattedItems,
4872
5137
  allowDeselect: false,
4873
5138
  searchable: true,
5139
+ styles: isMissing ? { input: { color: MISSING_COLOR } } : void 0,
4874
5140
  comboboxProps: { withinPortal: true, zIndex: 2e3 },
4875
5141
  leftSectionWidth: "4vh",
4876
5142
  leftSectionPointerEvents: "none",
4877
- leftSection: props.value ? /* @__PURE__ */ jsx(
5143
+ leftSection: isMissing ? /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", w: "4vh", h: "4vh", children: /* @__PURE__ */ jsx(AlertTriangle, { size: "2vh", color: MISSING_COLOR, strokeWidth: 2.5 }) }) : props.value ? /* @__PURE__ */ jsx(
4878
5144
  Image$1,
4879
5145
  {
4880
5146
  fallbackSrc: "/placeholder.png",
@@ -4885,19 +5151,37 @@ function SelectItem(props) {
4885
5151
  }
4886
5152
  ) : null,
4887
5153
  nothingFoundMessage: locale("NoItemsFound"),
4888
- renderOption: (item) => /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", w: "100%", children: [
4889
- /* @__PURE__ */ jsx(
4890
- LazyImage,
4891
- {
4892
- src: invItems[item.option.value]?.image || "",
4893
- style: { aspectRatio: "1 / 1" }
4894
- }
4895
- ),
4896
- /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
4897
- /* @__PURE__ */ jsx(Text, { size: "sm", children: item.option.label }),
4898
- /* @__PURE__ */ jsx(Text, { size: "xxs", c: "dimmed", children: item.option.value })
4899
- ] })
4900
- ] })
5154
+ renderOption: (item) => {
5155
+ const optionMissing = !invItems[item.option.value] && item.option.value === props.value;
5156
+ if (optionMissing) {
5157
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", w: "100%", children: [
5158
+ /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", w: "4vh", h: "4vh", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx(AlertTriangle, { size: "2vh", color: MISSING_COLOR, strokeWidth: 2.5 }) }),
5159
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { flex: 1, minWidth: 0 }, children: [
5160
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: MISSING_COLOR, style: { fontFamily: "monospace" }, children: item.option.value }),
5161
+ /* @__PURE__ */ jsx(Text, { size: "xxs", c: "dimmed", children: locale("ItemNotInInventory") })
5162
+ ] }),
5163
+ /* @__PURE__ */ jsx("div", { style: {
5164
+ background: "rgba(245,158,11,0.12)",
5165
+ border: `0.1vh solid ${MISSING_COLOR}59`,
5166
+ borderRadius: "0.3vh",
5167
+ padding: "0.1vh 0.6vh"
5168
+ }, children: /* @__PURE__ */ jsx(Text, { size: "xxs", c: MISSING_COLOR, ff: "Akrobat Bold", tt: "uppercase", lts: "0.06em", children: locale("Missing") }) })
5169
+ ] });
5170
+ }
5171
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", w: "100%", children: [
5172
+ /* @__PURE__ */ jsx(
5173
+ LazyImage,
5174
+ {
5175
+ src: invItems[item.option.value]?.image || "",
5176
+ style: { aspectRatio: "1 / 1" }
5177
+ }
5178
+ ),
5179
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
5180
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: item.option.label }),
5181
+ /* @__PURE__ */ jsx(Text, { size: "xxs", c: "dimmed", children: item.option.value })
5182
+ ] })
5183
+ ] });
5184
+ }
4901
5185
  }
4902
5186
  );
4903
5187
  }
@@ -5114,6 +5398,148 @@ function PickerButton({
5114
5398
  }
5115
5399
  ) });
5116
5400
  }
5401
+ function fmtV4(n) {
5402
+ return Number.isFinite(n) ? n.toFixed(2) : "0.00";
5403
+ }
5404
+ function Vector4Display({ value }) {
5405
+ const theme2 = useMantineTheme();
5406
+ return /* @__PURE__ */ jsx(
5407
+ Flex,
5408
+ {
5409
+ align: "center",
5410
+ gap: "xs",
5411
+ p: "xs",
5412
+ style: {
5413
+ background: alpha(theme2.colors.dark[5], 0.35),
5414
+ border: "0.1vh solid rgba(255,255,255,0.05)",
5415
+ borderRadius: theme2.radius.xs
5416
+ },
5417
+ children: /* @__PURE__ */ jsxs(
5418
+ Text,
5419
+ {
5420
+ ff: "monospace",
5421
+ size: "xxs",
5422
+ c: "rgba(255,255,255,0.85)",
5423
+ style: { flex: 1, letterSpacing: "0.02em", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" },
5424
+ children: [
5425
+ "vector4(",
5426
+ fmtV4(value.x),
5427
+ ", ",
5428
+ fmtV4(value.y),
5429
+ ", ",
5430
+ fmtV4(value.z),
5431
+ ", ",
5432
+ fmtV4(value.w),
5433
+ ")"
5434
+ ]
5435
+ }
5436
+ )
5437
+ }
5438
+ );
5439
+ }
5440
+ function Vector4ActionButton({
5441
+ icon,
5442
+ label: label2,
5443
+ tooltip,
5444
+ onClick,
5445
+ color,
5446
+ compact
5447
+ }) {
5448
+ const theme2 = useMantineTheme();
5449
+ return /* @__PURE__ */ jsx(Tooltip, { label: tooltip, position: "top", withArrow: true, withinPortal: true, zIndex: 2e3, children: /* @__PURE__ */ jsxs(
5450
+ motion.button,
5451
+ {
5452
+ onClick,
5453
+ whileHover: { background: alpha(color, 0.18) },
5454
+ whileTap: { scale: 0.95 },
5455
+ style: {
5456
+ background: alpha(color, 0.1),
5457
+ border: `0.1vh solid ${alpha(color, 0.35)}`,
5458
+ borderRadius: theme2.radius.xs,
5459
+ padding: compact ? "0.25vh 0.6vh" : "0.5vh 0.8vh",
5460
+ cursor: "pointer",
5461
+ display: "flex",
5462
+ alignItems: "center",
5463
+ gap: compact ? "0.3vh" : "0.4vh"
5464
+ },
5465
+ children: [
5466
+ icon,
5467
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.06em", c: color, children: label2 })
5468
+ ]
5469
+ }
5470
+ ) });
5471
+ }
5472
+ function WorldPositionSetButton({
5473
+ value,
5474
+ onChange,
5475
+ compact
5476
+ }) {
5477
+ const theme2 = useMantineTheme();
5478
+ const color = theme2.colors[theme2.primaryColor][5];
5479
+ const grab = async () => {
5480
+ try {
5481
+ const resp = await fetchNui("GET_POSITION", {}, value);
5482
+ if (!resp || typeof resp !== "object") return;
5483
+ onChange({
5484
+ x: Number(resp.x ?? 0),
5485
+ y: Number(resp.y ?? 0),
5486
+ z: Number(resp.z ?? 0),
5487
+ w: Number(resp.w ?? 0)
5488
+ });
5489
+ } catch {
5490
+ }
5491
+ };
5492
+ return /* @__PURE__ */ jsx(
5493
+ Vector4ActionButton,
5494
+ {
5495
+ icon: /* @__PURE__ */ jsx(Crosshair, { size: compact ? "1.1vh" : "1.3vh", color }),
5496
+ label: locale("Set"),
5497
+ tooltip: locale("SetWorldTooltip"),
5498
+ onClick: grab,
5499
+ color,
5500
+ compact
5501
+ }
5502
+ );
5503
+ }
5504
+ function WorldPositionGotoButton({
5505
+ value,
5506
+ compact
5507
+ }) {
5508
+ const theme2 = useMantineTheme();
5509
+ const color = theme2.colors[theme2.primaryColor][5];
5510
+ const goto = () => {
5511
+ fetchNui("GOTO_POSITION", value).catch(() => {
5512
+ });
5513
+ };
5514
+ return /* @__PURE__ */ jsx(
5515
+ Vector4ActionButton,
5516
+ {
5517
+ icon: /* @__PURE__ */ jsx(MapPin, { size: compact ? "1.1vh" : "1.3vh", color }),
5518
+ label: locale("Goto"),
5519
+ tooltip: locale("GotoWorldTooltip"),
5520
+ onClick: goto,
5521
+ color,
5522
+ compact
5523
+ }
5524
+ );
5525
+ }
5526
+ function Vector4DeleteButton({
5527
+ onClick,
5528
+ compact
5529
+ }) {
5530
+ const color = "#ef4444";
5531
+ return /* @__PURE__ */ jsx(
5532
+ Vector4ActionButton,
5533
+ {
5534
+ icon: /* @__PURE__ */ jsx(Trash2, { size: compact ? "1.1vh" : "1.3vh", color }),
5535
+ label: locale("Delete"),
5536
+ tooltip: locale("Delete"),
5537
+ onClick,
5538
+ color,
5539
+ compact
5540
+ }
5541
+ );
5542
+ }
5117
5543
  var GroupSelectContext = createContext(null);
5118
5544
  function GroupSelect({
5119
5545
  value,
@@ -5870,6 +6296,6 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
5870
6296
  return /* @__PURE__ */ jsx(MantineProvider, { theme: mergedTheme, defaultColorScheme: "dark", children: /* @__PURE__ */ jsx(DirkErrorBoundary, { children: content }) });
5871
6297
  }
5872
6298
 
5873
- export { AdminPageTitle, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DirkProvider, FiveMKeyBindInput, FloatingParticles, FormProvider, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GroupName, GroupRank, GroupSelect, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, InfoBox, InputContainer, LevelBanner, LevelPanel, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PositionPicker, PromptModal, SegmentedControl, SegmentedProgress, SelectItem, TestBed, Title, TornEdgeSVGFilter, colorWithAlpha, copyToClipboard, createFormStore, createScriptConfig, createSkill, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getGtaControl, getImageShape, getItemImageUrl, getScriptConfigInstance, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAudio, useAutoFetcher, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useFrameworkGroups, useItems, useItemsList, useModal, useModalActions, useNavigation, useNavigationStore, useNuiEvent, useProfanityStore, useSettings, useTornEdges };
6299
+ export { AdminPageTitle, AsyncSaveButton, BlipColorSelect, BlipDisplaySelect, BlipIconSelect, BorderedIcon, ConfigPanel, ConfirmModal, ControlMultiSelect, ControlSelect, Counter, DirkProvider, FiveMKeyBindInput, FloatingParticles, FormProvider, GTA_CONTROLS, GTA_CONTROL_GROUP_ORDER, GroupName, GroupRank, GroupSelect, INPUT_MAPPER_KEYS_BY_PRIMARY, INPUT_MAPPER_PRIMARY_OPTIONS, InfoBox, InputContainer, LevelBanner, LevelPanel, MissingItemsBanner, Modal, ModalContext, ModalProvider, MotionFlex, MotionIcon, MotionImage, MotionText, NavBar, NavigationContext, NavigationProvider, PositionPicker, PromptModal, SegmentedControl, SegmentedProgress, SelectItem, TestBed, Title, TornEdgeSVGFilter, Vector4DeleteButton, Vector4Display, WorldPositionGotoButton, WorldPositionSetButton, colorWithAlpha, copyToClipboard, createFormStore, createScriptConfig, createSkill, extractDefaults, fetchLuaTable, fetchNui, formatGtaControl, gameToMap, getGtaControl, getImageShape, getItemImageUrl, getScriptConfigInstance, initialFetches, internalEvent, isEnvBrowser, isProfanity, latPr100, locale, localeStore, mapCenter, mapToGame, noop, numberToRoman, openLink, registerInitialFetch, registerInitialLuaTableFetch, runFetches, selectAllGroups, splitFAString, updatePresignedURL, uploadImage, useAudio, useAutoFetcher, useForm, useFormActions, useFormError, useFormErrors, useFormField, useFormFields, useFrameworkGroups, useItems, useItemsList, useMissingItemsAudit, useModal, useModalActions, useNavigation, useNavigationStore, useNuiEvent, useProfanityStore, useSettings, useTornEdges };
5874
6300
  //# sourceMappingURL=index.js.map
5875
6301
  //# sourceMappingURL=index.js.map