bits-ui 1.0.0-next.33 → 1.0.0-next.34

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 (40) hide show
  1. package/dist/bits/context-menu/components/context-menu-content-static.svelte +77 -27
  2. package/dist/bits/context-menu/components/context-menu-content-static.svelte.d.ts +2 -2
  3. package/dist/bits/context-menu/components/context-menu-content.svelte +70 -31
  4. package/dist/bits/dropdown-menu/components/dropdown-menu-content-static.svelte +64 -26
  5. package/dist/bits/dropdown-menu/components/dropdown-menu-content-static.svelte.d.ts +2 -2
  6. package/dist/bits/dropdown-menu/components/dropdown-menu-content.svelte +59 -25
  7. package/dist/bits/link-preview/components/link-preview-content-static.svelte +90 -31
  8. package/dist/bits/link-preview/components/link-preview-content-static.svelte.d.ts +2 -2
  9. package/dist/bits/link-preview/components/link-preview-content.svelte +65 -30
  10. package/dist/bits/menu/components/menu-content-static.svelte +70 -30
  11. package/dist/bits/menu/components/menu-content-static.svelte.d.ts +2 -2
  12. package/dist/bits/menu/components/menu-content.svelte +65 -28
  13. package/dist/bits/menu/components/menu-sub-content-static.svelte +83 -46
  14. package/dist/bits/menu/components/menu-sub-content.svelte +76 -43
  15. package/dist/bits/popover/components/popover-content-static.svelte +70 -31
  16. package/dist/bits/popover/components/popover-content-static.svelte.d.ts +2 -2
  17. package/dist/bits/popover/components/popover-content.svelte +64 -29
  18. package/dist/bits/popover/popover.svelte.d.ts +3 -0
  19. package/dist/bits/popover/popover.svelte.js +3 -0
  20. package/dist/bits/select/components/select-content-static.svelte +68 -33
  21. package/dist/bits/select/components/select-content-static.svelte.d.ts +2 -2
  22. package/dist/bits/select/components/select-content.svelte +63 -38
  23. package/dist/bits/select/select.svelte.d.ts +4 -0
  24. package/dist/bits/select/select.svelte.js +1 -0
  25. package/dist/bits/tooltip/components/tooltip-content-static.svelte +88 -30
  26. package/dist/bits/tooltip/components/tooltip-content-static.svelte.d.ts +2 -2
  27. package/dist/bits/tooltip/components/tooltip-content.svelte +63 -28
  28. package/dist/bits/tooltip/tooltip.svelte.d.ts +8 -4
  29. package/dist/bits/tooltip/tooltip.svelte.js +4 -0
  30. package/dist/bits/utilities/focus-scope/focus-scope-stack.svelte.js +1 -1
  31. package/dist/bits/utilities/focus-scope/focus-scope.svelte +2 -0
  32. package/dist/bits/utilities/focus-scope/types.d.ts +4 -0
  33. package/dist/bits/utilities/focus-scope/useFocusScope.svelte.d.ts +5 -1
  34. package/dist/bits/utilities/focus-scope/useFocusScope.svelte.js +53 -34
  35. package/dist/bits/utilities/popper-layer/popper-layer-force-mount.svelte +85 -0
  36. package/dist/bits/utilities/popper-layer/popper-layer-force-mount.svelte.d.ts +21 -0
  37. package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte +126 -0
  38. package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte.d.ts +21 -0
  39. package/dist/bits/utilities/popper-layer/popper-layer.svelte +22 -62
  40. package/package.json +1 -1
@@ -5,6 +5,7 @@
5
5
  import { useId } from "../../../internal/use-id.js";
6
6
  import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
7
7
  import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
8
+ import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
8
9
 
9
10
  let {
10
11
  children,
@@ -45,38 +46,72 @@
45
46
  });
46
47
 
47
48
  const mergedProps = $derived(mergeProps(restProps, floatingProps, contentState.props));
48
- </script>
49
49
 
50
- <PopperLayer
51
- {...mergedProps}
52
- present={contentState.root.open.current || forceMount}
53
- {id}
54
- onInteractOutside={(e) => {
50
+ function handleInteractOutside(e: PointerEvent) {
55
51
  onInteractOutside?.(e);
56
52
  if (e.defaultPrevented) return;
57
- contentState.root.immediateClose();
58
- }}
59
- onEscapeKeydown={(e) => {
53
+ contentState.root.handleClose();
54
+ }
55
+
56
+ function handleEscapeKeydown(e: KeyboardEvent) {
60
57
  onEscapeKeydown?.(e);
61
58
  if (e.defaultPrevented) return;
62
- contentState.root.immediateClose();
63
- }}
64
- onOpenAutoFocus={(e) => e.preventDefault()}
65
- onCloseAutoFocus={(e) => e.preventDefault()}
66
- trapFocus={false}
67
- loop={false}
68
- preventScroll={false}
69
- >
70
- {#snippet popper({ props })}
71
- {@const mergedProps = mergeProps(props, {
72
- style: getFloatingContentCSSVars("link-preview"),
73
- })}
74
- {#if child}
75
- {@render child({ props: mergedProps, ...contentState.snippetProps })}
76
- {:else}
77
- <div {...mergedProps}>
78
- {@render children?.()}
79
- </div>
80
- {/if}
81
- {/snippet}
82
- </PopperLayer>
59
+ contentState.root.handleClose();
60
+ }
61
+ </script>
62
+
63
+ {#if forceMount}
64
+ <PopperLayerForceMount
65
+ {...mergedProps}
66
+ enabled={contentState.root.open.current}
67
+ {id}
68
+ onInteractOutside={handleInteractOutside}
69
+ onEscapeKeydown={handleEscapeKeydown}
70
+ onOpenAutoFocus={(e) => e.preventDefault()}
71
+ onCloseAutoFocus={(e) => e.preventDefault()}
72
+ trapFocus={false}
73
+ loop={false}
74
+ preventScroll={false}
75
+ forceMount={true}
76
+ >
77
+ {#snippet popper({ props })}
78
+ {@const mergedProps = mergeProps(props, {
79
+ style: getFloatingContentCSSVars("link-preview"),
80
+ })}
81
+ {#if child}
82
+ {@render child({ props: mergedProps, ...contentState.snippetProps })}
83
+ {:else}
84
+ <div {...mergedProps}>
85
+ {@render children?.()}
86
+ </div>
87
+ {/if}
88
+ {/snippet}
89
+ </PopperLayerForceMount>
90
+ {:else if !forceMount}
91
+ <PopperLayer
92
+ {...mergedProps}
93
+ present={contentState.root.open.current}
94
+ {id}
95
+ onInteractOutside={handleInteractOutside}
96
+ onEscapeKeydown={handleEscapeKeydown}
97
+ onOpenAutoFocus={(e) => e.preventDefault()}
98
+ onCloseAutoFocus={(e) => e.preventDefault()}
99
+ trapFocus={false}
100
+ loop={false}
101
+ preventScroll={false}
102
+ forceMount={false}
103
+ >
104
+ {#snippet popper({ props })}
105
+ {@const mergedProps = mergeProps(props, {
106
+ style: getFloatingContentCSSVars("link-preview"),
107
+ })}
108
+ {#if child}
109
+ {@render child({ props: mergedProps, ...contentState.snippetProps })}
110
+ {:else}
111
+ <div {...mergedProps}>
112
+ {@render children?.()}
113
+ </div>
114
+ {/if}
115
+ {/snippet}
116
+ </PopperLayer>
117
+ {/if}
@@ -1,11 +1,13 @@
1
1
  <script lang="ts">
2
2
  import { box, mergeProps } from "svelte-toolbelt";
3
- import type { MenuContentStaticProps } from "../types.js";
3
+ import type { MenuContentProps } from "../types.js";
4
4
  import { useMenuContent } from "../menu.svelte.js";
5
5
  import { useId } from "../../../internal/use-id.js";
6
6
  import { noop } from "../../../internal/noop.js";
7
7
  import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
8
8
  import Mounted from "../../utilities/mounted.svelte";
9
+ import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
10
+ import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
9
11
 
10
12
  let {
11
13
  id = useId(),
@@ -17,7 +19,7 @@
17
19
  onEscapeKeydown = noop,
18
20
  forceMount = false,
19
21
  ...restProps
20
- }: MenuContentStaticProps = $props();
22
+ }: MenuContentProps = $props();
21
23
 
22
24
  let isMounted = $state(false);
23
25
 
@@ -36,38 +38,76 @@
36
38
  style: { outline: "none" },
37
39
  })
38
40
  );
39
- </script>
40
41
 
41
- <PopperLayer
42
- isStatic={true}
43
- {...mergedProps}
44
- present={contentState.parentMenu.open.current || forceMount}
45
- onInteractOutside={(e) => {
42
+ function handleInteractOutside(e: PointerEvent) {
46
43
  onInteractOutside(e);
47
44
  if (e.defaultPrevented) return;
48
45
  contentState.parentMenu.onClose();
49
- }}
50
- onEscapeKeydown={(e) => {
46
+ }
47
+
48
+ function handleEscapeKeydown(e: KeyboardEvent) {
51
49
  onEscapeKeydown(e);
52
50
  if (e.defaultPrevented) return;
53
51
  contentState.parentMenu.onClose();
54
- }}
55
- trapFocus
56
- {loop}
57
- >
58
- {#snippet popper({ props })}
59
- {@const finalProps = mergeProps(props, {
60
- style: {
61
- outline: "none",
62
- },
63
- })}
64
- {#if child}
65
- {@render child({ props: finalProps, ...contentState.snippetProps })}
66
- {:else}
67
- <div {...finalProps}>
68
- {@render children?.()}
69
- </div>
70
- {/if}
71
- <Mounted bind:isMounted />
72
- {/snippet}
73
- </PopperLayer>
52
+ }
53
+ </script>
54
+
55
+ {#if forceMount}
56
+ <PopperLayerForceMount
57
+ {...mergedProps}
58
+ enabled={contentState.parentMenu.open.current}
59
+ onInteractOutside={handleInteractOutside}
60
+ onEscapeKeydown={handleEscapeKeydown}
61
+ trapFocus
62
+ {loop}
63
+ forceMount={true}
64
+ isStatic
65
+ {id}
66
+ >
67
+ {#snippet popper({ props })}
68
+ {@const finalProps = mergeProps(props, {
69
+ style: {
70
+ outline: "none",
71
+ ...getFloatingContentCSSVars("menu"),
72
+ },
73
+ })}
74
+ {#if child}
75
+ {@render child({ props: finalProps, ...contentState.snippetProps })}
76
+ {:else}
77
+ <div {...finalProps}>
78
+ {@render children?.()}
79
+ </div>
80
+ {/if}
81
+ <Mounted bind:isMounted />
82
+ {/snippet}
83
+ </PopperLayerForceMount>
84
+ {:else if !forceMount}
85
+ <PopperLayer
86
+ {...mergedProps}
87
+ present={contentState.parentMenu.open.current}
88
+ onInteractOutside={handleInteractOutside}
89
+ onEscapeKeydown={handleEscapeKeydown}
90
+ trapFocus
91
+ {loop}
92
+ forceMount={false}
93
+ isStatic
94
+ {id}
95
+ >
96
+ {#snippet popper({ props })}
97
+ {@const finalProps = mergeProps(props, {
98
+ style: {
99
+ outline: "none",
100
+ ...getFloatingContentCSSVars("menu"),
101
+ },
102
+ })}
103
+ {#if child}
104
+ {@render child({ props: finalProps, ...contentState.snippetProps })}
105
+ {:else}
106
+ <div {...finalProps}>
107
+ {@render children?.()}
108
+ </div>
109
+ {/if}
110
+ <Mounted bind:isMounted />
111
+ {/snippet}
112
+ </PopperLayer>
113
+ {/if}
@@ -1,4 +1,4 @@
1
- import type { MenuContentStaticProps } from "../types.js";
1
+ import type { MenuContentProps } from "../types.js";
2
2
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
3
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
4
  $$bindings?: Bindings;
@@ -12,7 +12,7 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
12
12
  };
13
13
  z_$$bindings?: Bindings;
14
14
  }
15
- declare const MenuContentStatic: $$__sveltets_2_IsomorphicComponent<MenuContentStaticProps, {
15
+ declare const MenuContentStatic: $$__sveltets_2_IsomorphicComponent<MenuContentProps, {
16
16
  [evt: string]: CustomEvent<any>;
17
17
  }, {}, {}, "ref">;
18
18
  type MenuContentStatic = InstanceType<typeof MenuContentStatic>;
@@ -7,6 +7,7 @@
7
7
  import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
8
8
  import Mounted from "../../utilities/mounted.svelte";
9
9
  import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
10
+ import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
10
11
 
11
12
  let {
12
13
  id = useId(),
@@ -37,38 +38,74 @@
37
38
  style: { outline: "none" },
38
39
  })
39
40
  );
40
- </script>
41
41
 
42
- <PopperLayer
43
- {...mergedProps}
44
- present={contentState.parentMenu.open.current || forceMount}
45
- onInteractOutside={(e) => {
42
+ function handleInteractOutside(e: PointerEvent) {
46
43
  onInteractOutside(e);
47
44
  if (e.defaultPrevented) return;
48
45
  contentState.parentMenu.onClose();
49
- }}
50
- onEscapeKeydown={(e) => {
46
+ }
47
+
48
+ function handleEscapeKeydown(e: KeyboardEvent) {
51
49
  onEscapeKeydown(e);
52
50
  if (e.defaultPrevented) return;
53
51
  contentState.parentMenu.onClose();
54
- }}
55
- trapFocus
56
- {loop}
57
- >
58
- {#snippet popper({ props })}
59
- {@const finalProps = mergeProps(props, {
60
- style: {
61
- outline: "none",
62
- ...getFloatingContentCSSVars("menu"),
63
- },
64
- })}
65
- {#if child}
66
- {@render child({ props: finalProps, ...contentState.snippetProps })}
67
- {:else}
68
- <div {...finalProps}>
69
- {@render children?.()}
70
- </div>
71
- {/if}
72
- <Mounted bind:isMounted />
73
- {/snippet}
74
- </PopperLayer>
52
+ }
53
+ </script>
54
+
55
+ {#if forceMount}
56
+ <PopperLayerForceMount
57
+ {...mergedProps}
58
+ enabled={contentState.parentMenu.open.current}
59
+ onInteractOutside={handleInteractOutside}
60
+ onEscapeKeydown={handleEscapeKeydown}
61
+ trapFocus
62
+ {loop}
63
+ forceMount={true}
64
+ {id}
65
+ >
66
+ {#snippet popper({ props })}
67
+ {@const finalProps = mergeProps(props, {
68
+ style: {
69
+ outline: "none",
70
+ ...getFloatingContentCSSVars("menu"),
71
+ },
72
+ })}
73
+ {#if child}
74
+ {@render child({ props: finalProps, ...contentState.snippetProps })}
75
+ {:else}
76
+ <div {...finalProps}>
77
+ {@render children?.()}
78
+ </div>
79
+ {/if}
80
+ <Mounted bind:isMounted />
81
+ {/snippet}
82
+ </PopperLayerForceMount>
83
+ {:else if !forceMount}
84
+ <PopperLayer
85
+ {...mergedProps}
86
+ present={contentState.parentMenu.open.current}
87
+ onInteractOutside={handleInteractOutside}
88
+ onEscapeKeydown={handleEscapeKeydown}
89
+ trapFocus
90
+ {loop}
91
+ forceMount={false}
92
+ {id}
93
+ >
94
+ {#snippet popper({ props })}
95
+ {@const finalProps = mergeProps(props, {
96
+ style: {
97
+ outline: "none",
98
+ ...getFloatingContentCSSVars("menu"),
99
+ },
100
+ })}
101
+ {#if child}
102
+ {@render child({ props: finalProps, ...contentState.snippetProps })}
103
+ {:else}
104
+ <div {...finalProps}>
105
+ {@render children?.()}
106
+ </div>
107
+ {/if}
108
+ <Mounted bind:isMounted />
109
+ {/snippet}
110
+ </PopperLayer>
111
+ {/if}
@@ -9,6 +9,7 @@
9
9
  import { isHTMLElement } from "../../../internal/is.js";
10
10
  import Mounted from "../../utilities/mounted.svelte";
11
11
  import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
12
+ import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
12
13
 
13
14
  let {
14
15
  id = useId(),
@@ -23,7 +24,7 @@
23
24
  escapeKeydownBehavior = "defer-otherwise-close",
24
25
  onOpenAutoFocus: onOpenAutoFocusProp = noop,
25
26
  onCloseAutoFocus: onCloseAutoFocusProp = noop,
26
- onFocusOutside: onFocusOutsideProp = noop,
27
+ onFocusOutside = noop,
27
28
  side = "right",
28
29
  ...restProps
29
30
  }: MenuSubContentProps = $props();
@@ -53,15 +54,19 @@
53
54
  }
54
55
  }
55
56
 
57
+ const dataAttr = $derived(subContentState.parentMenu.root.getAttr("sub-content"));
58
+
56
59
  const mergedProps = $derived(
57
60
  mergeProps(restProps, subContentState.props, {
58
61
  side,
59
62
  onkeydown,
60
- "data-menu-sub-content": "",
63
+ [dataAttr]: "",
61
64
  })
62
65
  );
63
66
 
64
- function onOpenAutoFocus(e: Event) {
67
+ function handleOpenAutoFocus(e: Event) {
68
+ onOpenAutoFocusProp(e);
69
+ if (e.defaultPrevented) return;
65
70
  afterTick(() => {
66
71
  e.preventDefault();
67
72
  if (subContentState.parentMenu.root.isUsingKeyboard.current) {
@@ -71,40 +76,26 @@
71
76
  });
72
77
  }
73
78
 
74
- function onCloseAutoFocus(e: Event) {
79
+ function handleCloseAutoFocus(e: Event) {
80
+ onCloseAutoFocusProp(e);
81
+ if (e.defaultPrevented) return;
75
82
  e.preventDefault();
76
83
  }
77
- </script>
78
84
 
79
- <PopperLayer
80
- isStatic={true}
81
- {...mergedProps}
82
- {interactOutsideBehavior}
83
- {escapeKeydownBehavior}
84
- onCloseAutoFocus={(e) => {
85
- onCloseAutoFocusProp(e);
86
- if (e.defaultPrevented) return;
87
- onCloseAutoFocus(e);
88
- }}
89
- onOpenAutoFocus={(e) => {
90
- onOpenAutoFocusProp(e);
91
- if (e.defaultPrevented) return;
92
- onOpenAutoFocus(e);
93
- }}
94
- present={subContentState.parentMenu.open.current || forceMount}
95
- onInteractOutside={(e) => {
85
+ function handleInteractOutside(e: PointerEvent) {
96
86
  onInteractOutside(e);
97
87
  if (e.defaultPrevented) return;
98
88
  subContentState.parentMenu.onClose();
99
- }}
100
- onEscapeKeydown={(e) => {
101
- // TODO: users should be able to cancel this
89
+ }
90
+
91
+ function handleEscapeKeydown(e: KeyboardEvent) {
102
92
  onEscapeKeydown(e);
103
93
  if (e.defaultPrevented) return;
104
94
  subContentState.parentMenu.onClose();
105
- }}
106
- onFocusOutside={(e) => {
107
- onFocusOutsideProp(e);
95
+ }
96
+
97
+ function handleOnFocusOutside(e: FocusEvent) {
98
+ onFocusOutside(e);
108
99
  if (e.defaultPrevented) return;
109
100
  // We prevent closing when the trigger is focused to avoid triggering a re-open animation
110
101
  // on pointer interaction.
@@ -112,21 +103,67 @@
112
103
  if (e.target.id !== subContentState.parentMenu.triggerNode?.id) {
113
104
  subContentState.parentMenu.onClose();
114
105
  }
115
- }}
116
- preventScroll={false}
117
- {loop}
118
- >
119
- {#snippet popper({ props })}
120
- {@const finalProps = mergeProps(props, mergedProps, {
121
- style: getFloatingContentCSSVars("menu"),
122
- })}
123
- {#if child}
124
- {@render child({ props: finalProps, ...subContentState.snippetProps })}
125
- {:else}
126
- <div {...finalProps}>
127
- {@render children?.()}
128
- </div>
129
- {/if}
130
- <Mounted bind:isMounted />
131
- {/snippet}
132
- </PopperLayer>
106
+ }
107
+ </script>
108
+
109
+ {#if forceMount}
110
+ <PopperLayerForceMount
111
+ {...mergedProps}
112
+ {interactOutsideBehavior}
113
+ {escapeKeydownBehavior}
114
+ onCloseAutoFocus={handleCloseAutoFocus}
115
+ onOpenAutoFocus={handleOpenAutoFocus}
116
+ enabled={subContentState.parentMenu.open.current}
117
+ onInteractOutside={handleInteractOutside}
118
+ onEscapeKeydown={handleEscapeKeydown}
119
+ onFocusOutside={handleOnFocusOutside}
120
+ preventScroll={false}
121
+ {loop}
122
+ trapFocus={false}
123
+ isStatic
124
+ >
125
+ {#snippet popper({ props })}
126
+ {@const finalProps = mergeProps(props, mergedProps, {
127
+ style: getFloatingContentCSSVars("menu"),
128
+ })}
129
+ {#if child}
130
+ {@render child({ props: finalProps, ...subContentState.snippetProps })}
131
+ {:else}
132
+ <div {...finalProps}>
133
+ {@render children?.()}
134
+ </div>
135
+ {/if}
136
+ <Mounted bind:isMounted />
137
+ {/snippet}
138
+ </PopperLayerForceMount>
139
+ {:else if !forceMount}
140
+ <PopperLayer
141
+ {...mergedProps}
142
+ {interactOutsideBehavior}
143
+ {escapeKeydownBehavior}
144
+ onCloseAutoFocus={handleCloseAutoFocus}
145
+ onOpenAutoFocus={handleOpenAutoFocus}
146
+ present={subContentState.parentMenu.open.current}
147
+ onInteractOutside={handleInteractOutside}
148
+ onEscapeKeydown={handleEscapeKeydown}
149
+ onFocusOutside={handleOnFocusOutside}
150
+ preventScroll={false}
151
+ {loop}
152
+ trapFocus={false}
153
+ isStatic
154
+ >
155
+ {#snippet popper({ props })}
156
+ {@const finalProps = mergeProps(props, mergedProps, {
157
+ style: getFloatingContentCSSVars("menu"),
158
+ })}
159
+ {#if child}
160
+ {@render child({ props: finalProps, ...subContentState.snippetProps })}
161
+ {:else}
162
+ <div {...finalProps}>
163
+ {@render children?.()}
164
+ </div>
165
+ {/if}
166
+ <Mounted bind:isMounted />
167
+ {/snippet}
168
+ </PopperLayer>
169
+ {/if}
@@ -9,6 +9,7 @@
9
9
  import { isHTMLElement } from "../../../internal/is.js";
10
10
  import Mounted from "../../utilities/mounted.svelte";
11
11
  import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
12
+ import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
12
13
 
13
14
  let {
14
15
  id = useId(),
@@ -63,7 +64,9 @@
63
64
  })
64
65
  );
65
66
 
66
- function onOpenAutoFocus(e: Event) {
67
+ function handleOpenAutoFocus(e: Event) {
68
+ onOpenAutoFocusProp(e);
69
+ if (e.defaultPrevented) return;
67
70
  afterTick(() => {
68
71
  e.preventDefault();
69
72
  if (subContentState.parentMenu.root.isUsingKeyboard.current) {
@@ -73,38 +76,25 @@
73
76
  });
74
77
  }
75
78
 
76
- function onCloseAutoFocus(e: Event) {
79
+ function handleCloseAutoFocus(e: Event) {
80
+ onCloseAutoFocusProp(e);
81
+ if (e.defaultPrevented) return;
77
82
  e.preventDefault();
78
83
  }
79
- </script>
80
84
 
81
- <PopperLayer
82
- {...mergedProps}
83
- {interactOutsideBehavior}
84
- {escapeKeydownBehavior}
85
- onCloseAutoFocus={(e) => {
86
- onCloseAutoFocusProp(e);
87
- if (e.defaultPrevented) return;
88
- onCloseAutoFocus(e);
89
- }}
90
- onOpenAutoFocus={(e) => {
91
- onOpenAutoFocusProp(e);
92
- if (e.defaultPrevented) return;
93
- onOpenAutoFocus(e);
94
- }}
95
- present={subContentState.parentMenu.open.current || forceMount}
96
- onInteractOutside={(e) => {
85
+ function handleInteractOutside(e: PointerEvent) {
97
86
  onInteractOutside(e);
98
87
  if (e.defaultPrevented) return;
99
88
  subContentState.parentMenu.onClose();
100
- }}
101
- onEscapeKeydown={(e) => {
102
- // TODO: users should be able to cancel this
89
+ }
90
+
91
+ function handleEscapeKeydown(e: KeyboardEvent) {
103
92
  onEscapeKeydown(e);
104
93
  if (e.defaultPrevented) return;
105
94
  subContentState.parentMenu.onClose();
106
- }}
107
- onFocusOutside={(e) => {
95
+ }
96
+
97
+ function handleOnFocusOutside(e: FocusEvent) {
108
98
  onFocusOutside(e);
109
99
  if (e.defaultPrevented) return;
110
100
  // We prevent closing when the trigger is focused to avoid triggering a re-open animation
@@ -113,22 +103,65 @@
113
103
  if (e.target.id !== subContentState.parentMenu.triggerNode?.id) {
114
104
  subContentState.parentMenu.onClose();
115
105
  }
116
- }}
117
- preventScroll={false}
118
- {loop}
119
- trapFocus={false}
120
- >
121
- {#snippet popper({ props })}
122
- {@const finalProps = mergeProps(props, mergedProps, {
123
- style: getFloatingContentCSSVars("menu"),
124
- })}
125
- {#if child}
126
- {@render child({ props: finalProps, ...subContentState.snippetProps })}
127
- {:else}
128
- <div {...finalProps}>
129
- {@render children?.()}
130
- </div>
131
- {/if}
132
- <Mounted bind:isMounted />
133
- {/snippet}
134
- </PopperLayer>
106
+ }
107
+ </script>
108
+
109
+ {#if forceMount}
110
+ <PopperLayerForceMount
111
+ {...mergedProps}
112
+ {interactOutsideBehavior}
113
+ {escapeKeydownBehavior}
114
+ onCloseAutoFocus={handleCloseAutoFocus}
115
+ onOpenAutoFocus={handleOpenAutoFocus}
116
+ enabled={subContentState.parentMenu.open.current}
117
+ onInteractOutside={handleInteractOutside}
118
+ onEscapeKeydown={handleEscapeKeydown}
119
+ onFocusOutside={handleOnFocusOutside}
120
+ preventScroll={false}
121
+ {loop}
122
+ trapFocus={false}
123
+ >
124
+ {#snippet popper({ props })}
125
+ {@const finalProps = mergeProps(props, mergedProps, {
126
+ style: getFloatingContentCSSVars("menu"),
127
+ })}
128
+ {#if child}
129
+ {@render child({ props: finalProps, ...subContentState.snippetProps })}
130
+ {:else}
131
+ <div {...finalProps}>
132
+ {@render children?.()}
133
+ </div>
134
+ {/if}
135
+ <Mounted bind:isMounted />
136
+ {/snippet}
137
+ </PopperLayerForceMount>
138
+ {:else if !forceMount}
139
+ <PopperLayer
140
+ {...mergedProps}
141
+ {interactOutsideBehavior}
142
+ {escapeKeydownBehavior}
143
+ onCloseAutoFocus={handleCloseAutoFocus}
144
+ onOpenAutoFocus={handleOpenAutoFocus}
145
+ present={subContentState.parentMenu.open.current}
146
+ onInteractOutside={handleInteractOutside}
147
+ onEscapeKeydown={handleEscapeKeydown}
148
+ onFocusOutside={handleOnFocusOutside}
149
+ preventScroll={false}
150
+ {loop}
151
+ trapFocus={false}
152
+ >
153
+ {#snippet popper({ props })}
154
+ {@const finalProps = mergeProps(props, mergedProps, {
155
+ style: getFloatingContentCSSVars("menu"),
156
+ })}
157
+ {#if child}
158
+ {@render child({ props: finalProps, ...subContentState.snippetProps })}
159
+ {:else}
160
+ <div {...finalProps}>
161
+ {@render children?.()}
162
+ </div>
163
+ {/if}
164
+ <Mounted bind:isMounted />
165
+ {/snippet}
166
+ </PopperLayer>
167
+ {/if}