fivem-nui-react 1.0.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.
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # fivem-nui-react
2
+
3
+ React hooks and utilities for FiveM NUI development.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install fivem-nui-react
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **useNuiEvent** - Listen for NUI messages from Lua
14
+ - **fetchNui** - Send requests to Lua client and receive responses
15
+ - **useNuiCallback** - Hook for NUI requests with loading/error states
16
+ - **isEnvBrowser** - Check if running in browser (debug mode)
17
+ - **Mock data support** - Test your UI in browser with simulated responses
18
+
19
+ ## API Reference
20
+
21
+ ### useNuiEvent
22
+
23
+ Listen for NUI messages sent from Lua.
24
+
25
+ ```tsx
26
+ useNuiEvent<T>(action: string, handler: (data: T) => void, options?: UseNuiEventOptions<T>): void
27
+ ```
28
+
29
+ **Parameters:**
30
+
31
+ - `action` - The action name to listen for
32
+ - `handler` - Callback function executed when message is received
33
+ - `options` - Optional mock data configuration for browser testing
34
+
35
+ **Example:**
36
+
37
+ ```tsx
38
+ import { useNuiEvent } from "fivem-nui-react";
39
+
40
+ function App() {
41
+ const [visible, setVisible] = useState(false);
42
+
43
+ useNuiEvent<{ show: boolean }>("toggleUI", (data) => {
44
+ setVisible(data.show);
45
+ });
46
+
47
+ // With mock data for browser testing
48
+ useNuiEvent<{ show: boolean }>("toggleUI", (data) => setVisible(data.show), {
49
+ mockData: { show: true },
50
+ mockDelay: 1000,
51
+ });
52
+
53
+ return visible ? <div>UI Content</div> : null;
54
+ }
55
+ ```
56
+
57
+ **Fivem client side:**
58
+
59
+ ```lua
60
+ SendNUIMessage({
61
+ action = "toggleUI",
62
+ data = { show = true }
63
+ })
64
+ ```
65
+
66
+ ---
67
+
68
+ ### fetchNui
69
+
70
+ Send a request to the Fivem client and receive a response.
71
+
72
+ ```tsx
73
+ fetchNui<T, D>(eventName: string, data?: D, options?: FetchNuiOptions<T>): Promise<T>
74
+ ```
75
+
76
+ **Parameters:**
77
+
78
+ - `eventName` - The NUI callback event name
79
+ - `data` - Data to send to Lua
80
+ - `options` - Optional mock data configuration for browser testing
81
+
82
+ **Example:**
83
+
84
+ ```tsx
85
+ import { fetchNui } from "fivem-nui-react";
86
+
87
+ interface PlayerData {
88
+ name: string;
89
+ level: number;
90
+ }
91
+
92
+ async function getPlayer() {
93
+ const player = await fetchNui<PlayerData>("getPlayerData", { id: 1 });
94
+ console.log(player.name, player.level);
95
+ }
96
+
97
+ // With mock data for browser testing
98
+ async function getPlayerMocked() {
99
+ const player = await fetchNui<PlayerData>(
100
+ "getPlayerData",
101
+ { id: 1 },
102
+ {
103
+ mockData: { name: "John", level: 10 },
104
+ mockDelay: 500,
105
+ },
106
+ );
107
+ console.log(player.name, player.level);
108
+ }
109
+ ```
110
+
111
+ **Lua side:**
112
+
113
+ ```lua
114
+ RegisterNUICallback("getPlayerData", function(data, cb)
115
+ local playerId = data.id
116
+ -- Fetch player data...
117
+ cb({ name = "John", level = 10 })
118
+ end)
119
+ ```
120
+
121
+ ---
122
+
123
+ ### useNuiCallback
124
+
125
+ A hook that wraps `fetchNui` with loading and error state management.
126
+
127
+ ```tsx
128
+ useNuiCallback<T, D>(
129
+ eventName: string,
130
+ callback: (data: T) => void,
131
+ options?: UseNuiCallbackOptions<T>
132
+ ): [fetchFn: (data?: D) => Promise<T>, state: { loading: boolean, error: Error | null }]
133
+ ```
134
+
135
+ **Parameters:**
136
+
137
+ - `eventName` - The NUI callback event name
138
+ - `callback` - Callback function executed when response is received
139
+ - `options` - Optional mock data configuration for browser testing
140
+
141
+ **Returns:**
142
+
143
+ - `fetchFn` - Function to trigger the request
144
+ - `state.loading` - Boolean indicating if request is in progress
145
+ - `state.error` - Error object if request failed
146
+
147
+ **Example:**
148
+
149
+ ```tsx
150
+ import { useNuiCallback } from "fivem-nui-react";
151
+
152
+ interface PlayerData {
153
+ name: string;
154
+ level: number;
155
+ }
156
+
157
+ function PlayerInfo() {
158
+ const [player, setPlayer] = useState<PlayerData | null>(null);
159
+
160
+ const [fetchPlayer, { loading, error }] = useNuiCallback<PlayerData>(
161
+ "getPlayerData",
162
+ (data) => setPlayer(data),
163
+ {
164
+ mockData: { name: "John", level: 10 },
165
+ mockDelay: 500,
166
+ },
167
+ );
168
+
169
+ useEffect(() => {
170
+ fetchPlayer({ id: 1 });
171
+ }, [fetchPlayer]);
172
+
173
+ if (loading) return <div>Loading...</div>;
174
+ if (error) return <div>Error: {error.message}</div>;
175
+ if (!player) return null;
176
+
177
+ return (
178
+ <div>
179
+ <p>Name: {player.name}</p>
180
+ <p>Level: {player.level}</p>
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ---
187
+
188
+ ### isEnvBrowser
189
+
190
+ Check if running in browser (outside FiveM).
191
+
192
+ ```tsx
193
+ isEnvBrowser(): boolean
194
+ ```
195
+
196
+ **Example:**
197
+
198
+ ```tsx
199
+ import { isEnvBrowser } from "fivem-nui-react";
200
+
201
+ if (isEnvBrowser()) {
202
+ console.log("Running in browser - debug mode");
203
+ } else {
204
+ console.log("Running in FiveM");
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Browser Testing (Mock Data)
211
+
212
+ All hooks and functions support mock data for testing your UI in a regular browser without FiveM.
213
+
214
+ When `isEnvBrowser()` returns `true`:
215
+
216
+ - `useNuiEvent` will trigger the handler with `mockData` after `mockDelay` milliseconds
217
+ - `fetchNui` will return `mockData` after `mockDelay` milliseconds
218
+ - `useNuiCallback` will call the callback with `mockData` after `mockDelay` milliseconds
219
+
220
+ **Options:**
221
+
222
+ - `mockData` - The data to return in browser mode
223
+ - `mockDelay` - Delay in milliseconds before returning data (default: 500ms)
224
+
225
+ ---
226
+
227
+ ## TypeScript Support
228
+
229
+ All functions are fully typed with generics:
230
+
231
+ ```tsx
232
+ // Define your types
233
+ interface ShowUIData {
234
+ visible: boolean;
235
+ title: string;
236
+ }
237
+
238
+ interface PlayerRequest {
239
+ id: number;
240
+ }
241
+
242
+ interface PlayerResponse {
243
+ name: string;
244
+ level: number;
245
+ }
246
+
247
+ // Use with type parameters
248
+ useNuiEvent<ShowUIData>("showUI", (data) => {
249
+ // data is typed as ShowUIData
250
+ console.log(data.visible, data.title);
251
+ });
252
+
253
+ const player = await fetchNui<PlayerResponse, PlayerRequest>("getPlayer", {
254
+ id: 1,
255
+ });
256
+ // player is typed as PlayerResponse
257
+
258
+ const [fetchPlayer, { loading }] = useNuiCallback<
259
+ PlayerResponse,
260
+ PlayerRequest
261
+ >("getPlayer", (data) => console.log(data.name));
262
+ ```
263
+
264
+ ---
265
+
266
+ ## License
267
+
268
+ MIT
@@ -0,0 +1,74 @@
1
+ interface NuiMessageEvent<T = unknown> {
2
+ action: string;
3
+ data: T;
4
+ }
5
+ type NuiEventHandler<T = unknown> = (data: T) => void;
6
+ interface UseNuiEventOptions<T = unknown> {
7
+ mockData?: T;
8
+ mockDelay?: number;
9
+ }
10
+ interface FetchNuiOptions<T = unknown> {
11
+ mockData?: T;
12
+ mockDelay?: number;
13
+ }
14
+ /**
15
+ * Checks if running in browser debug mode
16
+ */
17
+ declare function isEnvBrowser(): boolean;
18
+ /**
19
+ * React hook for listening to NUI messages from Lua
20
+ * @param action - The action name to listen for
21
+ * @param handler - Callback function to execute when message is received
22
+ * @param options - Options for mock data in browser mode
23
+ * @example
24
+ * useNuiEvent("showUI", (data) => {
25
+ * setVisible(data.visible);
26
+ * }, { mockData: { visible: true }, mockDelay: 1000 });
27
+ */
28
+ declare function useNuiEvent<T = unknown>(action: string, handler: NuiEventHandler<T>, options?: UseNuiEventOptions<T>): void;
29
+ /**
30
+ * Sends a request to NUI callback (fivem client)
31
+ * @param eventName - The callback event name
32
+ * @param data - Data to send
33
+ * @param options - Options for mock data in browser mode
34
+ * @returns Promise<T> - Response from fivem client
35
+ * @example
36
+ * const result = await fetchNui("getPlayerData", { id: 1 }, {
37
+ * mockData: { name: "John", level: 10 },
38
+ * mockDelay: 500
39
+ * });
40
+ */
41
+ declare function fetchNui<T = unknown, D = unknown>(eventName: string, data?: D, options?: FetchNuiOptions<T>): Promise<T>;
42
+ interface UseNuiCallbackOptions<T = unknown> {
43
+ mockData?: T;
44
+ mockDelay?: number;
45
+ }
46
+ interface UseNuiCallbackState {
47
+ loading: boolean;
48
+ error: Error | null;
49
+ }
50
+ type UseNuiCallbackReturn<T, D> = [
51
+ (data?: D) => Promise<T>,
52
+ UseNuiCallbackState
53
+ ];
54
+ /**
55
+ * React hook for making NUI callback requests with loading and error states
56
+ * @param eventName - The callback event name
57
+ * @param callback - Callback function to execute when response is received
58
+ * @param options - Options for mock data in browser mode
59
+ * @returns [fetchFunction, { loading, error }]
60
+ * @example
61
+ * const [fetchPlayer, { loading, error }] = useNuiCallback<PlayerData>("getPlayer", (data) => {
62
+ * setPlayer(data);
63
+ * }, {
64
+ * mockData: { name: "John", level: 10 },
65
+ * mockDelay: 500
66
+ * });
67
+ *
68
+ * useEffect(() => {
69
+ * fetchPlayer({ id: 1 });
70
+ * }, [fetchPlayer]);
71
+ */
72
+ declare function useNuiCallback<T = unknown, D = unknown>(eventName: string, callback: (data: T) => void, options?: UseNuiCallbackOptions<T>): UseNuiCallbackReturn<T, D>;
73
+
74
+ export { type FetchNuiOptions, type NuiEventHandler, type NuiMessageEvent, type UseNuiCallbackOptions, type UseNuiCallbackReturn, type UseNuiCallbackState, type UseNuiEventOptions, fetchNui, isEnvBrowser, useNuiCallback, useNuiEvent };
@@ -0,0 +1,74 @@
1
+ interface NuiMessageEvent<T = unknown> {
2
+ action: string;
3
+ data: T;
4
+ }
5
+ type NuiEventHandler<T = unknown> = (data: T) => void;
6
+ interface UseNuiEventOptions<T = unknown> {
7
+ mockData?: T;
8
+ mockDelay?: number;
9
+ }
10
+ interface FetchNuiOptions<T = unknown> {
11
+ mockData?: T;
12
+ mockDelay?: number;
13
+ }
14
+ /**
15
+ * Checks if running in browser debug mode
16
+ */
17
+ declare function isEnvBrowser(): boolean;
18
+ /**
19
+ * React hook for listening to NUI messages from Lua
20
+ * @param action - The action name to listen for
21
+ * @param handler - Callback function to execute when message is received
22
+ * @param options - Options for mock data in browser mode
23
+ * @example
24
+ * useNuiEvent("showUI", (data) => {
25
+ * setVisible(data.visible);
26
+ * }, { mockData: { visible: true }, mockDelay: 1000 });
27
+ */
28
+ declare function useNuiEvent<T = unknown>(action: string, handler: NuiEventHandler<T>, options?: UseNuiEventOptions<T>): void;
29
+ /**
30
+ * Sends a request to NUI callback (fivem client)
31
+ * @param eventName - The callback event name
32
+ * @param data - Data to send
33
+ * @param options - Options for mock data in browser mode
34
+ * @returns Promise<T> - Response from fivem client
35
+ * @example
36
+ * const result = await fetchNui("getPlayerData", { id: 1 }, {
37
+ * mockData: { name: "John", level: 10 },
38
+ * mockDelay: 500
39
+ * });
40
+ */
41
+ declare function fetchNui<T = unknown, D = unknown>(eventName: string, data?: D, options?: FetchNuiOptions<T>): Promise<T>;
42
+ interface UseNuiCallbackOptions<T = unknown> {
43
+ mockData?: T;
44
+ mockDelay?: number;
45
+ }
46
+ interface UseNuiCallbackState {
47
+ loading: boolean;
48
+ error: Error | null;
49
+ }
50
+ type UseNuiCallbackReturn<T, D> = [
51
+ (data?: D) => Promise<T>,
52
+ UseNuiCallbackState
53
+ ];
54
+ /**
55
+ * React hook for making NUI callback requests with loading and error states
56
+ * @param eventName - The callback event name
57
+ * @param callback - Callback function to execute when response is received
58
+ * @param options - Options for mock data in browser mode
59
+ * @returns [fetchFunction, { loading, error }]
60
+ * @example
61
+ * const [fetchPlayer, { loading, error }] = useNuiCallback<PlayerData>("getPlayer", (data) => {
62
+ * setPlayer(data);
63
+ * }, {
64
+ * mockData: { name: "John", level: 10 },
65
+ * mockDelay: 500
66
+ * });
67
+ *
68
+ * useEffect(() => {
69
+ * fetchPlayer({ id: 1 });
70
+ * }, [fetchPlayer]);
71
+ */
72
+ declare function useNuiCallback<T = unknown, D = unknown>(eventName: string, callback: (data: T) => void, options?: UseNuiCallbackOptions<T>): UseNuiCallbackReturn<T, D>;
73
+
74
+ export { type FetchNuiOptions, type NuiEventHandler, type NuiMessageEvent, type UseNuiCallbackOptions, type UseNuiCallbackReturn, type UseNuiCallbackState, type UseNuiEventOptions, fetchNui, isEnvBrowser, useNuiCallback, useNuiEvent };
package/dist/index.js ADDED
@@ -0,0 +1,105 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.ts
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ fetchNui: () => fetchNui,
23
+ isEnvBrowser: () => isEnvBrowser,
24
+ useNuiCallback: () => useNuiCallback,
25
+ useNuiEvent: () => useNuiEvent
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+ var import_react = require("react");
29
+ var resourceName = window.GetParentResourceName ? window.GetParentResourceName() : "nui-frame-app";
30
+ function isEnvBrowser() {
31
+ return !window.invokeNative;
32
+ }
33
+ function useNuiEvent(action, handler, options) {
34
+ const savedHandler = (0, import_react.useRef)(handler);
35
+ (0, import_react.useEffect)(() => {
36
+ savedHandler.current = handler;
37
+ }, [handler]);
38
+ (0, import_react.useEffect)(() => {
39
+ if (isEnvBrowser()) {
40
+ if ((options == null ? void 0 : options.mockData) === void 0) return;
41
+ const delay = options.mockDelay ?? 500;
42
+ const timeout = setTimeout(
43
+ () => savedHandler.current(options.mockData),
44
+ delay
45
+ );
46
+ return () => clearTimeout(timeout);
47
+ }
48
+ const eventListener = (event) => {
49
+ const { action: eventAction, data } = event.data;
50
+ if (eventAction === action) savedHandler.current(data);
51
+ };
52
+ window.addEventListener("message", eventListener);
53
+ return () => window.removeEventListener("message", eventListener);
54
+ }, [action, options == null ? void 0 : options.mockData, options == null ? void 0 : options.mockDelay]);
55
+ }
56
+ async function fetchNui(eventName, data, options) {
57
+ if (isEnvBrowser()) {
58
+ if ((options == null ? void 0 : options.mockData) === void 0) return Promise.resolve(null);
59
+ const delay = options.mockDelay ?? 500;
60
+ await new Promise((resolve) => setTimeout(resolve, delay));
61
+ return options.mockData;
62
+ }
63
+ const response = await fetch(`https://${resourceName}/${eventName}`, {
64
+ method: "POST",
65
+ headers: {
66
+ "Content-Type": "application/json; charset=UTF-8"
67
+ },
68
+ body: JSON.stringify(data ?? {})
69
+ });
70
+ return response.json();
71
+ }
72
+ function useNuiCallback(eventName, callback, options) {
73
+ const [state, setState] = (0, import_react.useState)({
74
+ loading: false,
75
+ error: null
76
+ });
77
+ const callbackRef = (0, import_react.useRef)(callback);
78
+ (0, import_react.useEffect)(() => {
79
+ callbackRef.current = callback;
80
+ }, [callback]);
81
+ const fetch2 = (0, import_react.useCallback)(
82
+ async (data) => {
83
+ setState({ loading: true, error: null });
84
+ try {
85
+ const result = await fetchNui(eventName, data, options);
86
+ callbackRef.current(result);
87
+ setState({ loading: false, error: null });
88
+ return result;
89
+ } catch (err) {
90
+ const error = err instanceof Error ? err : new Error(String(err));
91
+ setState({ loading: false, error });
92
+ throw error;
93
+ }
94
+ },
95
+ [eventName, options]
96
+ );
97
+ return [fetch2, state];
98
+ }
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ fetchNui,
102
+ isEnvBrowser,
103
+ useNuiCallback,
104
+ useNuiEvent
105
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,78 @@
1
+ // src/index.ts
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ var resourceName = window.GetParentResourceName ? window.GetParentResourceName() : "nui-frame-app";
4
+ function isEnvBrowser() {
5
+ return !window.invokeNative;
6
+ }
7
+ function useNuiEvent(action, handler, options) {
8
+ const savedHandler = useRef(handler);
9
+ useEffect(() => {
10
+ savedHandler.current = handler;
11
+ }, [handler]);
12
+ useEffect(() => {
13
+ if (isEnvBrowser()) {
14
+ if ((options == null ? void 0 : options.mockData) === void 0) return;
15
+ const delay = options.mockDelay ?? 500;
16
+ const timeout = setTimeout(
17
+ () => savedHandler.current(options.mockData),
18
+ delay
19
+ );
20
+ return () => clearTimeout(timeout);
21
+ }
22
+ const eventListener = (event) => {
23
+ const { action: eventAction, data } = event.data;
24
+ if (eventAction === action) savedHandler.current(data);
25
+ };
26
+ window.addEventListener("message", eventListener);
27
+ return () => window.removeEventListener("message", eventListener);
28
+ }, [action, options == null ? void 0 : options.mockData, options == null ? void 0 : options.mockDelay]);
29
+ }
30
+ async function fetchNui(eventName, data, options) {
31
+ if (isEnvBrowser()) {
32
+ if ((options == null ? void 0 : options.mockData) === void 0) return Promise.resolve(null);
33
+ const delay = options.mockDelay ?? 500;
34
+ await new Promise((resolve) => setTimeout(resolve, delay));
35
+ return options.mockData;
36
+ }
37
+ const response = await fetch(`https://${resourceName}/${eventName}`, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json; charset=UTF-8"
41
+ },
42
+ body: JSON.stringify(data ?? {})
43
+ });
44
+ return response.json();
45
+ }
46
+ function useNuiCallback(eventName, callback, options) {
47
+ const [state, setState] = useState({
48
+ loading: false,
49
+ error: null
50
+ });
51
+ const callbackRef = useRef(callback);
52
+ useEffect(() => {
53
+ callbackRef.current = callback;
54
+ }, [callback]);
55
+ const fetch2 = useCallback(
56
+ async (data) => {
57
+ setState({ loading: true, error: null });
58
+ try {
59
+ const result = await fetchNui(eventName, data, options);
60
+ callbackRef.current(result);
61
+ setState({ loading: false, error: null });
62
+ return result;
63
+ } catch (err) {
64
+ const error = err instanceof Error ? err : new Error(String(err));
65
+ setState({ loading: false, error });
66
+ throw error;
67
+ }
68
+ },
69
+ [eventName, options]
70
+ );
71
+ return [fetch2, state];
72
+ }
73
+ export {
74
+ fetchNui,
75
+ isEnvBrowser,
76
+ useNuiCallback,
77
+ useNuiEvent
78
+ };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "fivem-nui-react",
3
+ "version": "1.0.0",
4
+ "description": "React hooks and utilities for FiveM NUI development",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format cjs,esm --dts",
20
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
21
+ },
22
+ "keywords": [
23
+ "fivem",
24
+ "nui",
25
+ "react",
26
+ "hooks",
27
+ "cfx"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "type": "commonjs",
32
+ "peerDependencies": {
33
+ "react": ">=19.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^19.2.8",
37
+ "@types/react-dom": "^19.2.3",
38
+ "react": "^19.2.3",
39
+ "react-dom": "^19.2.3",
40
+ "tsup": "^8.5.1",
41
+ "typescript": "^5.9.3"
42
+ }
43
+ }