@fivem-nui/svelte 0.0.0-stage → 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.
Files changed (222) hide show
  1. package/README.md +284 -2
  2. package/dist/actions/clickOutside/clickOutside.d.ts +24 -0
  3. package/dist/actions/clickOutside/clickOutside.d.ts.map +1 -0
  4. package/dist/actions/clickOutside/clickOutside.js +62 -0
  5. package/dist/actions/clickOutside/clickOutside.js.map +1 -0
  6. package/dist/actions/clickOutside/handler.d.ts +11 -0
  7. package/dist/actions/clickOutside/handler.d.ts.map +1 -0
  8. package/dist/actions/clickOutside/handler.js +45 -0
  9. package/dist/actions/clickOutside/handler.js.map +1 -0
  10. package/dist/actions/clickOutside/index.d.ts +4 -0
  11. package/dist/actions/clickOutside/index.d.ts.map +1 -0
  12. package/dist/actions/clickOutside/index.js +4 -0
  13. package/dist/actions/clickOutside/index.js.map +1 -0
  14. package/dist/actions/clickOutside/types.d.ts +36 -0
  15. package/dist/actions/clickOutside/types.d.ts.map +1 -0
  16. package/dist/actions/clickOutside/types.js +6 -0
  17. package/dist/actions/clickOutside/types.js.map +1 -0
  18. package/dist/actions/clickOutside.d.ts +63 -0
  19. package/dist/actions/clickOutside.d.ts.map +1 -0
  20. package/dist/actions/clickOutside.js +106 -0
  21. package/dist/actions/clickOutside.js.map +1 -0
  22. package/dist/actions/escape/escape.d.ts +26 -0
  23. package/dist/actions/escape/escape.d.ts.map +1 -0
  24. package/dist/actions/escape/escape.js +74 -0
  25. package/dist/actions/escape/escape.js.map +1 -0
  26. package/dist/actions/escape/handler.d.ts +11 -0
  27. package/dist/actions/escape/handler.d.ts.map +1 -0
  28. package/dist/actions/escape/handler.js +50 -0
  29. package/dist/actions/escape/handler.js.map +1 -0
  30. package/dist/actions/escape/index.d.ts +4 -0
  31. package/dist/actions/escape/index.d.ts.map +1 -0
  32. package/dist/actions/escape/index.js +4 -0
  33. package/dist/actions/escape/index.js.map +1 -0
  34. package/dist/actions/escape/types.d.ts +70 -0
  35. package/dist/actions/escape/types.d.ts.map +1 -0
  36. package/dist/actions/escape/types.js +12 -0
  37. package/dist/actions/escape/types.js.map +1 -0
  38. package/dist/actions/escape.d.ts +99 -0
  39. package/dist/actions/escape.d.ts.map +1 -0
  40. package/dist/actions/escape.js +128 -0
  41. package/dist/actions/escape.js.map +1 -0
  42. package/dist/actions/focusTrap/focusTrap.d.ts +19 -0
  43. package/dist/actions/focusTrap/focusTrap.d.ts.map +1 -0
  44. package/dist/actions/focusTrap/focusTrap.js +198 -0
  45. package/dist/actions/focusTrap/focusTrap.js.map +1 -0
  46. package/dist/actions/focusTrap/focusables.d.ts +39 -0
  47. package/dist/actions/focusTrap/focusables.d.ts.map +1 -0
  48. package/dist/actions/focusTrap/focusables.js +142 -0
  49. package/dist/actions/focusTrap/focusables.js.map +1 -0
  50. package/dist/actions/focusTrap/index.d.ts +5 -0
  51. package/dist/actions/focusTrap/index.d.ts.map +1 -0
  52. package/dist/actions/focusTrap/index.js +5 -0
  53. package/dist/actions/focusTrap/index.js.map +1 -0
  54. package/dist/actions/focusTrap/trapStack.d.ts +33 -0
  55. package/dist/actions/focusTrap/trapStack.d.ts.map +1 -0
  56. package/dist/actions/focusTrap/trapStack.js +84 -0
  57. package/dist/actions/focusTrap/trapStack.js.map +1 -0
  58. package/dist/actions/focusTrap/types.d.ts +50 -0
  59. package/dist/actions/focusTrap/types.d.ts.map +1 -0
  60. package/dist/actions/focusTrap/types.js +10 -0
  61. package/dist/actions/focusTrap/types.js.map +1 -0
  62. package/dist/actions/focusTrap.d.ts +24 -0
  63. package/dist/actions/focusTrap.d.ts.map +1 -0
  64. package/dist/actions/focusTrap.js +201 -0
  65. package/dist/actions/focusTrap.js.map +1 -0
  66. package/dist/actions/focusTrap.types.d.ts +50 -0
  67. package/dist/actions/focusTrap.types.d.ts.map +1 -0
  68. package/dist/actions/focusTrap.types.js +10 -0
  69. package/dist/actions/focusTrap.types.js.map +1 -0
  70. package/dist/actions/focusables.d.ts +39 -0
  71. package/dist/actions/focusables.d.ts.map +1 -0
  72. package/dist/actions/focusables.js +142 -0
  73. package/dist/actions/focusables.js.map +1 -0
  74. package/dist/actions/index.d.ts +5 -0
  75. package/dist/actions/index.d.ts.map +1 -0
  76. package/dist/actions/index.js +5 -0
  77. package/dist/actions/index.js.map +1 -0
  78. package/dist/actions/layer/index.d.ts +4 -0
  79. package/dist/actions/layer/index.d.ts.map +1 -0
  80. package/dist/actions/layer/index.js +4 -0
  81. package/dist/actions/layer/index.js.map +1 -0
  82. package/dist/actions/layer/layer.d.ts +28 -0
  83. package/dist/actions/layer/layer.d.ts.map +1 -0
  84. package/dist/actions/layer/layer.js +118 -0
  85. package/dist/actions/layer/layer.js.map +1 -0
  86. package/dist/actions/layer/layerStack.d.ts +10 -0
  87. package/dist/actions/layer/layerStack.d.ts.map +1 -0
  88. package/dist/actions/layer/layerStack.js +153 -0
  89. package/dist/actions/layer/layerStack.js.map +1 -0
  90. package/dist/actions/layer/types.d.ts +105 -0
  91. package/dist/actions/layer/types.d.ts.map +1 -0
  92. package/dist/actions/layer/types.js +14 -0
  93. package/dist/actions/layer/types.js.map +1 -0
  94. package/dist/actions/layer.d.ts +133 -0
  95. package/dist/actions/layer.d.ts.map +1 -0
  96. package/dist/actions/layer.js +269 -0
  97. package/dist/actions/layer.js.map +1 -0
  98. package/dist/actions/trapStack.d.ts +33 -0
  99. package/dist/actions/trapStack.d.ts.map +1 -0
  100. package/dist/actions/trapStack.js +84 -0
  101. package/dist/actions/trapStack.js.map +1 -0
  102. package/dist/client.d.ts +179 -0
  103. package/dist/client.d.ts.map +1 -0
  104. package/dist/client.js +176 -0
  105. package/dist/client.js.map +1 -0
  106. package/dist/context/index.d.ts +68 -0
  107. package/dist/context/index.d.ts.map +1 -0
  108. package/dist/context/index.js +112 -0
  109. package/dist/context/index.js.map +1 -0
  110. package/dist/index.d.ts +22 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +30 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/mock/index.d.ts +27 -0
  115. package/dist/mock/index.d.ts.map +1 -0
  116. package/dist/mock/index.js +137 -0
  117. package/dist/mock/index.js.map +1 -0
  118. package/dist/mock/interceptor.d.ts +19 -0
  119. package/dist/mock/interceptor.d.ts.map +1 -0
  120. package/dist/mock/interceptor.js +128 -0
  121. package/dist/mock/interceptor.js.map +1 -0
  122. package/dist/mock/types.d.ts +100 -0
  123. package/dist/mock/types.d.ts.map +1 -0
  124. package/dist/mock/types.js +27 -0
  125. package/dist/mock/types.js.map +1 -0
  126. package/dist/mock/url.d.ts +14 -0
  127. package/dist/mock/url.d.ts.map +1 -0
  128. package/dist/mock/url.js +38 -0
  129. package/dist/mock/url.js.map +1 -0
  130. package/dist/runes/clickOutside.svelte.d.ts +29 -0
  131. package/dist/runes/clickOutside.svelte.d.ts.map +1 -0
  132. package/dist/runes/clickOutside.svelte.js +42 -0
  133. package/dist/runes/clickOutside.svelte.js.map +1 -0
  134. package/dist/runes/escape.svelte.d.ts +34 -0
  135. package/dist/runes/escape.svelte.d.ts.map +1 -0
  136. package/dist/runes/escape.svelte.js +44 -0
  137. package/dist/runes/escape.svelte.js.map +1 -0
  138. package/dist/runes/focusTrap.svelte.d.ts +21 -0
  139. package/dist/runes/focusTrap.svelte.d.ts.map +1 -0
  140. package/dist/runes/focusTrap.svelte.js +37 -0
  141. package/dist/runes/focusTrap.svelte.js.map +1 -0
  142. package/dist/runes/index.svelte.d.ts +8 -0
  143. package/dist/runes/index.svelte.d.ts.map +1 -0
  144. package/dist/runes/index.svelte.js +8 -0
  145. package/dist/runes/index.svelte.js.map +1 -0
  146. package/dist/runes/layer.svelte.d.ts +36 -0
  147. package/dist/runes/layer.svelte.d.ts.map +1 -0
  148. package/dist/runes/layer.svelte.js +48 -0
  149. package/dist/runes/layer.svelte.js.map +1 -0
  150. package/dist/runes/query.svelte.d.ts +104 -0
  151. package/dist/runes/query.svelte.d.ts.map +1 -0
  152. package/dist/runes/query.svelte.js +179 -0
  153. package/dist/runes/query.svelte.js.map +1 -0
  154. package/dist/runes/state.svelte.d.ts +72 -0
  155. package/dist/runes/state.svelte.d.ts.map +1 -0
  156. package/dist/runes/state.svelte.js +98 -0
  157. package/dist/runes/state.svelte.js.map +1 -0
  158. package/dist/runes/window.svelte.d.ts +120 -0
  159. package/dist/runes/window.svelte.d.ts.map +1 -0
  160. package/dist/runes/window.svelte.js +196 -0
  161. package/dist/runes/window.svelte.js.map +1 -0
  162. package/dist/types/index.d.ts +2 -0
  163. package/dist/types/index.d.ts.map +1 -0
  164. package/dist/types/index.js +3 -0
  165. package/dist/types/index.js.map +1 -0
  166. package/dist/types/nui.d.ts +34 -0
  167. package/dist/types/nui.d.ts.map +1 -0
  168. package/dist/types/nui.js +17 -0
  169. package/dist/types/nui.js.map +1 -0
  170. package/dist/utils/env.d.ts +21 -0
  171. package/dist/utils/env.d.ts.map +1 -0
  172. package/dist/utils/env.js +36 -0
  173. package/dist/utils/env.js.map +1 -0
  174. package/dist/utils/error.d.ts +11 -0
  175. package/dist/utils/error.d.ts.map +1 -0
  176. package/dist/utils/error.js +30 -0
  177. package/dist/utils/error.js.map +1 -0
  178. package/dist/utils/index.d.ts +3 -0
  179. package/dist/utils/index.d.ts.map +1 -0
  180. package/dist/utils/index.js +3 -0
  181. package/dist/utils/index.js.map +1 -0
  182. package/dist/utils/keyboard.d.ts +127 -0
  183. package/dist/utils/keyboard.d.ts.map +1 -0
  184. package/dist/utils/keyboard.js +152 -0
  185. package/dist/utils/keyboard.js.map +1 -0
  186. package/package.json +76 -4
  187. package/src/actions/clickOutside/clickOutside.ts +78 -0
  188. package/src/actions/clickOutside/handler.ts +49 -0
  189. package/src/actions/clickOutside/index.ts +11 -0
  190. package/src/actions/clickOutside/types.ts +54 -0
  191. package/src/actions/escape/escape.ts +90 -0
  192. package/src/actions/escape/handler.ts +52 -0
  193. package/src/actions/escape/index.ts +11 -0
  194. package/src/actions/escape/types.ts +88 -0
  195. package/src/actions/focusTrap/focusTrap.ts +228 -0
  196. package/src/actions/focusTrap/focusables.ts +155 -0
  197. package/src/actions/focusTrap/index.ts +22 -0
  198. package/src/actions/focusTrap/trapStack.ts +109 -0
  199. package/src/actions/focusTrap/types.ts +64 -0
  200. package/src/actions/index.ts +35 -0
  201. package/src/actions/layer/index.ts +13 -0
  202. package/src/actions/layer/layer.ts +140 -0
  203. package/src/actions/layer/layerStack.ts +169 -0
  204. package/src/actions/layer/types.ts +132 -0
  205. package/src/client.ts +323 -0
  206. package/src/context/index.ts +127 -0
  207. package/src/index.ts +53 -0
  208. package/src/mock/index.ts +176 -0
  209. package/src/mock/interceptor.ts +177 -0
  210. package/src/mock/types.ts +125 -0
  211. package/src/mock/url.ts +37 -0
  212. package/src/runes/clickOutside.svelte.ts +53 -0
  213. package/src/runes/escape.svelte.ts +71 -0
  214. package/src/runes/focusTrap.svelte.ts +56 -0
  215. package/src/runes/index.svelte.ts +38 -0
  216. package/src/runes/layer.svelte.ts +74 -0
  217. package/src/runes/query.svelte.ts +313 -0
  218. package/src/runes/state.svelte.ts +175 -0
  219. package/src/runes/window.svelte.ts +308 -0
  220. package/src/utils/env.ts +36 -0
  221. package/src/utils/index.ts +2 -0
  222. package/src/utils/keyboard.ts +244 -0
package/README.md CHANGED
@@ -1,3 +1,285 @@
1
- # Temporary Holding Version
1
+ # @fivem-nui/svelte
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Svelte adapter and reactive toolkit for FiveM NUI communication, engineered for **Svelte 5** Runes (`$state`, `$derived`, `$effect`).
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/rian-be/FiveM.Nui/blob/main/LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.12.0-brightgreen.svg)](#requirements)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-7.x-blue.svg)](#requirements)
8
+ [![Svelte](https://img.shields.io/badge/Svelte-5.x-orange.svg)](https://svelte.dev)
9
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#contributing)
10
+
11
+ `@fivem-nui/svelte` provides seamless, reactive integration between client C# scripts (.NET 10) and Svelte 5 NUI panels. It wraps `@fivem-nui/core` with native Svelte 5 Runes, DOM actions (`use:action`), keyboard shortcuts, focus trapping, and browser mocking for rapid local development.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @fivem-nui/svelte @fivem-nui/core svelte
19
+ ```
20
+
21
+ > **Note:** `@fivem-nui/core` (`>=1.0.0`) and `svelte` (`>=5.0.0`) are peer dependencies.
22
+
23
+ ---
24
+
25
+ ## Package Entry Points
26
+
27
+ The package exposes modular subpaths for tree-shaking and isolation:
28
+
29
+ | Import Path | Description | Contents |
30
+ |---|---|---|
31
+ | `@fivem-nui/svelte` | Main library | Runes (`useNuiState`, `useNuiQuery`, `useNuiWindow`), client, context, error re-exports |
32
+ | `@fivem-nui/svelte/actions` | DOM actions | `nuiEscapeAction`, `nuiFocusTrap`, `nuiClickOutside`, `nuiLayer` |
33
+ | `@fivem-nui/svelte/mock` | Browser mocking | `setupNuiMock`, mock transport and window emission helpers |
34
+
35
+ ```ts
36
+ import { nui, useNuiState, useNuiQuery } from '@fivem-nui/svelte';
37
+ import { nuiFocusTrap, nuiClickOutside } from '@fivem-nui/svelte/actions';
38
+ import { setupNuiMock } from '@fivem-nui/svelte/mock';
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Runes API
44
+
45
+ ### 1. `useNuiState` (Reactive C# → UI Events)
46
+
47
+ Synchronizes incoming NUI events with a reactive `$state` rune, supporting functional updates:
48
+
49
+ ```svelte
50
+ <script lang="ts">
51
+ import { useNuiState } from '@fivem-nui/svelte';
52
+
53
+ interface PlayerStats {
54
+ health: number;
55
+ armor: number;
56
+ }
57
+
58
+ // Automatically listens to 'player:stats' and unregisters on component unmount
59
+ const stats = useNuiState<PlayerStats>('player:stats', { health: 100, armor: 0 });
60
+
61
+ function heal(amount: number) {
62
+ stats.update(prev => ({ ...prev, health: Math.min(100, prev.health + amount) }));
63
+ }
64
+ </script>
65
+
66
+ <div class="hud">
67
+ <p>Health: {stats.value.health}%</p>
68
+ <p>Armor: {stats.value.armor}%</p>
69
+ {#if stats.updatedAt}
70
+ <small>Last updated: {new Date(stats.updatedAt).toLocaleTimeString()}</small>
71
+ {/if}
72
+ </div>
73
+ ```
74
+
75
+ ---
76
+
77
+ ### 2. `useNuiQuery` (Reactive UI → C# Request/Response)
78
+
79
+ Manages outgoing `nui.request` calls with automated reactive states (`loading`, `error`, `data`), retries, and cancellation:
80
+
81
+ ```svelte
82
+ <script lang="ts">
83
+ import { useNuiQuery } from '@fivem-nui/svelte';
84
+
85
+ interface BuyRequest { itemId: string; quantity: number; }
86
+ interface BuyResponse { success: boolean; balance: number; }
87
+
88
+ const buy = useNuiQuery<BuyRequest, BuyResponse>('shop:buy');
89
+ </script>
90
+
91
+ <button
92
+ onclick={() => buy.execute({ itemId: 'water', quantity: 2 })}
93
+ disabled={buy.loading}
94
+ >
95
+ {buy.loading ? 'Purchasing...' : 'Buy Water'}
96
+ </button>
97
+
98
+ <button onclick={() => buy.refetch()} disabled={!buy.called || buy.loading}>
99
+ Repeat Purchase
100
+ </button>
101
+
102
+ {#if buy.error}
103
+ <p class="error">{buy.error.message}</p>
104
+ {/if}
105
+
106
+ {#if buy.data}
107
+ <p>Remaining Balance: ${buy.data.balance}</p>
108
+ {/if}
109
+ ```
110
+
111
+ ---
112
+
113
+ ### 3. `useNuiWindow` (Window Visibility & Lifecycle)
114
+
115
+ Synchronizes window visibility with `onWindow` events emitted from C# (`open`, `close`, `focus`, `unfocus`) and handles the `Escape` key by default:
116
+
117
+ ```svelte
118
+ <script lang="ts">
119
+ import { useNuiWindow } from '@fivem-nui/svelte';
120
+
121
+ // closeOnEscape is enabled by default (true)
122
+ const panel = useNuiWindow('inventory', {
123
+ onClose: () => console.log('Window closed')
124
+ });
125
+ </script>
126
+
127
+ {#if panel.visible}
128
+ <div class="panel">
129
+ <h2>Inventory</h2>
130
+ <button onclick={() => panel.close()}>Close (or press ESC)</button>
131
+ </div>
132
+ {/if}
133
+ ```
134
+
135
+ ---
136
+
137
+ ## UI Utilities, Keyboard & Svelte Actions
138
+
139
+ The package provides two integration paths: **Svelte Actions (`use:action`)** for declarative DOM binding and **Runes Composables** for programmatic control in `<script>`:
140
+
141
+ | Feature | Svelte Action (`use:action`) | Runes Composable | Use Case |
142
+ |---|---|---|---|
143
+ | **Escape Key** | `nuiEscapeAction` | `useEscape()` / `useNuiEscape()` | Close modals or panels on ESC |
144
+ | **Focus Trap** | `nuiFocusTrap` | `useFocusTrap()` | Prevent keyboard Tab key from escaping modal |
145
+ | **Click Outside** | `nuiClickOutside` | `useClickOutside()` | Dismiss dropdowns and context menus |
146
+ | **Layer Stack (Z-Index)** | `nuiLayer` | `useLayer()` | Manage stacking order of nested modals |
147
+ | **Keyboard Shortcuts** | — | `useNuiKey()` | Listen for custom hotkeys (e.g., F1, Enter) |
148
+
149
+ ### 1. Keyboard Shortcuts (`useNuiEscape` & `useNuiKey`)
150
+
151
+ ```svelte
152
+ <script lang="ts">
153
+ import { useNuiEscape, useNuiKey, nui } from '@fivem-nui/svelte';
154
+
155
+ // Cleaned up automatically on component unmount
156
+ useNuiEscape(() => nui.notify('close'));
157
+
158
+ // Listen to arbitrary keys with optional condition:
159
+ useNuiKey('F1', () => console.log('Help toggled'), { enabled: () => true });
160
+ </script>
161
+ ```
162
+
163
+ Or declaratively in template:
164
+ ```svelte
165
+ <div use:nuiEscapeAction={() => panel.close()}>...</div>
166
+ ```
167
+
168
+ ### 2. Focus Trap (`nuiFocusTrap` / `useFocusTrap`)
169
+
170
+ Keeps keyboard Tab focus trapped inside the active dialog:
171
+
172
+ ```svelte
173
+ <script lang="ts">
174
+ import { nuiFocusTrap } from '@fivem-nui/svelte/actions';
175
+ </script>
176
+
177
+ <div class="modal-dialog" use:nuiFocusTrap>
178
+ <input type="text" placeholder="Character Name..." />
179
+ <button>Save</button>
180
+ </div>
181
+ ```
182
+
183
+ ### 3. Click Outside (`nuiClickOutside` / `useClickOutside`)
184
+
185
+ Automatically closes popups or dropdowns when clicking outside their element:
186
+
187
+ ```svelte
188
+ <script lang="ts">
189
+ import { nuiClickOutside } from '@fivem-nui/svelte/actions';
190
+
191
+ let open = $state(true);
192
+ </script>
193
+
194
+ {#if open}
195
+ <div class="dropdown" use:nuiClickOutside={() => (open = false)}>
196
+ Menu Content...
197
+ </div>
198
+ {/if}
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Environment Detection
204
+
205
+ Detect whether the UI is running inside GTA V / FiveM CEF or in a standard browser:
206
+
207
+ ```typescript
208
+ import { isNui, isBrowser, getResourceName } from '@fivem-nui/svelte';
209
+
210
+ if (isBrowser()) {
211
+ console.log('Running locally in browser (outside FiveM CEF)');
212
+ }
213
+
214
+ console.log('Resource Name:', getResourceName());
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Browser Mocking (`setupNuiMock`)
220
+
221
+ Test and style your UI panels in Google Chrome (`npm run dev`) with instant Vite HMR without launching FiveM:
222
+
223
+ ```typescript
224
+ import { isBrowser, setupNuiMock } from '@fivem-nui/svelte/mock';
225
+
226
+ if (isBrowser()) {
227
+ setupNuiMock({
228
+ requests: {
229
+ 'shop:buy': async (payload) => {
230
+ return { success: true, balance: 4500, bought: payload.itemId };
231
+ }
232
+ },
233
+ callbacks: {
234
+ 'close': () => console.log('Panel closed by UI'),
235
+ 'ready': () => console.log('Panel ready acknowledged')
236
+ },
237
+ onSend: {
238
+ 'comps:log': (toast) => console.log('Toast sent from UI:', toast)
239
+ }
240
+ });
241
+
242
+ // You can also simulate incoming C# traffic from browser DevTools:
243
+ // window.__nuiMock.emitEvent('player:stats', { health: 80, armor: 50 });
244
+ // window.__nuiMock.emitWindow('open', 'inventory');
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Svelte Context & Custom Clients
251
+
252
+ When you need an isolated NUI client passed down the component hierarchy:
253
+
254
+ ```svelte
255
+ <script lang="ts">
256
+ import { setNuiClient, SvelteNuiClient } from '@fivem-nui/svelte';
257
+
258
+ const customClient = new SvelteNuiClient({ resource: 'my_resource' });
259
+ setNuiClient(customClient);
260
+ </script>
261
+ ```
262
+
263
+ In any descendant component:
264
+ ```svelte
265
+ <script lang="ts">
266
+ import { useNuiClient } from '@fivem-nui/svelte';
267
+
268
+ const client = useNuiClient();
269
+ </script>
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Re-exports & Error Handling
275
+
276
+ `@fivem-nui/svelte` directly re-exports the entire `@fivem-nui/error` toolkit and core contract types:
277
+
278
+ - **Error handling:** `installGlobalErrorHandlers`, `withRetry`, `globalErrorHandler`, `NuiErrorCategory`, `NuiErrorSeverity`, `captureRenderError`, `isAbortError`.
279
+ - **Core contracts:** `NuiEventMap`, `NuiEventKey`, `NuiEventRequest`, `NuiEventResponse`, `NuiMessage`, `NuiError`.
280
+
281
+ ---
282
+
283
+ ## License
284
+
285
+ [MIT](../../../LICENSE) © 2026 Rian.be
@@ -0,0 +1,24 @@
1
+ import type { Action } from 'svelte/action';
2
+ import { type NuiClickOutsideInput } from './types';
3
+ /**
4
+ * Svelte Action for reliable outside click detection in FiveM CEF.
5
+ *
6
+ * Uses `event.composedPath()` to eliminate the detached DOM node bug when
7
+ * inner elements mutate during click events.
8
+ *
9
+ * @remarks
10
+ * **Multiple Overlays in CEF**:
11
+ * Because `pointerdown` is used with `capture: true`, clicking into another open NUI panel
12
+ * will trigger an outside click unless that other panel is explicitly included in `ignore`.
13
+ *
14
+ * @param node - The DOM element to monitor for outside clicks.
15
+ * @param parameter - Callback function or configuration options object.
16
+ *
17
+ * @example
18
+ * ```svelte
19
+ * <div use:nuiClickOutside={() => (isOpen = false)}>...</div>
20
+ * <div use:nuiClickOutside={{ onClickOutside: close, ignore: [triggerEl, '.header-btn'] }}>...</div>
21
+ * ```
22
+ */
23
+ export declare const nuiClickOutside: Action<HTMLElement, NuiClickOutsideInput>;
24
+ //# sourceMappingURL=clickOutside.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickOutside.d.ts","sourceRoot":"","sources":["../../../src/actions/clickOutside/clickOutside.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAkDrE,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { toClickOutsideOptions } from './types';
2
+ import { createClickOutsideHandler } from './handler';
3
+ /**
4
+ * Svelte Action for reliable outside click detection in FiveM CEF.
5
+ *
6
+ * Uses `event.composedPath()` to eliminate the detached DOM node bug when
7
+ * inner elements mutate during click events.
8
+ *
9
+ * @remarks
10
+ * **Multiple Overlays in CEF**:
11
+ * Because `pointerdown` is used with `capture: true`, clicking into another open NUI panel
12
+ * will trigger an outside click unless that other panel is explicitly included in `ignore`.
13
+ *
14
+ * @param node - The DOM element to monitor for outside clicks.
15
+ * @param parameter - Callback function or configuration options object.
16
+ *
17
+ * @example
18
+ * ```svelte
19
+ * <div use:nuiClickOutside={() => (isOpen = false)}>...</div>
20
+ * <div use:nuiClickOutside={{ onClickOutside: close, ignore: [triggerEl, '.header-btn'] }}>...</div>
21
+ * ```
22
+ */
23
+ export const nuiClickOutside = (node, parameter) => {
24
+ let currentParam = parameter;
25
+ let controller = null;
26
+ const handler = createClickOutsideHandler(() => node, () => toClickOutsideOptions(currentParam));
27
+ function getCapture() {
28
+ const opts = toClickOutsideOptions(currentParam);
29
+ return opts?.capture ?? true;
30
+ }
31
+ function setup() {
32
+ teardown();
33
+ controller = new AbortController();
34
+ document.addEventListener('pointerdown', handler, {
35
+ capture: getCapture(),
36
+ signal: controller.signal
37
+ });
38
+ }
39
+ function teardown() {
40
+ if (controller) {
41
+ controller.abort();
42
+ controller = null;
43
+ }
44
+ }
45
+ setup();
46
+ return {
47
+ update(newParam) {
48
+ const prevCapture = getCapture();
49
+ currentParam = newParam;
50
+ // Only changes to `capture` require re-binding the document listener.
51
+ // All other options (`enabled`, `onClickOutside`, `ignore`)
52
+ // are read lazily on each pointerdown event via getOptions().
53
+ if (getCapture() !== prevCapture) {
54
+ setup();
55
+ }
56
+ },
57
+ destroy() {
58
+ teardown();
59
+ }
60
+ };
61
+ };
62
+ //# sourceMappingURL=clickOutside.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickOutside.js","sourceRoot":"","sources":["../../../src/actions/clickOutside/clickOutside.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,qBAAqB,EACtB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,eAAe,GAA8C,CACxE,IAAI,EACJ,SAAS,EACT,EAAE;IACF,IAAI,YAAY,GAAG,SAAS,CAAC;IAC7B,IAAI,UAAU,GAA2B,IAAI,CAAC;IAE9C,MAAM,OAAO,GAAG,yBAAyB,CACvC,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAC1C,CAAC;IAEF,SAAS,UAAU;QACjB,MAAM,IAAI,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;QACjD,OAAO,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC;IAC/B,CAAC;IAED,SAAS,KAAK;QACZ,QAAQ,EAAE,CAAC;QACX,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACnC,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE;YAChD,OAAO,EAAE,UAAU,EAAE;YACrB,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,SAAS,QAAQ;QACf,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,KAAK,EAAE,CAAC;IAER,OAAO;QACL,MAAM,CAAC,QAAQ;YACb,MAAM,WAAW,GAAG,UAAU,EAAE,CAAC;YACjC,YAAY,GAAG,QAAQ,CAAC;YACxB,sEAAsE;YACtE,4DAA4D;YAC5D,8DAA8D;YAC9D,IAAI,UAAU,EAAE,KAAK,WAAW,EAAE,CAAC;gBACjC,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QACD,OAAO;YACL,QAAQ,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ClickOutsideTarget, NuiClickOutsideParameter } from './types';
2
+ /**
3
+ * Resolves a DOM Element from an Element reference, CSS selector string, or getter function.
4
+ */
5
+ export declare function resolveElement(target: ClickOutsideTarget): Element | null;
6
+ /**
7
+ * Creates a reusable pointerdown event handler for outside click detection.
8
+ * Shared between Svelte action and composable to eliminate duplication.
9
+ */
10
+ export declare function createClickOutsideHandler(getNode: () => Element | null | undefined, getOptions: () => NuiClickOutsideParameter | undefined): (event: PointerEvent) => void;
11
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/actions/clickOutside/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAE5E;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,GAAG,IAAI,CAQzE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,GAAG,SAAS,EACzC,UAAU,EAAE,MAAM,wBAAwB,GAAG,SAAS,WAEvC,YAAY,UAyB5B"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Resolves a DOM Element from an Element reference, CSS selector string, or getter function.
3
+ */
4
+ export function resolveElement(target) {
5
+ if (typeof target === 'string') {
6
+ return document.querySelector(target);
7
+ }
8
+ if (typeof target === 'function') {
9
+ return target() ?? null;
10
+ }
11
+ return target ?? null;
12
+ }
13
+ /**
14
+ * Creates a reusable pointerdown event handler for outside click detection.
15
+ * Shared between Svelte action and composable to eliminate duplication.
16
+ */
17
+ export function createClickOutsideHandler(getNode, getOptions) {
18
+ return (event) => {
19
+ const node = getNode();
20
+ const opts = getOptions();
21
+ if (!node?.isConnected || !opts)
22
+ return;
23
+ const enabled = typeof opts.enabled === 'function' ? opts.enabled() : opts.enabled ?? true;
24
+ if (!enabled || event.button !== 0)
25
+ return;
26
+ const path = event.composedPath();
27
+ if (path.includes(node))
28
+ return;
29
+ for (const item of opts.ignore ?? []) {
30
+ const el = resolveElement(item);
31
+ if (el && path.includes(el))
32
+ return;
33
+ }
34
+ const callback = opts.onClickOutside ?? opts.callback;
35
+ if (callback) {
36
+ try {
37
+ callback(event);
38
+ }
39
+ catch (err) {
40
+ console.error('[NuiClickOutside] Error in onClickOutside callback:', err);
41
+ }
42
+ }
43
+ };
44
+ }
45
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/actions/clickOutside/handler.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAA0B;IACvD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO,MAAM,EAAE,IAAI,IAAI,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAyC,EACzC,UAAsD;IAEtD,OAAO,CAAC,KAAmB,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,IAAI;YAAE,OAAO;QAExC,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;QAC3F,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE3C,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO;QAEhC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAAE,OAAO;QACtC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,CAAC;QACtD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC;gBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { nuiClickOutside } from './clickOutside';
2
+ export { type ClickOutsideTarget, type NuiClickOutsideParameter, type NuiClickOutsideInput, toClickOutsideOptions } from './types';
3
+ export { resolveElement, createClickOutsideHandler } from './handler';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/actions/clickOutside/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,cAAc,EACd,yBAAyB,EAC1B,MAAM,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { nuiClickOutside } from './clickOutside';
2
+ export { toClickOutsideOptions } from './types';
3
+ export { resolveElement, createClickOutsideHandler } from './handler';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/actions/clickOutside/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAIL,qBAAqB,EACtB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,cAAc,EACd,yBAAyB,EAC1B,MAAM,WAAW,CAAC"}
@@ -0,0 +1,36 @@
1
+ export type ClickOutsideTarget = Element | string | null | undefined | (() => Element | null | undefined);
2
+ export interface NuiClickOutsideParameter {
3
+ /**
4
+ * Callback invoked when a click or touch occurs outside the target node.
5
+ */
6
+ onClickOutside?: (event: PointerEvent) => void;
7
+ /**
8
+ * @deprecated Use `onClickOutside` instead.
9
+ */
10
+ callback?: (event: PointerEvent) => void;
11
+ /**
12
+ * Whether the outside click detector is active.
13
+ * Can be a static boolean or a reactive getter `() => boolean`.
14
+ * @defaultValue true
15
+ */
16
+ enabled?: boolean | (() => boolean);
17
+ /**
18
+ * Elements, selectors, or getters to exclude from triggering outside click.
19
+ *
20
+ * @remarks
21
+ * **Trigger / Toggle Buttons**:
22
+ * Because `capture: true` listens on the capturing phase (`pointerdown` fires before `click`),
23
+ * clicking a toggle/trigger button without adding it to `ignore` will cause an immediate
24
+ * flicker (the outside click closes the popover during `pointerdown`, and the button's
25
+ * subsequent `click` immediately re-opens it). Always pass your toggle button in `ignore`.
26
+ */
27
+ ignore?: ClickOutsideTarget[];
28
+ /**
29
+ * Listen during capture phase to intercept before bubbling mutations.
30
+ * @defaultValue true
31
+ */
32
+ capture?: boolean;
33
+ }
34
+ export type NuiClickOutsideInput = ((event: PointerEvent) => void) | NuiClickOutsideParameter;
35
+ export declare function toClickOutsideOptions(param: NuiClickOutsideInput | undefined): NuiClickOutsideParameter | undefined;
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/actions/clickOutside/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,MAAM,GACN,IAAI,GACJ,SAAS,GACT,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEvC,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAE/C;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAEzC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IAEpC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAE9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,oBAAoB,GAC5B,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAC/B,wBAAwB,CAAC;AAE7B,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,oBAAoB,GAAG,SAAS,GACtC,wBAAwB,GAAG,SAAS,CAGtC"}
@@ -0,0 +1,6 @@
1
+ export function toClickOutsideOptions(param) {
2
+ if (!param)
3
+ return undefined;
4
+ return typeof param === 'function' ? { onClickOutside: param } : param;
5
+ }
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/actions/clickOutside/types.ts"],"names":[],"mappings":"AAgDA,MAAM,UAAU,qBAAqB,CACnC,KAAuC;IAEvC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACzE,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { Action } from 'svelte/action';
2
+ export type ClickOutsideTarget = Element | string | null | undefined | (() => Element | null | undefined);
3
+ export interface NuiClickOutsideParameter {
4
+ /**
5
+ * Callback invoked when a click or touch occurs outside the target node.
6
+ */
7
+ onClickOutside?: (event: PointerEvent) => void;
8
+ /**
9
+ * @deprecated Use `onClickOutside` instead.
10
+ */
11
+ callback?: (event: PointerEvent) => void;
12
+ /**
13
+ * Whether the outside click detector is active.
14
+ * Can be a static boolean or a reactive getter `() => boolean`.
15
+ * @defaultValue true
16
+ */
17
+ enabled?: boolean | (() => boolean);
18
+ /**
19
+ * Elements, selectors, or getters to exclude from triggering outside click.
20
+ *
21
+ * @remarks
22
+ * **Trigger / Toggle Buttons**:
23
+ * Because `capture: true` listens on the capturing phase (`pointerdown` fires before `click`),
24
+ * clicking a toggle/trigger button without adding it to `ignore` will cause an immediate
25
+ * flicker (the outside click closes the popover during `pointerdown`, and the button's
26
+ * subsequent `click` immediately re-opens it). Always pass your toggle button in `ignore`.
27
+ */
28
+ ignore?: ClickOutsideTarget[];
29
+ /**
30
+ * Listen during capture phase to intercept before bubbling mutations.
31
+ * @defaultValue true
32
+ */
33
+ capture?: boolean;
34
+ }
35
+ export type NuiClickOutsideInput = ((event: PointerEvent) => void) | NuiClickOutsideParameter;
36
+ export declare function resolveElement(target: ClickOutsideTarget): Element | null;
37
+ /**
38
+ * Creates a reusable pointerdown event handler for outside click detection.
39
+ * Shared between Svelte action and composable to eliminate duplication.
40
+ */
41
+ export declare function createClickOutsideHandler(getNode: () => Element | null | undefined, getOptions: () => NuiClickOutsideParameter | undefined): (event: PointerEvent) => void;
42
+ /**
43
+ * Svelte Action for reliable outside click detection in FiveM CEF.
44
+ *
45
+ * Uses `event.composedPath()` to eliminate the detached DOM node bug when
46
+ * inner elements mutate during click events.
47
+ *
48
+ * @remarks
49
+ * **Multiple Overlays in CEF**:
50
+ * Because `pointerdown` is used with `capture: true`, clicking into another open NUI panel
51
+ * will trigger an outside click unless that other panel is explicitly included in `ignore`.
52
+ *
53
+ * @param node - The DOM element to monitor for outside clicks.
54
+ * @param parameter - Callback function or configuration options object.
55
+ *
56
+ * @example
57
+ * ```svelte
58
+ * <div use:nuiClickOutside={() => (isOpen = false)}>...</div>
59
+ * <div use:nuiClickOutside={{ onClickOutside: close, ignore: [triggerEl, '.header-btn'] }}>...</div>
60
+ * ```
61
+ */
62
+ export declare const nuiClickOutside: Action<HTMLElement, NuiClickOutsideInput>;
63
+ //# sourceMappingURL=clickOutside.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickOutside.d.ts","sourceRoot":"","sources":["../../src/actions/clickOutside.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,MAAM,GACN,IAAI,GACJ,SAAS,GACT,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEvC,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAE/C;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAEzC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IAEpC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAE9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,oBAAoB,GAC5B,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAC/B,wBAAwB,CAAC;AAE7B,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,GAAG,IAAI,CAQzE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,GAAG,SAAS,EACzC,UAAU,EAAE,MAAM,wBAAwB,GAAG,SAAS,WAEvC,YAAY,UAyB5B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAuDrE,CAAC"}