@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
@@ -0,0 +1,118 @@
1
+ import { nuiFocusTrap } from '../focusTrap';
2
+ import { toLayerOptions } from './types';
3
+ import { pushLayer, removeLayer, getTopLayer, nextLayerId } from './layerStack';
4
+ /**
5
+ * Managing an overlay layer in FiveM NUI.
6
+ *
7
+ * Coordinates:
8
+ * - **Escape key**: Traverses the layer stack top-to-bottom. The topmost active layer that handles Escape
9
+ * receives the event and dismisses. If the topmost layer disables Escape (`onEscape: false`),
10
+ * lower layers can handle it.
11
+ * - **Outside click**: Evaluates strictly the topmost active layer. If the topmost layer disables outside
12
+ * clicks (`onClickOutside: false`), clicks outside are blocked and do NOT fall through to underlying layers,
13
+ * preserving modal barrier isolation.
14
+ * - **Focus trap**: Integrates `nuiFocusTrap` synchronized with layer priority so focus containment and Tab
15
+ * navigation are enforced by the topmost layer even when layers have varying priorities.
16
+ * - **Portal integration**: `allowOutside` allows portaled children (selects, datepickers, tooltips)
17
+ * without triggering outside clicks or breaking focus containment.
18
+ *
19
+ * @param node - The DOM element attaching the layer action.
20
+ * @param parameter - Dismissal callback function or layer configuration options object.
21
+ *
22
+ * @example
23
+ * ```svelte
24
+ * <div use:nuiLayer={() => (isOpen = false)}>...</div>
25
+ * <div use:nuiLayer={{ onDismiss: close, allowOutside: '.portal-menu' }}>...</div>
26
+ * ```
27
+ */
28
+ export const nuiLayer = (node, parameter) => {
29
+ let currentParam = parameter;
30
+ let active = false;
31
+ let trapAction = null;
32
+ const id = toLayerOptions(parameter).id ?? nextLayerId();
33
+ function getOptions() {
34
+ return toLayerOptions(currentParam);
35
+ }
36
+ function isEnabled() {
37
+ const opts = getOptions();
38
+ const { enabled } = opts;
39
+ return typeof enabled === 'function' ? enabled() : (enabled ?? true);
40
+ }
41
+ const instance = {
42
+ id,
43
+ node,
44
+ getOptions
45
+ };
46
+ function syncFocusTrap() {
47
+ const opts = getOptions();
48
+ const enabled = isEnabled();
49
+ if (!enabled || opts.trapFocus === false) {
50
+ if (trapAction) {
51
+ trapAction.destroy?.();
52
+ trapAction = null;
53
+ }
54
+ return;
55
+ }
56
+ const trapConfig = typeof opts.trapFocus === 'object' ? { ...opts.trapFocus } : {};
57
+ if (trapConfig.allowOutside === undefined && opts.allowOutside !== undefined) {
58
+ trapConfig.allowOutside = opts.allowOutside;
59
+ }
60
+ if (trapConfig.initialFocus === undefined && opts.initialFocus !== undefined) {
61
+ trapConfig.initialFocus = opts.initialFocus;
62
+ }
63
+ if (trapConfig.returnFocus === undefined && opts.returnFocus !== undefined) {
64
+ trapConfig.returnFocus = opts.returnFocus;
65
+ }
66
+ if (trapConfig.autofocus === undefined && opts.autofocus !== undefined) {
67
+ trapConfig.autofocus = opts.autofocus;
68
+ }
69
+ trapConfig.enabled = enabled;
70
+ trapConfig.isTopmost = () => getTopLayer() === instance;
71
+ if (!trapAction) {
72
+ trapAction = nuiFocusTrap(node, trapConfig);
73
+ }
74
+ else {
75
+ trapAction.update?.(trapConfig);
76
+ }
77
+ }
78
+ function setup() {
79
+ if (active)
80
+ return;
81
+ active = true;
82
+ pushLayer(instance);
83
+ syncFocusTrap();
84
+ }
85
+ function deactivate() {
86
+ if (!active)
87
+ return;
88
+ active = false;
89
+ if (trapAction) {
90
+ trapAction.destroy?.();
91
+ trapAction = null;
92
+ }
93
+ removeLayer(instance);
94
+ }
95
+ if (isEnabled()) {
96
+ setup();
97
+ }
98
+ return {
99
+ update(newParam) {
100
+ const wasEnabled = active;
101
+ currentParam = newParam;
102
+ const nowEnabled = isEnabled();
103
+ if (!wasEnabled && nowEnabled) {
104
+ setup();
105
+ }
106
+ else if (wasEnabled && !nowEnabled) {
107
+ deactivate();
108
+ }
109
+ else if (nowEnabled) {
110
+ syncFocusTrap();
111
+ }
112
+ },
113
+ destroy() {
114
+ deactivate();
115
+ }
116
+ };
117
+ };
118
+ //# sourceMappingURL=layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer.js","sourceRoot":"","sources":["../../../src/actions/layer/layer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type LayerInstance } from './types';
2
+ export declare function nextLayerId(): string;
3
+ export declare function pushLayer(instance: LayerInstance): void;
4
+ export declare function removeLayer(instance: LayerInstance): void;
5
+ export declare function getLayerStack(): readonly LayerInstance[];
6
+ export declare function resetLayerStack(): void;
7
+ export declare function getTopLayer(): LayerInstance | undefined;
8
+ export declare function ensureGlobalListeners(): void;
9
+ export declare function cleanupGlobalListeners(): void;
10
+ //# sourceMappingURL=layerStack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layerStack.d.ts","sourceRoot":"","sources":["../../../src/actions/layer/layerStack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAcpE,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAGvD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAMzD;AAED,wBAAgB,aAAa,IAAI,SAAS,aAAa,EAAE,CAExD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAQD,wBAAgB,WAAW,IAAI,aAAa,GAAG,SAAS,CAWvD;AA6FD,wBAAgB,qBAAqB,IAAI,IAAI,CAW5C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C"}
@@ -0,0 +1,153 @@
1
+ import { NuiLayerDismissReason } from './types';
2
+ import { isNodeAllowedOutside } from '../focusTrap';
3
+ import { resolveElement } from '../clickOutside';
4
+ /**
5
+ * Global stack of active overlay layers.
6
+ * Manages hierarchical Escape key and outside click handling across modals, dialogs,
7
+ * drawers, and portaled overlays in FiveM NUI.
8
+ */
9
+ const layerStack = [];
10
+ let globalController = null;
11
+ let layerIdCounter = 0;
12
+ export function nextLayerId() {
13
+ return `nui-layer-${++layerIdCounter}`;
14
+ }
15
+ export function pushLayer(instance) {
16
+ layerStack.push(instance);
17
+ ensureGlobalListeners();
18
+ }
19
+ export function removeLayer(instance) {
20
+ const idx = layerStack.findIndex((l) => l === instance);
21
+ if (idx !== -1) {
22
+ layerStack.splice(idx, 1);
23
+ }
24
+ cleanupGlobalListeners();
25
+ }
26
+ export function getLayerStack() {
27
+ return [...layerStack];
28
+ }
29
+ export function resetLayerStack() {
30
+ layerStack.length = 0;
31
+ cleanupGlobalListeners();
32
+ }
33
+ function getSortedStack() {
34
+ return [...layerStack].sort((a, b) => {
35
+ return (a.getOptions().priority ?? 0) - (b.getOptions().priority ?? 0);
36
+ });
37
+ }
38
+ export function getTopLayer() {
39
+ const sorted = getSortedStack();
40
+ for (let i = sorted.length - 1; i >= 0; i--) {
41
+ const layer = sorted[i];
42
+ const opts = layer.getOptions();
43
+ const isEnabled = typeof opts.enabled === 'function' ? opts.enabled() : (opts.enabled ?? true);
44
+ if (isEnabled && layer.node.isConnected) {
45
+ return layer;
46
+ }
47
+ }
48
+ return undefined;
49
+ }
50
+ function onGlobalKeyDown(event) {
51
+ if (event.key !== 'Escape' || event.isComposing)
52
+ return;
53
+ if (layerStack.length === 0)
54
+ return;
55
+ const sorted = getSortedStack();
56
+ // Find the topmost active layer that handles Escape
57
+ for (let i = sorted.length - 1; i >= 0; i--) {
58
+ const layer = sorted[i];
59
+ const opts = layer.getOptions();
60
+ const isEnabled = typeof opts.enabled === 'function' ? opts.enabled() : (opts.enabled ?? true);
61
+ if (!isEnabled || !layer.node.isConnected)
62
+ continue;
63
+ const handlesEscape = opts.onEscape !== false &&
64
+ (typeof opts.onEscape === 'function' || typeof opts.onDismiss === 'function');
65
+ if (!handlesEscape)
66
+ continue;
67
+ if ((opts.ignoreRepeat ?? true) && event.repeat) {
68
+ if (opts.preventEscapeDefault ?? true) {
69
+ event.preventDefault();
70
+ }
71
+ return;
72
+ }
73
+ if (opts.preventEscapeDefault ?? true) {
74
+ event.preventDefault();
75
+ }
76
+ if (opts.stopEscapePropagation) {
77
+ event.stopPropagation();
78
+ }
79
+ try {
80
+ if (typeof opts.onEscape === 'function') {
81
+ opts.onEscape(event);
82
+ }
83
+ else if (typeof opts.onDismiss === 'function') {
84
+ opts.onDismiss(NuiLayerDismissReason.Escape);
85
+ }
86
+ }
87
+ catch (err) {
88
+ console.error('[NuiLayer] Error in onEscape/onDismiss callback:', err);
89
+ }
90
+ // Only the topmost handling layer responds to Escape
91
+ return;
92
+ }
93
+ }
94
+ function onGlobalPointerDown(event) {
95
+ if (event.button !== 0 || layerStack.length === 0)
96
+ return;
97
+ const topLayer = getTopLayer();
98
+ if (!topLayer)
99
+ return;
100
+ const opts = topLayer.getOptions();
101
+ const handlesOutside = opts.onClickOutside !== false &&
102
+ (typeof opts.onClickOutside === 'function' || typeof opts.onDismiss === 'function');
103
+ if (!handlesOutside)
104
+ return;
105
+ const path = event.composedPath();
106
+ // 1. Click inside top layer node
107
+ if (path.includes(topLayer.node))
108
+ return;
109
+ // 2. Click inside any allowed outside target (e.g. portaled dropdown)
110
+ if (opts.allowOutside && isNodeAllowedOutside(event.target, opts.allowOutside)) {
111
+ return;
112
+ }
113
+ // 3. Click inside any ignoreOutside target (e.g. trigger button)
114
+ if (opts.ignoreOutside) {
115
+ for (const item of opts.ignoreOutside) {
116
+ const el = resolveElement(item);
117
+ if (el && path.includes(el))
118
+ return;
119
+ }
120
+ }
121
+ // Trigger outside click for the topmost layer only
122
+ try {
123
+ if (typeof opts.onClickOutside === 'function') {
124
+ opts.onClickOutside(event);
125
+ }
126
+ else if (typeof opts.onDismiss === 'function') {
127
+ opts.onDismiss(NuiLayerDismissReason.Outside);
128
+ }
129
+ }
130
+ catch (err) {
131
+ console.error('[NuiLayer] Error in onClickOutside/onDismiss callback:', err);
132
+ }
133
+ }
134
+ export function ensureGlobalListeners() {
135
+ if (globalController || layerStack.length === 0)
136
+ return;
137
+ globalController = new AbortController();
138
+ document.addEventListener('keydown', onGlobalKeyDown, {
139
+ capture: true,
140
+ signal: globalController.signal
141
+ });
142
+ document.addEventListener('pointerdown', onGlobalPointerDown, {
143
+ capture: true,
144
+ signal: globalController.signal
145
+ });
146
+ }
147
+ export function cleanupGlobalListeners() {
148
+ if (layerStack.length === 0 && globalController) {
149
+ globalController.abort();
150
+ globalController = null;
151
+ }
152
+ }
153
+ //# sourceMappingURL=layerStack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layerStack.js","sourceRoot":"","sources":["../../../src/actions/layer/layerStack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import type { NuiFocusTrapOptions, FocusTrapAllowOutside } from '../focusTrap';
2
+ import type { ClickOutsideTarget } from '../clickOutside';
3
+ export declare enum NuiLayerDismissReason {
4
+ Escape = "escape",
5
+ Outside = "outside"
6
+ }
7
+ export interface NuiLayerOptions {
8
+ /**
9
+ * Unique identifier for the layer.
10
+ * Auto-generated if omitted.
11
+ */
12
+ id?: string;
13
+ /**
14
+ * Whether the layer is active in the layer stack.
15
+ * Accepts a boolean or a reactive getter `() => boolean`.
16
+ * @defaultValue true
17
+ */
18
+ enabled?: boolean | (() => boolean);
19
+ /**
20
+ * Unified callback invoked when the layer should be dismissed
21
+ * (either via Escape key or outside click while topmost).
22
+ */
23
+ onDismiss?: (reason: NuiLayerDismissReason) => void;
24
+ /**
25
+ * Specific callback invoked when the Escape key is pressed while this layer is topmost.
26
+ * Set to `false` to disable Escape handling for this layer.
27
+ */
28
+ onEscape?: ((event: KeyboardEvent) => void) | boolean;
29
+ /**
30
+ * Specific callback invoked when a click occurs outside this layer while it is topmost.
31
+ * Set to `false` to disable outside click handling for this layer.
32
+ */
33
+ onClickOutside?: ((event: PointerEvent) => void) | boolean;
34
+ /**
35
+ * Focus trap configuration for this layer:
36
+ * - `true`: enables default focus trap (default)
37
+ * - `false`: disables focus trap
38
+ * - `NuiFocusTrapOptions`: custom focus trap options (initialFocus, returnFocus, autofocus, etc.)
39
+ *
40
+ * @remarks
41
+ * `nuiLayer` automatically controls and overrides `trapFocus.isTopmost` so focus containment
42
+ * is synchronized strictly with layer priority (`getTopLayer() === instance`).
43
+ * @defaultValue true
44
+ */
45
+ trapFocus?: boolean | NuiFocusTrapOptions;
46
+ /**
47
+ * Elements, selectors, or getters outside the container that are permitted.
48
+ * Shared between focus trap (won't redirect Tab from them) and click-outside (won't dismiss on them).
49
+ * Essential for portaled child elements (e.g. dropdowns, date pickers, tooltips).
50
+ */
51
+ allowOutside?: FocusTrapAllowOutside;
52
+ /**
53
+ * Additional elements, selectors, or getters to ignore specifically for click-outside detection
54
+ * (e.g. the toggle or trigger button that opened this layer).
55
+ */
56
+ ignoreOutside?: ClickOutsideTarget[];
57
+ /**
58
+ * Custom element, selector or getter to receive initial focus upon activation.
59
+ * Shorthand for `trapFocus.initialFocus`.
60
+ */
61
+ initialFocus?: HTMLElement | string | (() => HTMLElement | null | undefined);
62
+ /**
63
+ * Whether to restore focus to previously focused element upon layer deactivation.
64
+ * Shorthand for `trapFocus.returnFocus`.
65
+ * @defaultValue true
66
+ */
67
+ returnFocus?: boolean | HTMLElement;
68
+ /**
69
+ * Whether to automatically move focus inside the layer on activation.
70
+ * Shorthand for `trapFocus.autofocus`.
71
+ * @defaultValue true
72
+ */
73
+ autofocus?: boolean;
74
+ /**
75
+ * Priority/z-index override. Layers with higher priority are considered on top
76
+ * regardless of activation order. Equal priority layers follow activation order.
77
+ * @defaultValue 0
78
+ */
79
+ priority?: number;
80
+ /**
81
+ * Whether to ignore repeated keydown events fired while holding the Escape key down.
82
+ * If `true`, holding Escape will not dismiss subsequent layers in rapid succession.
83
+ * @defaultValue true
84
+ */
85
+ ignoreRepeat?: boolean;
86
+ /**
87
+ * Whether to call `event.preventDefault()` when Escape is handled.
88
+ * @defaultValue true
89
+ */
90
+ preventEscapeDefault?: boolean;
91
+ /**
92
+ * Whether to call `event.stopPropagation()` when Escape is handled.
93
+ * Defaults to `false` to avoid breaking uncoordinated parent listeners on window/document.
94
+ * @defaultValue false
95
+ */
96
+ stopEscapePropagation?: boolean;
97
+ }
98
+ export type NuiLayerInput = ((reason: NuiLayerDismissReason) => void) | NuiLayerOptions | undefined;
99
+ export declare function toLayerOptions(input: NuiLayerInput): NuiLayerOptions;
100
+ export interface LayerInstance {
101
+ id: string;
102
+ node: HTMLElement;
103
+ getOptions: () => NuiLayerOptions;
104
+ }
105
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/actions/layer/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,oBAAY,qBAAqB;IAC/B,MAAM,WAAW;IACjB,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IAEpC;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAEpD;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC;IAEtD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC;IAE3D;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAE1C;;;;OAIG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;OAGG;IACH,aAAa,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAErC;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAE7E;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAEpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,aAAa,GACrB,CAAC,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC,GACzC,eAAe,GACf,SAAS,CAAC;AAEd,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAMpE;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,eAAe,CAAC;CACnC"}
@@ -0,0 +1,14 @@
1
+ export var NuiLayerDismissReason;
2
+ (function (NuiLayerDismissReason) {
3
+ NuiLayerDismissReason["Escape"] = "escape";
4
+ NuiLayerDismissReason["Outside"] = "outside";
5
+ })(NuiLayerDismissReason || (NuiLayerDismissReason = {}));
6
+ export function toLayerOptions(input) {
7
+ if (!input)
8
+ return { enabled: true };
9
+ if (typeof input === 'function') {
10
+ return { enabled: true, onDismiss: input };
11
+ }
12
+ return input;
13
+ }
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/actions/layer/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAN,IAAY,qBAGX;AAHD,WAAY,qBAAqB;IAC/B,0CAAiB,CAAA;IACjB,4CAAmB,CAAA;AACrB,CAAC,EAHW,qBAAqB,KAArB,qBAAqB,QAGhC;AAiHD,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,133 @@
1
+ import type { Action } from 'svelte/action';
2
+ import { type NuiFocusTrapOptions, type FocusTrapAllowOutside } from './focusTrap';
3
+ import { type ClickOutsideTarget } from './clickOutside';
4
+ export declare enum NuiLayerDismissReason {
5
+ Escape = "escape",
6
+ Outside = "outside"
7
+ }
8
+ export interface NuiLayerOptions {
9
+ /**
10
+ * Unique identifier for the layer.
11
+ * Auto-generated if omitted.
12
+ */
13
+ id?: string;
14
+ /**
15
+ * Whether the layer is active in the layer stack.
16
+ * Accepts a boolean or a reactive getter `() => boolean`.
17
+ * @defaultValue true
18
+ */
19
+ enabled?: boolean | (() => boolean);
20
+ /**
21
+ * Unified callback invoked when the layer should be dismissed
22
+ * (either via Escape key or outside click while topmost).
23
+ */
24
+ onDismiss?: (reason: NuiLayerDismissReason) => void;
25
+ /**
26
+ * Specific callback invoked when the Escape key is pressed while this layer is topmost.
27
+ * Set to `false` to disable Escape handling for this layer.
28
+ */
29
+ onEscape?: ((event: KeyboardEvent) => void) | boolean;
30
+ /**
31
+ * Specific callback invoked when a click occurs outside this layer while it is topmost.
32
+ * Set to `false` to disable outside click handling for this layer.
33
+ */
34
+ onClickOutside?: ((event: PointerEvent) => void) | boolean;
35
+ /**
36
+ * Focus trap configuration for this layer:
37
+ * - `true`: enables default focus trap (default)
38
+ * - `false`: disables focus trap
39
+ * - `NuiFocusTrapOptions`: custom focus trap options (initialFocus, returnFocus, autofocus, etc.)
40
+ *
41
+ * @remarks
42
+ * `nuiLayer` automatically controls and overrides `trapFocus.isTopmost` so focus containment
43
+ * is synchronized strictly with layer priority (`getTopLayer() === instance`).
44
+ * @defaultValue true
45
+ */
46
+ trapFocus?: boolean | NuiFocusTrapOptions;
47
+ /**
48
+ * Elements, selectors, or getters outside the container that are permitted.
49
+ * Shared between focus trap (won't redirect Tab from them) and click-outside (won't dismiss on them).
50
+ * Essential for portaled child elements (e.g. dropdowns, date pickers, tooltips).
51
+ */
52
+ allowOutside?: FocusTrapAllowOutside;
53
+ /**
54
+ * Additional elements, selectors, or getters to ignore specifically for click-outside detection
55
+ * (e.g. the toggle or trigger button that opened this layer).
56
+ */
57
+ ignoreOutside?: ClickOutsideTarget[];
58
+ /**
59
+ * Custom element, selector or getter to receive initial focus upon activation.
60
+ * Shorthand for `trapFocus.initialFocus`.
61
+ */
62
+ initialFocus?: HTMLElement | string | (() => HTMLElement | null | undefined);
63
+ /**
64
+ * Whether to restore focus to previously focused element upon layer deactivation.
65
+ * Shorthand for `trapFocus.returnFocus`.
66
+ * @defaultValue true
67
+ */
68
+ returnFocus?: boolean | HTMLElement;
69
+ /**
70
+ * Whether to automatically move focus inside the layer on activation.
71
+ * Shorthand for `trapFocus.autofocus`.
72
+ * @defaultValue true
73
+ */
74
+ autofocus?: boolean;
75
+ /**
76
+ * Priority/z-index override. Layers with higher priority are considered on top
77
+ * regardless of activation order. Equal priority layers follow activation order.
78
+ * @defaultValue 0
79
+ */
80
+ priority?: number;
81
+ /**
82
+ * Whether to ignore repeated keydown events fired while holding the Escape key down.
83
+ * If `true`, holding Escape will not dismiss subsequent layers in rapid succession.
84
+ * @defaultValue true
85
+ */
86
+ ignoreRepeat?: boolean;
87
+ /**
88
+ * Whether to call `event.preventDefault()` when Escape is handled.
89
+ * @defaultValue true
90
+ */
91
+ preventEscapeDefault?: boolean;
92
+ /**
93
+ * Whether to call `event.stopPropagation()` when Escape is handled.
94
+ * Defaults to `false` to avoid breaking uncoordinated parent listeners on window/document.
95
+ * @defaultValue false
96
+ */
97
+ stopEscapePropagation?: boolean;
98
+ }
99
+ export type NuiLayerInput = ((reason: NuiLayerDismissReason) => void) | NuiLayerOptions | undefined;
100
+ export declare function toLayerOptions(input: NuiLayerInput): NuiLayerOptions;
101
+ export interface LayerInstance {
102
+ id: string;
103
+ node: HTMLElement;
104
+ getOptions: () => NuiLayerOptions;
105
+ }
106
+ export declare function getLayerStack(): readonly LayerInstance[];
107
+ export declare function resetLayerStack(): void;
108
+ export declare function getTopLayer(): LayerInstance | undefined;
109
+ /**
110
+ * Svelte Action for managing an overlay layer in FiveM NUI.
111
+ *
112
+ * Coordinates:
113
+ * - **Escape key**: Traverses the layer stack top-to-bottom. The topmost active layer that handles Escape
114
+ * receives the event and dismisses. If the topmost layer disables Escape (`onEscape: false`),
115
+ * lower layers can handle it.
116
+ * - **Outside click**: Evaluates strictly the topmost active layer. If the topmost layer disables outside
117
+ * clicks (`onClickOutside: false`), clicks outside are blocked and do NOT fall through to underlying layers,
118
+ * preserving modal barrier isolation.
119
+ * - **Focus trap**: Integrates `nuiFocusTrap` synchronized with layer priority so focus containment and Tab
120
+ * navigation are enforced by the topmost layer even when layers have varying priorities.
121
+ * - **Portal integration**: `allowOutside` allows portaled children (selects, datepickers, tooltips)
122
+ * without triggering outside clicks or breaking focus containment.
123
+ * @param node - The DOM element attaching the layer action.
124
+ * @param parameter - Dismissal callback function or layer configuration options object.
125
+ *
126
+ * @example
127
+ * ```svelte
128
+ * <div use:nuiLayer={() => (isOpen = false)}>...</div>
129
+ * <div use:nuiLayer={{ onDismiss: close, allowOutside: '.portal-menu' }}>...</div>
130
+ * ```
131
+ */
132
+ export declare const nuiLayer: Action<HTMLElement, NuiLayerInput>;
133
+ //# sourceMappingURL=layer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../../src/actions/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAE3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAExB,oBAAY,qBAAqB;IAC/B,MAAM,WAAW;IACjB,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IAEpC;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAEpD;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC;IAEtD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC;IAE3D;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAE1C;;;;OAIG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;OAGG;IACH,aAAa,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAErC;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAE7E;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAEpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,aAAa,GACrB,CAAC,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC,GACzC,eAAe,GACf,SAAS,CAAC;AAEd,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAMpE;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,eAAe,CAAC;CACnC;AAYD,wBAAgB,aAAa,IAAI,SAAS,aAAa,EAAE,CAExD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAQD,wBAAgB,WAAW,IAAI,aAAa,GAAG,SAAS,CAWvD;AAiHD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,aAAa,CAyGvD,CAAC"}