dirk-cfx-react 1.1.72 → 1.1.75

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,7 +1,8 @@
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';
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, TestBedPlacement, TestBedProps, ThemeOverrideSection, ThemeOverrideSectionProps, ThemeOverrideValue, Title, TitleProps, TitleSize, 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';
5
+ import { z } from 'zod';
5
6
  import 'react/jsx-runtime';
6
7
  import '@mantine/core';
7
8
  import 'react';
@@ -9,3 +10,35 @@ import 'framer-motion';
9
10
  import '@fortawesome/fontawesome-svg-core';
10
11
  import 'zustand';
11
12
  import 'lucide-react';
13
+
14
+ /**
15
+ * 2-component vector (x, y). FiveM `vec2(x, y)`.
16
+ */
17
+ declare const Vector2Schema: z.ZodObject<{
18
+ x: z.ZodNumber;
19
+ y: z.ZodNumber;
20
+ }, z.core.$strip>;
21
+ type Vector2 = z.infer<typeof Vector2Schema>;
22
+ /**
23
+ * 3-component vector (x, y, z). FiveM `vec3(x, y, z)`.
24
+ * Used for positions, rotations, camera offsets.
25
+ */
26
+ declare const Vector3Schema: z.ZodObject<{
27
+ x: z.ZodNumber;
28
+ y: z.ZodNumber;
29
+ z: z.ZodNumber;
30
+ }, z.core.$strip>;
31
+ type Vector3 = z.infer<typeof Vector3Schema>;
32
+ /**
33
+ * 4-component vector (x, y, z, w). FiveM `vec4(x, y, z, w)`.
34
+ * `w` is typically heading (degrees) in worldspace positions.
35
+ */
36
+ declare const Vector4Schema: z.ZodObject<{
37
+ x: z.ZodNumber;
38
+ y: z.ZodNumber;
39
+ z: z.ZodNumber;
40
+ w: z.ZodNumber;
41
+ }, z.core.$strip>;
42
+ type Vector4 = z.infer<typeof Vector4Schema>;
43
+
44
+ export { type Vector2, Vector2Schema, type Vector3, Vector3Schema, type Vector4, Vector4Schema };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
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';
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, TestBedPlacement, TestBedProps, ThemeOverrideSection, ThemeOverrideSectionProps, ThemeOverrideValue, Title, TitleProps, TitleSize, 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';
5
+ import { z } from 'zod';
5
6
  import 'react/jsx-runtime';
6
7
  import '@mantine/core';
7
8
  import 'react';
@@ -9,3 +10,35 @@ import 'framer-motion';
9
10
  import '@fortawesome/fontawesome-svg-core';
10
11
  import 'zustand';
11
12
  import 'lucide-react';
13
+
14
+ /**
15
+ * 2-component vector (x, y). FiveM `vec2(x, y)`.
16
+ */
17
+ declare const Vector2Schema: z.ZodObject<{
18
+ x: z.ZodNumber;
19
+ y: z.ZodNumber;
20
+ }, z.core.$strip>;
21
+ type Vector2 = z.infer<typeof Vector2Schema>;
22
+ /**
23
+ * 3-component vector (x, y, z). FiveM `vec3(x, y, z)`.
24
+ * Used for positions, rotations, camera offsets.
25
+ */
26
+ declare const Vector3Schema: z.ZodObject<{
27
+ x: z.ZodNumber;
28
+ y: z.ZodNumber;
29
+ z: z.ZodNumber;
30
+ }, z.core.$strip>;
31
+ type Vector3 = z.infer<typeof Vector3Schema>;
32
+ /**
33
+ * 4-component vector (x, y, z, w). FiveM `vec4(x, y, z, w)`.
34
+ * `w` is typically heading (degrees) in worldspace positions.
35
+ */
36
+ declare const Vector4Schema: z.ZodObject<{
37
+ x: z.ZodNumber;
38
+ y: z.ZodNumber;
39
+ z: z.ZodNumber;
40
+ w: z.ZodNumber;
41
+ }, z.core.$strip>;
42
+ type Vector4 = z.infer<typeof Vector4Schema>;
43
+
44
+ export { type Vector2, Vector2Schema, type Vector3, Vector3Schema, type Vector4, Vector4Schema };
package/dist/index.js CHANGED
@@ -1,15 +1,16 @@
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';
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, Switch, ColorInput, Popover, MantineProvider, BackgroundImage, Group, JsonInput } from '@mantine/core';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
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, RefreshCw, ChevronDown, Check, Copy, MapPin, Crosshair, EyeOff, Eye, RotateCcw, FlaskConical, ChevronUp, 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, Palette, 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
11
  import { notifications } from '@mantine/notifications';
12
12
  import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
13
+ import { generateColors } from '@mantine/colors-generator';
13
14
  import '@mantine/core/styles.css';
14
15
  import '@mantine/notifications/styles.css';
15
16
  import './styles/fonts.css';
@@ -20,6 +21,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
20
21
  import { fab } from '@fortawesome/free-brands-svg-icons';
21
22
  import { far } from '@fortawesome/free-regular-svg-icons';
22
23
  import { fas } from '@fortawesome/free-solid-svg-icons';
24
+ import { z } from 'zod';
23
25
 
24
26
  var __defProp = Object.defineProperty;
25
27
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -1331,7 +1333,11 @@ async function fetchNui(eventName, data, mockData) {
1331
1333
  return {};
1332
1334
  }
1333
1335
  const overrideResourceName = useSettings.getState().overideResourceName;
1334
- const resourceName = window.GetParentResourceName ? window.GetParentResourceName() : overrideResourceName ? overrideResourceName : "dirk-cfx-react";
1336
+ const hasResourceContext = typeof window.GetParentResourceName === "function" || !!overrideResourceName;
1337
+ if (!hasResourceContext) {
1338
+ return mockData ?? {};
1339
+ }
1340
+ const resourceName = window.GetParentResourceName ? window.GetParentResourceName() : overrideResourceName;
1335
1341
  try {
1336
1342
  const resp = await fetch(`https://${resourceName}/${eventName}`, options);
1337
1343
  return await resp.json();
@@ -3074,9 +3080,25 @@ function SegmentedProgress(props) {
3074
3080
  }
3075
3081
  );
3076
3082
  }
3083
+ function getSizePreset(size, themeMdFontSize) {
3084
+ switch (size) {
3085
+ case "xs":
3086
+ return { iconFontSize: "1.2vh", iconPadding: "xxs", titleSize: "xxs", titleLineHeight: "1.2vh", descriptionSize: "xxs", innerGap: "xs", bottomPad: "xs" };
3087
+ case "sm":
3088
+ return { iconFontSize: "1.6vh", iconPadding: "xxs", titleSize: "xs", titleLineHeight: "1.6vh", descriptionSize: "xxs", innerGap: "xs", bottomPad: "xs" };
3089
+ case "lg":
3090
+ return { iconFontSize: "2.6vh", iconPadding: "sm", titleSize: "md", titleLineHeight: "2.6vh", descriptionSize: "sm", innerGap: "sm", bottomPad: "sm" };
3091
+ case "xl":
3092
+ return { iconFontSize: "3.2vh", iconPadding: "sm", titleSize: "lg", titleLineHeight: "3.2vh", descriptionSize: "md", innerGap: "md", bottomPad: "md" };
3093
+ case "md":
3094
+ default:
3095
+ return { iconFontSize: themeMdFontSize, iconPadding: "xs", titleSize: "sm", titleLineHeight: themeMdFontSize, descriptionSize: "xs", innerGap: "sm", bottomPad: "sm" };
3096
+ }
3097
+ }
3077
3098
  function Title(props) {
3078
3099
  const game = useSettings((state) => state.game);
3079
3100
  const theme2 = useMantineTheme();
3101
+ const preset = getSizePreset(props.size ?? "md", theme2.fontSizes.md);
3080
3102
  return /* @__PURE__ */ jsx(
3081
3103
  Flex,
3082
3104
  {
@@ -3085,71 +3107,50 @@ function Title(props) {
3085
3107
  gap: "xs",
3086
3108
  w: props.w || "100%",
3087
3109
  p: props.p || "unset",
3088
- pb: !props.p ? "sm" : props.p,
3110
+ pb: !props.p ? preset.bottomPad : props.p,
3089
3111
  style: {
3090
3112
  userSelect: "none",
3091
3113
  borderBottom: props.removeBorder ? "none" : `0.3vh solid ${props.borderColor || colorWithAlpha(theme2.colors[theme2.primaryColor][9], 0.5)}`
3092
3114
  },
3093
- children: /* @__PURE__ */ jsxs(
3094
- Flex,
3095
- {
3096
- align: "center",
3097
- justify: "center",
3098
- children: [
3099
- /* @__PURE__ */ jsxs(
3100
- Flex,
3115
+ children: /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "center", children: [
3116
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: preset.innerGap, pr: "xs", children: [
3117
+ /* @__PURE__ */ jsx(
3118
+ BorderedIcon,
3119
+ {
3120
+ icon: props.icon,
3121
+ fontSize: preset.iconFontSize,
3122
+ color: props.iconColor,
3123
+ p: preset.iconPadding
3124
+ }
3125
+ ),
3126
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "0.25vh", children: [
3127
+ /* @__PURE__ */ jsx(
3128
+ Text,
3101
3129
  {
3102
- align: "center",
3103
- gap: "sm",
3104
- pr: "xs",
3105
- children: [
3106
- /* @__PURE__ */ jsx(
3107
- BorderedIcon,
3108
- {
3109
- icon: props.icon,
3110
- fontSize: theme2.fontSizes.md,
3111
- color: props.iconColor
3112
- }
3113
- ),
3114
- /* @__PURE__ */ jsxs(
3115
- Flex,
3116
- {
3117
- direction: "column",
3118
- gap: "0.25vh",
3119
- children: [
3120
- /* @__PURE__ */ jsx(Text, { p: "0", size: "sm", style: {
3121
- lineHeight: theme2.fontSizes.md,
3122
- fontFamily: game == "fivem" ? "Akrobat Bold" : "Red Dead",
3123
- letterSpacing: "0.05em",
3124
- textTransform: "uppercase"
3125
- }, children: props.title }),
3126
- /* @__PURE__ */ jsx(
3127
- Text,
3128
- {
3129
- size: "xs",
3130
- c: "grey",
3131
- style: { whiteSpace: "normal", wordWrap: "break-word" },
3132
- children: props.description
3133
- }
3134
- )
3135
- ]
3136
- }
3137
- )
3138
- ]
3130
+ p: "0",
3131
+ size: preset.titleSize,
3132
+ style: {
3133
+ lineHeight: preset.titleLineHeight,
3134
+ fontFamily: game == "fivem" ? "Akrobat Bold" : "Red Dead",
3135
+ letterSpacing: "0.05em",
3136
+ textTransform: "uppercase"
3137
+ },
3138
+ children: props.title
3139
3139
  }
3140
3140
  ),
3141
3141
  /* @__PURE__ */ jsx(
3142
- Flex,
3142
+ Text,
3143
3143
  {
3144
- ml: "auto",
3145
- align: "center",
3146
- gap: "xs",
3147
- children: props.rightSection
3144
+ size: preset.descriptionSize,
3145
+ c: "grey",
3146
+ style: { whiteSpace: "normal", wordWrap: "break-word" },
3147
+ children: props.description
3148
3148
  }
3149
3149
  )
3150
- ]
3151
- }
3152
- )
3150
+ ] })
3151
+ ] }),
3152
+ /* @__PURE__ */ jsx(Flex, { ml: "auto", align: "center", gap: "xs", children: props.rightSection })
3153
+ ] })
3153
3154
  }
3154
3155
  );
3155
3156
  }
@@ -4826,7 +4827,22 @@ function ConfigPanelInner({
4826
4827
  if (result?.success) {
4827
4828
  const { store } = getScriptConfigInstance();
4828
4829
  form.reinitialize(cloneConfig(store.getState()));
4830
+ notifications.show({
4831
+ color: "green",
4832
+ title: locale("ConfigResetSuccessTitle"),
4833
+ message: locale("ConfigResetSuccessBody"),
4834
+ autoClose: 3e3
4835
+ });
4836
+ return;
4829
4837
  }
4838
+ const err = result?._error || "Unknown";
4839
+ console.warn(`[ConfigPanel] config reset failed: ${err}`);
4840
+ notifications.show({
4841
+ color: "red",
4842
+ title: locale("ConfigResetFailedTitle"),
4843
+ message: locale("ConfigResetFailedBody", err),
4844
+ autoClose: 6e3
4845
+ });
4830
4846
  },
4831
4847
  onClose: () => setResetOpen(false),
4832
4848
  zIndex: 300
@@ -4894,8 +4910,8 @@ function ConfigPanelInner({
4894
4910
  children: /* @__PURE__ */ jsx(ArrowLeft, { size: "1.4vh", color })
4895
4911
  }
4896
4912
  ),
4897
- /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { minWidth: 0, lineHeight: 1 }, children: [
4898
- /* @__PURE__ */ jsx(Text, { size: "lg", ff: "Akrobat Bold", tt: "uppercase", lts: "0.04em", truncate: true, children: title }),
4913
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { minWidth: 0, flex: 1, lineHeight: 1, overflow: "hidden" }, children: [
4914
+ /* @__PURE__ */ jsx(Text, { size: "md", ff: "Akrobat Bold", tt: "uppercase", lts: "0.04em", truncate: true, children: title }),
4899
4915
  subtitle && /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.08em", c: color, truncate: true, children: subtitle })
4900
4916
  ] })
4901
4917
  ] }),
@@ -5836,6 +5852,17 @@ function AdminPageTitle(props) {
5836
5852
  /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", tt: "uppercase", lts: "0.1em", size: "sm", c: "rgba(255,255,255,0.6)", children: locale(props.title) })
5837
5853
  ] });
5838
5854
  }
5855
+ var placementStyle = (placement) => {
5856
+ switch (placement) {
5857
+ case "top-center":
5858
+ return { top: "1vh", left: "50%", transform: "translateX(-50%)" };
5859
+ case "top-right":
5860
+ return { top: "1vh", right: "1vh" };
5861
+ case "top-left":
5862
+ default:
5863
+ return { top: "1vh", left: "1vh" };
5864
+ }
5865
+ };
5839
5866
  var loadPersistedState = (storageKey) => {
5840
5867
  try {
5841
5868
  const raw = localStorage.getItem(storageKey);
@@ -5854,7 +5881,8 @@ function TestBed({
5854
5881
  items,
5855
5882
  storageKey = "testbed:open-state",
5856
5883
  disablePersistence = false,
5857
- title = "TestBed"
5884
+ title = "TestBed",
5885
+ placement = "top-left"
5858
5886
  }) {
5859
5887
  const [open, setOpen] = useState(false);
5860
5888
  const itemsRef = useRef(items);
@@ -5884,8 +5912,7 @@ function TestBed({
5884
5912
  {
5885
5913
  style: {
5886
5914
  position: "fixed",
5887
- top: "1vh",
5888
- left: "1vh",
5915
+ ...placementStyle(placement),
5889
5916
  zIndex: 2147483647,
5890
5917
  pointerEvents: "auto",
5891
5918
  fontSize: "1.4vh"
@@ -5990,6 +6017,281 @@ function TestBed({
5990
6017
  }
5991
6018
  );
5992
6019
  }
6020
+ var MANTINE_COLOR_OPTIONS = [
6021
+ "dirk",
6022
+ "red",
6023
+ "pink",
6024
+ "grape",
6025
+ "violet",
6026
+ "indigo",
6027
+ "blue",
6028
+ "cyan",
6029
+ "teal",
6030
+ "green",
6031
+ "lime",
6032
+ "yellow",
6033
+ "orange"
6034
+ ].map((value) => ({ value, label: value }));
6035
+ var DEFAULT_PALETTE = [
6036
+ "#f0f4ff",
6037
+ "#d9e3ff",
6038
+ "#bfcfff",
6039
+ "#a6bbff",
6040
+ "#8ca7ff",
6041
+ "#7393ff",
6042
+ "#5a7fff",
6043
+ "#406bff",
6044
+ "#2547ff",
6045
+ "#0b33ff"
6046
+ ];
6047
+ var DEFAULT_VALUE = {
6048
+ useOverride: false,
6049
+ primaryColor: "dirk",
6050
+ primaryShade: 5,
6051
+ customTheme: DEFAULT_PALETTE
6052
+ };
6053
+ function GroupLabel({ label: label2 }) {
6054
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", mt: "xxs", children: [
6055
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", tt: "uppercase", lts: "0.07em", c: "rgba(255,255,255,0.2)", children: label2 }),
6056
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: "0.05vh", background: "rgba(255,255,255,0.06)" } })
6057
+ ] });
6058
+ }
6059
+ function ThemeOverrideSection({
6060
+ schemaKey = "theme",
6061
+ title
6062
+ }) {
6063
+ const mantineTheme = useMantineTheme();
6064
+ const color = mantineTheme.colors[mantineTheme.primaryColor][5];
6065
+ const raw = useFormField(schemaKey);
6066
+ const value = {
6067
+ useOverride: raw?.useOverride ?? DEFAULT_VALUE.useOverride,
6068
+ primaryColor: raw?.primaryColor ?? DEFAULT_VALUE.primaryColor,
6069
+ primaryShade: raw?.primaryShade ?? DEFAULT_VALUE.primaryShade,
6070
+ customTheme: Array.isArray(raw?.customTheme) && raw.customTheme.length === 10 ? raw.customTheme : DEFAULT_VALUE.customTheme
6071
+ };
6072
+ const { setValue } = useFormActions();
6073
+ const set = (key, val) => setValue(schemaKey, { ...value, [key]: val });
6074
+ const useCustom = value.primaryColor === "custom";
6075
+ const editable = value.useOverride;
6076
+ const setSwatch = (index, hex) => {
6077
+ const next = [...value.customTheme];
6078
+ next[index] = hex;
6079
+ set("customTheme", next);
6080
+ };
6081
+ const generateFromBase = (hex) => {
6082
+ try {
6083
+ const generated = generateColors(hex);
6084
+ set("customTheme", generated);
6085
+ } catch {
6086
+ }
6087
+ };
6088
+ const resetPalette = () => set("customTheme", DEFAULT_PALETTE);
6089
+ return /* @__PURE__ */ jsxs(
6090
+ Flex,
6091
+ {
6092
+ direction: "column",
6093
+ gap: "xs",
6094
+ p: "sm",
6095
+ style: { flex: 1, minHeight: 0, overflowY: "auto" },
6096
+ children: [
6097
+ /* @__PURE__ */ jsx(
6098
+ AdminPageTitle,
6099
+ {
6100
+ icon: Palette,
6101
+ title: title || locale("Theme") || "Theme",
6102
+ color
6103
+ }
6104
+ ),
6105
+ /* @__PURE__ */ jsxs(
6106
+ Flex,
6107
+ {
6108
+ align: "center",
6109
+ justify: "space-between",
6110
+ p: "xs",
6111
+ style: {
6112
+ background: `rgba(255,255,255,${editable ? 0.04 : 0.02})`,
6113
+ border: `0.1vh solid ${editable ? color : "rgba(255,255,255,0.08)"}`,
6114
+ borderRadius: mantineTheme.radius.xs,
6115
+ transition: "background 0.15s, border-color 0.15s"
6116
+ },
6117
+ children: [
6118
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "xxs", style: { flex: 1, minWidth: 0 }, children: [
6119
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xs", c: "rgba(255,255,255,0.9)", children: locale("OverrideGlobalTheme") || "Override global theme" }),
6120
+ /* @__PURE__ */ jsx(Text, { ff: "Akrobat Bold", size: "xxs", c: "rgba(255,255,255,0.4)", children: locale("OverrideGlobalThemeDesc") || "When on, this resource uses its own primary colour and palette instead of dirk_lib's. Turn off to fall back to the global theme \u2014 your custom palette is kept." })
6121
+ ] }),
6122
+ /* @__PURE__ */ jsx(
6123
+ Switch,
6124
+ {
6125
+ size: "md",
6126
+ checked: value.useOverride,
6127
+ onChange: (e) => set("useOverride", e.currentTarget.checked)
6128
+ }
6129
+ )
6130
+ ]
6131
+ }
6132
+ ),
6133
+ /* @__PURE__ */ jsxs(
6134
+ "div",
6135
+ {
6136
+ style: {
6137
+ opacity: editable ? 1 : 0.4,
6138
+ pointerEvents: editable ? "auto" : "none",
6139
+ transition: "opacity 0.15s"
6140
+ },
6141
+ children: [
6142
+ /* @__PURE__ */ jsx(GroupLabel, { label: locale("PrimaryColor") || "Primary Colour" }),
6143
+ /* @__PURE__ */ jsx(
6144
+ Switch,
6145
+ {
6146
+ label: locale("UseCustomPalette") || "Use custom palette",
6147
+ size: "md",
6148
+ checked: useCustom,
6149
+ onChange: (e) => set("primaryColor", e.currentTarget.checked ? "custom" : "dirk"),
6150
+ styles: {
6151
+ label: {
6152
+ fontFamily: "Akrobat Bold",
6153
+ fontSize: "0.65em",
6154
+ letterSpacing: "0.06em",
6155
+ textTransform: "uppercase",
6156
+ color: "rgba(255,255,255,0.35)"
6157
+ }
6158
+ }
6159
+ }
6160
+ ),
6161
+ /* @__PURE__ */ jsxs(Flex, { gap: "xs", mt: "xs", children: [
6162
+ !useCustom && /* @__PURE__ */ jsx(
6163
+ Select,
6164
+ {
6165
+ label: locale("MantinePalette") || "Mantine palette",
6166
+ size: "xs",
6167
+ style: { flex: 1 },
6168
+ value: value.primaryColor,
6169
+ data: MANTINE_COLOR_OPTIONS,
6170
+ allowDeselect: false,
6171
+ onChange: (v) => v && set("primaryColor", v)
6172
+ }
6173
+ ),
6174
+ /* @__PURE__ */ jsx(
6175
+ NumberInput,
6176
+ {
6177
+ label: locale("Shade") || "Shade",
6178
+ size: "xs",
6179
+ style: { flex: 1 },
6180
+ min: 0,
6181
+ max: 9,
6182
+ value: value.primaryShade,
6183
+ onChange: (v) => set("primaryShade", Number(v))
6184
+ }
6185
+ )
6186
+ ] }),
6187
+ useCustom && /* @__PURE__ */ jsxs(Fragment, { children: [
6188
+ /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", mt: "sm", children: [
6189
+ /* @__PURE__ */ jsx(
6190
+ Text,
6191
+ {
6192
+ ff: "Akrobat Bold",
6193
+ size: "xxs",
6194
+ tt: "uppercase",
6195
+ lts: "0.07em",
6196
+ c: "rgba(255,255,255,0.2)",
6197
+ children: locale("CustomPalette") || "Custom palette"
6198
+ }
6199
+ ),
6200
+ /* @__PURE__ */ jsx(
6201
+ ActionIcon,
6202
+ {
6203
+ size: "sm",
6204
+ variant: "subtle",
6205
+ onClick: resetPalette,
6206
+ title: locale("ResetPalette") || "Reset palette",
6207
+ children: /* @__PURE__ */ jsx(RotateCcw, { size: "1.4vh" })
6208
+ }
6209
+ )
6210
+ ] }),
6211
+ /* @__PURE__ */ jsx(
6212
+ ColorInput,
6213
+ {
6214
+ label: locale("BaseColor") || "Base colour",
6215
+ size: "xs",
6216
+ value: value.customTheme[value.primaryShade] ?? value.customTheme[5] ?? "#000000",
6217
+ onChange: generateFromBase,
6218
+ eyeDropperIcon: /* @__PURE__ */ jsx(Fragment, {})
6219
+ }
6220
+ ),
6221
+ /* @__PURE__ */ jsx(Flex, { gap: "xxs", mt: "xxs", children: value.customTheme.map((swatch, i) => /* @__PURE__ */ jsx(
6222
+ SwatchTile,
6223
+ {
6224
+ index: i,
6225
+ value: swatch,
6226
+ isPrimary: i === value.primaryShade,
6227
+ onChange: (v) => setSwatch(i, v)
6228
+ },
6229
+ i
6230
+ )) })
6231
+ ] })
6232
+ ]
6233
+ }
6234
+ )
6235
+ ]
6236
+ }
6237
+ );
6238
+ }
6239
+ function SwatchTile({
6240
+ index,
6241
+ value,
6242
+ isPrimary,
6243
+ onChange
6244
+ }) {
6245
+ const [opened, setOpened] = useState(false);
6246
+ return /* @__PURE__ */ jsxs(Popover, { opened, onChange: setOpened, position: "bottom", withArrow: true, zIndex: 1e4, children: [
6247
+ /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(
6248
+ "button",
6249
+ {
6250
+ onClick: () => setOpened((o) => !o),
6251
+ title: `${index} \xB7 ${value}`,
6252
+ style: {
6253
+ flex: 1,
6254
+ aspectRatio: "1 / 1",
6255
+ background: value,
6256
+ border: isPrimary ? "0.2vh solid rgba(255,255,255,0.85)" : "0.1vh solid rgba(255,255,255,0.15)",
6257
+ borderRadius: "0.4vh",
6258
+ cursor: "pointer",
6259
+ padding: 0,
6260
+ display: "flex",
6261
+ alignItems: "flex-end",
6262
+ justifyContent: "flex-end",
6263
+ position: "relative"
6264
+ },
6265
+ children: /* @__PURE__ */ jsx(
6266
+ "span",
6267
+ {
6268
+ style: {
6269
+ fontFamily: "Akrobat Bold",
6270
+ fontSize: "0.9vh",
6271
+ lineHeight: 1,
6272
+ padding: "0.2vh 0.3vh",
6273
+ color: "rgba(0,0,0,0.55)",
6274
+ background: "rgba(255,255,255,0.55)",
6275
+ borderRadius: "0.25vh",
6276
+ margin: "0.2vh"
6277
+ },
6278
+ children: index
6279
+ }
6280
+ )
6281
+ }
6282
+ ) }),
6283
+ /* @__PURE__ */ jsx(Popover.Dropdown, { p: "xs", children: /* @__PURE__ */ jsx(
6284
+ ColorInput,
6285
+ {
6286
+ size: "xs",
6287
+ value,
6288
+ onChange,
6289
+ format: "hex",
6290
+ eyeDropperIcon: /* @__PURE__ */ jsx(Fragment, {})
6291
+ }
6292
+ ) })
6293
+ ] });
6294
+ }
5993
6295
  function useTornEdges() {
5994
6296
  const game = useSettings((state) => state.game);
5995
6297
  return game === "rdr3" ? "torn-edge-wrapper" : "";
@@ -6271,6 +6573,12 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
6271
6573
  }, []);
6272
6574
  useNuiEvent("UPDATE_DIRK_LIB_SETTINGS", (data) => {
6273
6575
  if (!data || typeof data !== "object") return;
6576
+ const current = useSettings.getState();
6577
+ if (current.themeOverride) {
6578
+ const { primaryColor: _pc, primaryShade: _ps, customTheme: _ct, ...rest } = data;
6579
+ useSettings.setState(rest);
6580
+ return;
6581
+ }
6274
6582
  useSettings.setState(data);
6275
6583
  });
6276
6584
  const mergedTheme = useMemo(
@@ -6295,7 +6603,22 @@ function DirkProvider({ children, overideResourceName, themeOverride }) {
6295
6603
  ) : children;
6296
6604
  return /* @__PURE__ */ jsx(MantineProvider, { theme: mergedTheme, defaultColorScheme: "dark", children: /* @__PURE__ */ jsx(DirkErrorBoundary, { children: content }) });
6297
6605
  }
6606
+ var Vector2Schema = z.object({
6607
+ x: z.number(),
6608
+ y: z.number()
6609
+ });
6610
+ var Vector3Schema = z.object({
6611
+ x: z.number(),
6612
+ y: z.number(),
6613
+ z: z.number()
6614
+ });
6615
+ var Vector4Schema = z.object({
6616
+ x: z.number(),
6617
+ y: z.number(),
6618
+ z: z.number(),
6619
+ w: z.number()
6620
+ });
6298
6621
 
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 };
6622
+ 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, ThemeOverrideSection, Title, TornEdgeSVGFilter, Vector2Schema, Vector3Schema, Vector4DeleteButton, Vector4Display, Vector4Schema, 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 };
6300
6623
  //# sourceMappingURL=index.js.map
6301
6624
  //# sourceMappingURL=index.js.map