@pzerelles/headlessui-svelte 2.1.2-next.6 → 2.1.2-next.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/button/Button.svelte +16 -19
- package/dist/button/Button.svelte.d.ts +8 -36
- package/dist/button/index.d.ts +1 -1
- package/dist/button/index.js +1 -1
- package/dist/checkbox/Checkbox.svelte +31 -27
- package/dist/checkbox/Checkbox.svelte.d.ts +17 -38
- package/dist/checkbox/index.d.ts +1 -1
- package/dist/checkbox/index.js +1 -1
- package/dist/close-button/CloseButton.svelte +4 -7
- package/dist/close-button/CloseButton.svelte.d.ts +3 -46
- package/dist/close-button/index.d.ts +1 -0
- package/dist/close-button/index.js +1 -0
- package/dist/data-interactive/DataInteractive.svelte +6 -22
- package/dist/data-interactive/DataInteractive.svelte.d.ts +9 -34
- package/dist/data-interactive/index.d.ts +1 -1
- package/dist/data-interactive/index.js +1 -1
- package/dist/description/Description.svelte +29 -24
- package/dist/description/Description.svelte.d.ts +9 -30
- package/dist/description/context.svelte.js +14 -16
- package/dist/description/index.d.ts +1 -1
- package/dist/dialog/Dialog.svelte +25 -30
- package/dist/dialog/Dialog.svelte.d.ts +7 -45
- package/dist/dialog/DialogBackdrop.svelte +11 -14
- package/dist/dialog/DialogBackdrop.svelte.d.ts +8 -33
- package/dist/dialog/DialogPanel.svelte +30 -19
- package/dist/dialog/DialogPanel.svelte.d.ts +8 -34
- package/dist/dialog/DialogTitle.svelte +17 -8
- package/dist/dialog/DialogTitle.svelte.d.ts +9 -30
- package/dist/dialog/InternalDialog.svelte +38 -34
- package/dist/dialog/InternalDialog.svelte.d.ts +3 -41
- package/dist/dialog/context.svelte.js +2 -2
- package/dist/dialog/index.d.ts +4 -4
- package/dist/dialog/index.js +4 -4
- package/dist/disclosure/Disclosure.svelte +61 -0
- package/dist/disclosure/Disclosure.svelte.d.ts +14 -0
- package/dist/disclosure/DisclosureButton.svelte +191 -0
- package/dist/disclosure/DisclosureButton.svelte.d.ts +19 -0
- package/dist/disclosure/DisclosurePanel.svelte +99 -0
- package/dist/disclosure/DisclosurePanel.svelte.d.ts +16 -0
- package/dist/disclosure/context.svelte.d.ts +32 -0
- package/dist/disclosure/context.svelte.js +94 -0
- package/dist/disclosure/index.d.ts +3 -0
- package/dist/disclosure/index.js +3 -0
- package/dist/field/Field.svelte +27 -26
- package/dist/field/Field.svelte.d.ts +7 -34
- package/dist/field/index.d.ts +1 -1
- package/dist/fieldset/Fieldset.svelte +21 -20
- package/dist/fieldset/Fieldset.svelte.d.ts +8 -35
- package/dist/fieldset/index.d.ts +1 -1
- package/dist/focus-trap/FocusTrap.svelte +29 -36
- package/dist/focus-trap/FocusTrap.svelte.d.ts +8 -38
- package/dist/hooks/use-controllable.svelte.js +3 -2
- package/dist/hooks/use-did-element-move.svelte.js +5 -10
- package/dist/hooks/use-disabled.d.ts +6 -1
- package/dist/hooks/use-disabled.js +10 -5
- package/dist/hooks/use-element-size.svelte.js +1 -1
- package/dist/hooks/use-event-listener.svelte.d.ts +1 -1
- package/dist/hooks/use-event-listener.svelte.js +3 -1
- package/dist/hooks/use-focus-ring.svelte.js +1 -1
- package/dist/hooks/use-inert-others.svelte.js +10 -10
- package/dist/hooks/use-is-top-layer.svelte.js +2 -2
- package/dist/hooks/use-resolve-button-type.svelte.js +0 -1
- package/dist/hooks/use-root-containers.svelte.d.ts +2 -2
- package/dist/hooks/use-root-containers.svelte.js +7 -6
- package/dist/hooks/use-tab-direction.svelte.js +1 -1
- package/dist/hooks/use-transition.svelte.d.ts +1 -0
- package/dist/hooks/use-transition.svelte.js +32 -7
- package/dist/index.d.ts +11 -2
- package/dist/index.js +11 -2
- package/dist/input/Input.svelte +28 -21
- package/dist/input/Input.svelte.d.ts +16 -33
- package/dist/input/index.d.ts +1 -1
- package/dist/input/index.js +1 -1
- package/dist/internal/FloatingProvider.svelte +17 -0
- package/dist/internal/FloatingProvider.svelte.d.ts +8 -0
- package/dist/internal/FocusSentinel.svelte +33 -32
- package/dist/internal/FocusSentinel.svelte.d.ts +4 -18
- package/dist/internal/ForcePortalRoot.svelte.d.ts +4 -18
- package/dist/internal/FormFields.svelte +18 -13
- package/dist/internal/FormFields.svelte.d.ts +4 -18
- package/dist/internal/FormFieldsProvider.svelte +17 -0
- package/dist/internal/FormFieldsProvider.svelte.d.ts +7 -0
- package/dist/internal/FormResolver.svelte +6 -2
- package/dist/internal/FormResolver.svelte.d.ts +4 -18
- package/dist/internal/Hidden.svelte +10 -10
- package/dist/internal/Hidden.svelte.d.ts +6 -33
- package/dist/internal/MainTreeProvider.svelte +2 -2
- package/dist/internal/MainTreeProvider.svelte.d.ts +4 -18
- package/dist/internal/Portal.svelte.d.ts +4 -18
- package/dist/internal/floating-provider.svelte.d.ts +3 -0
- package/dist/internal/floating-provider.svelte.js +206 -0
- package/dist/internal/floating.svelte.d.ts +47 -23
- package/dist/internal/floating.svelte.js +90 -272
- package/dist/internal/form-fields.svelte.d.ts +10 -0
- package/dist/internal/form-fields.svelte.js +23 -0
- package/dist/internal/frozen.svelte.js +1 -1
- package/dist/label/Label.svelte +15 -11
- package/dist/label/Label.svelte.d.ts +8 -33
- package/dist/label/context.svelte.js +1 -1
- package/dist/label/index.d.ts +1 -1
- package/dist/legend/Legend.svelte +22 -15
- package/dist/legend/Legend.svelte.d.ts +10 -34
- package/dist/listbox/Listbox.svelte +79 -151
- package/dist/listbox/Listbox.svelte.d.ts +16 -91
- package/dist/listbox/ListboxButton.svelte +31 -29
- package/dist/listbox/ListboxButton.svelte.d.ts +8 -38
- package/dist/listbox/ListboxOption.svelte +40 -27
- package/dist/listbox/ListboxOption.svelte.d.ts +16 -32
- package/dist/listbox/ListboxOptions.svelte +126 -72
- package/dist/listbox/ListboxOptions.svelte.d.ts +8 -43
- package/dist/listbox/ListboxSelectedOption.svelte +24 -26
- package/dist/listbox/ListboxSelectedOption.svelte.d.ts +14 -39
- package/dist/listbox/context.svelte.d.ts +76 -0
- package/dist/listbox/context.svelte.js +36 -0
- package/dist/listbox/index.d.ts +5 -5
- package/dist/listbox/index.js +4 -4
- package/dist/menu/Menu.svelte +22 -266
- package/dist/menu/Menu.svelte.d.ts +7 -37
- package/dist/menu/MenuButton.svelte +29 -24
- package/dist/menu/MenuButton.svelte.d.ts +8 -39
- package/dist/menu/MenuHeading.svelte +12 -16
- package/dist/menu/MenuHeading.svelte.d.ts +7 -36
- package/dist/menu/MenuItem.svelte +18 -23
- package/dist/menu/MenuItem.svelte.d.ts +9 -39
- package/dist/menu/MenuItems.svelte +33 -34
- package/dist/menu/MenuItems.svelte.d.ts +8 -43
- package/dist/menu/MenuSection.svelte +9 -12
- package/dist/menu/MenuSection.svelte.d.ts +7 -33
- package/dist/menu/MenuSeparator.svelte +9 -12
- package/dist/menu/MenuSeparator.svelte.d.ts +7 -33
- package/dist/menu/context.svelte.d.ts +2 -1
- package/dist/menu/context.svelte.js +212 -2
- package/dist/menu/index.d.ts +7 -7
- package/dist/menu/index.js +3 -3
- package/dist/popover/Popover.svelte +231 -0
- package/dist/popover/Popover.svelte.d.ts +15 -0
- package/dist/popover/PopoverBackdrop.svelte +83 -0
- package/dist/popover/PopoverBackdrop.svelte.d.ts +17 -0
- package/dist/popover/PopoverButton.svelte +324 -0
- package/dist/popover/PopoverButton.svelte.d.ts +21 -0
- package/dist/popover/PopoverGroup.svelte +66 -0
- package/dist/popover/PopoverGroup.svelte.d.ts +9 -0
- package/dist/popover/PopoverPanel.svelte +359 -0
- package/dist/popover/PopoverPanel.svelte.d.ts +22 -0
- package/dist/popover/context.svelte.d.ts +51 -0
- package/dist/popover/context.svelte.js +108 -0
- package/dist/popover/index.d.ts +5 -0
- package/dist/popover/index.js +5 -0
- package/dist/portal/InternalPortal.svelte +18 -19
- package/dist/portal/InternalPortal.svelte.d.ts +7 -34
- package/dist/portal/Portal.svelte +7 -6
- package/dist/portal/Portal.svelte.d.ts +3 -22
- package/dist/portal/PortalGroup.svelte +6 -14
- package/dist/portal/PortalGroup.svelte.d.ts +5 -34
- package/dist/portal/PortalWrapper.svelte +10 -0
- package/dist/portal/PortalWrapper.svelte.d.ts +9 -0
- package/dist/radio-group/Radio.svelte +142 -0
- package/dist/radio-group/Radio.svelte.d.ts +35 -0
- package/dist/radio-group/RadioGroup.svelte +222 -0
- package/dist/radio-group/RadioGroup.svelte.d.ts +34 -0
- package/dist/radio-group/RadioOption.svelte +145 -0
- package/dist/radio-group/RadioOption.svelte.d.ts +37 -0
- package/dist/radio-group/contest.svelte.d.ts +30 -0
- package/dist/radio-group/contest.svelte.js +40 -0
- package/dist/radio-group/index.d.ts +3 -0
- package/dist/radio-group/index.js +3 -0
- package/dist/select/Select.svelte +112 -0
- package/dist/select/Select.svelte.d.ts +21 -0
- package/dist/select/index.d.ts +1 -0
- package/dist/select/index.js +1 -0
- package/dist/switch/Switch.svelte +27 -28
- package/dist/switch/Switch.svelte.d.ts +9 -42
- package/dist/switch/SwitchGroup.svelte +5 -5
- package/dist/switch/SwitchGroup.svelte.d.ts +8 -30
- package/dist/switch/index.d.ts +1 -1
- package/dist/switch/index.js +1 -1
- package/dist/tabs/Tab.svelte +28 -31
- package/dist/tabs/Tab.svelte.d.ts +8 -36
- package/dist/tabs/TabGroup.svelte +42 -264
- package/dist/tabs/TabGroup.svelte.d.ts +7 -57
- package/dist/tabs/TabList.svelte +13 -16
- package/dist/tabs/TabList.svelte.d.ts +8 -31
- package/dist/tabs/TabPanel.svelte +20 -20
- package/dist/tabs/TabPanel.svelte.d.ts +8 -38
- package/dist/tabs/TabPanels.svelte +11 -9
- package/dist/tabs/TabPanels.svelte.d.ts +8 -30
- package/dist/tabs/context.svelte.d.ts +31 -0
- package/dist/tabs/context.svelte.js +134 -0
- package/dist/tabs/index.d.ts +5 -5
- package/dist/tabs/index.js +4 -4
- package/dist/textarea/Textarea.svelte +24 -20
- package/dist/textarea/Textarea.svelte.d.ts +17 -29
- package/dist/textarea/index.d.ts +1 -1
- package/dist/textarea/index.js +1 -1
- package/dist/transition/InternalTransitionChild.svelte +36 -22
- package/dist/transition/InternalTransitionChild.svelte.d.ts +6 -37
- package/dist/transition/Transition.svelte +16 -17
- package/dist/transition/Transition.svelte.d.ts +8 -38
- package/dist/transition/TransitionChild.svelte +13 -12
- package/dist/transition/TransitionChild.svelte.d.ts +11 -38
- package/dist/transition/context.svelte.js +11 -11
- package/dist/transition/index.d.ts +2 -2
- package/dist/transition/index.js +2 -2
- package/dist/utils/DisabledProvider.svelte +10 -0
- package/dist/utils/DisabledProvider.svelte.d.ts +8 -0
- package/dist/utils/ElementOrComponent.svelte +58 -17
- package/dist/utils/ElementOrComponent.svelte.d.ts +19 -30
- package/dist/utils/StableCollection.svelte.d.ts +4 -18
- package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +32 -0
- package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte.d.ts +8 -0
- package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +94 -0
- package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte.d.ts +26 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.d.ts +6 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.js +158 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.d.ts +11 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.js +53 -0
- package/dist/utils/floating-ui/svelte/hooks/useId.svelte.d.ts +9 -0
- package/dist/utils/floating-ui/svelte/hooks/useId.svelte.js +28 -0
- package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.d.ts +23 -0
- package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.js +72 -0
- package/dist/utils/floating-ui/svelte/index.d.ts +5 -0
- package/dist/utils/floating-ui/svelte/index.js +5 -0
- package/dist/utils/floating-ui/svelte/inner.svelte.d.ts +83 -0
- package/dist/utils/floating-ui/svelte/inner.svelte.js +178 -0
- package/dist/utils/floating-ui/svelte/types.d.ts +114 -0
- package/dist/utils/floating-ui/svelte/utils/createPubSub.d.ts +5 -0
- package/dist/utils/floating-ui/svelte/utils/createPubSub.js +14 -0
- package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.d.ts +2 -0
- package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.js +13 -0
- package/dist/utils/floating-ui/svelte/utils/log.d.ts +2 -0
- package/dist/utils/floating-ui/svelte/utils/log.js +19 -0
- package/dist/utils/floating-ui/svelte/utils.d.ts +19 -0
- package/dist/utils/floating-ui/svelte/utils.js +136 -0
- package/dist/utils/floating-ui/svelte-dom/arrow.d.ts +22 -0
- package/dist/utils/floating-ui/svelte-dom/arrow.js +29 -0
- package/dist/utils/floating-ui/svelte-dom/index.d.ts +2 -0
- package/dist/utils/floating-ui/svelte-dom/index.js +2 -0
- package/dist/utils/floating-ui/svelte-dom/types.d.ts +80 -0
- package/dist/utils/floating-ui/svelte-dom/types.js +3 -0
- package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.d.ts +6 -0
- package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.js +183 -0
- package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.js +50 -0
- package/dist/utils/floating-ui/svelte-dom/utils/getDPR.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/getDPR.js +7 -0
- package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.js +5 -0
- package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.d.ts +4 -0
- package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.js +7 -0
- package/dist/utils/id.d.ts +1 -1
- package/dist/utils/id.js +1 -1
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/state.js +4 -4
- package/dist/utils/style.d.ts +2 -0
- package/dist/utils/style.js +6 -0
- package/dist/utils/types.d.ts +13 -19
- package/package.json +53 -53
- package/dist/combobox/Combobox.svelte +0 -53
- package/dist/combobox/Combobox.svelte.d.ts +0 -50
- package/dist/internal/HoistFormFields.svelte +0 -14
- package/dist/internal/HoistFormFields.svelte.d.ts +0 -21
- package/dist/internal/id.d.ts +0 -8
- package/dist/internal/id.js +0 -11
- package/dist/listbox/ListboxStates.d.ts +0 -12
- package/dist/listbox/ListboxStates.js +0 -15
- package/dist/utils/Generic.svelte +0 -56
- package/dist/utils/Generic.svelte.d.ts +0 -35
- package/dist/utils/alternative-types.d.ts +0 -21
- /package/dist/utils/{alternative-types.js → floating-ui/svelte/types.js} +0 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Props } from "../utils/types.js"
|
|
3
|
+
import { RenderFeatures } from "../utils/render.js"
|
|
4
|
+
|
|
5
|
+
const DEFAULT_PANEL_TAG = "div" as const
|
|
6
|
+
export type PanelRenderPropArg = {
|
|
7
|
+
open: boolean
|
|
8
|
+
close: (focusableElement?: HTMLElement) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static
|
|
12
|
+
|
|
13
|
+
type PanelPropsWeControl = "tabIndex"
|
|
14
|
+
|
|
15
|
+
export type PopoverPanelOwnProps = {
|
|
16
|
+
element?: HTMLElement
|
|
17
|
+
id?: string
|
|
18
|
+
focus?: boolean
|
|
19
|
+
anchor?: AnchorProps
|
|
20
|
+
portal?: boolean
|
|
21
|
+
modal?: boolean
|
|
22
|
+
transition?: boolean
|
|
23
|
+
|
|
24
|
+
// ItemsRenderFeatures
|
|
25
|
+
static?: boolean
|
|
26
|
+
unmount?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type PopoverPanelProps = Props<typeof DEFAULT_PANEL_TAG, PanelRenderPropArg, PopoverPanelOwnProps>
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script lang="ts">
|
|
33
|
+
import { useId } from "../hooks/use-id.js"
|
|
34
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
35
|
+
import { mergeProps } from "../utils/render.js"
|
|
36
|
+
import {
|
|
37
|
+
useFloatingPanel,
|
|
38
|
+
useFloatingPanelProps,
|
|
39
|
+
useResolvedAnchor,
|
|
40
|
+
type AnchorProps,
|
|
41
|
+
} from "../internal/floating.svelte.js"
|
|
42
|
+
import {
|
|
43
|
+
type PopoverAPIContext,
|
|
44
|
+
type PopoverPanelContext,
|
|
45
|
+
PopoverStates,
|
|
46
|
+
usePopoverAPIContext,
|
|
47
|
+
usePopoverContext,
|
|
48
|
+
} from "./context.svelte.js"
|
|
49
|
+
import { getOwnerDocument } from "../utils/owner.js"
|
|
50
|
+
import { clearOpenClosedContext, State, useOpenClosed } from "../internal/open-closed.js"
|
|
51
|
+
import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js"
|
|
52
|
+
import { useOnDisappear } from "../hooks/use-on-disappear.svelte.js"
|
|
53
|
+
import { useScrollLock } from "../hooks/use-scroll-lock.svelte.js"
|
|
54
|
+
import { Focus, focusIn, FocusResult, getFocusableElements } from "../utils/focus-management.js"
|
|
55
|
+
import { useElementSize } from "../hooks/use-element-size.svelte.js"
|
|
56
|
+
import { useTabDirection, Direction as TabDirection } from "../hooks/use-tab-direction.svelte.js"
|
|
57
|
+
import { match } from "../utils/match.js"
|
|
58
|
+
import { microTask } from "../utils/microTask.js"
|
|
59
|
+
import { setContext, untrack } from "svelte"
|
|
60
|
+
import Portal from "../portal/Portal.svelte"
|
|
61
|
+
import Hidden, { HiddenFeatures } from "../internal/Hidden.svelte"
|
|
62
|
+
|
|
63
|
+
let internalId = useId()
|
|
64
|
+
let {
|
|
65
|
+
element = $bindable(),
|
|
66
|
+
id = `headlessui-popover-panel-${internalId}`,
|
|
67
|
+
focus = false,
|
|
68
|
+
anchor: rawAnchor,
|
|
69
|
+
portal: theirPortal = false,
|
|
70
|
+
modal = false,
|
|
71
|
+
transition = false,
|
|
72
|
+
...theirProps
|
|
73
|
+
}: PopoverPanelProps = $props()
|
|
74
|
+
|
|
75
|
+
const context = usePopoverContext("PopoverPanel")
|
|
76
|
+
const api = usePopoverAPIContext("PopoverPanel")
|
|
77
|
+
const { close, isPortalled } = $derived(api)
|
|
78
|
+
|
|
79
|
+
const beforePanelSentinelId = `headlessui-focus-sentinel-before-${internalId}`
|
|
80
|
+
const afterPanelSentinelId = `headlessui-focus-sentinel-after-${internalId}`
|
|
81
|
+
|
|
82
|
+
const resolvedAnchor = useResolvedAnchor({
|
|
83
|
+
get anchor() {
|
|
84
|
+
return rawAnchor
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
const { anchor } = $derived(resolvedAnchor)
|
|
88
|
+
const floatingPanel = useFloatingPanel({
|
|
89
|
+
get placement() {
|
|
90
|
+
return anchor
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
const { setFloating, styles } = $derived(floatingPanel)
|
|
94
|
+
const getFloatingPanelProps = useFloatingPanelProps()
|
|
95
|
+
|
|
96
|
+
// Always enable `portal` functionality, when `anchor` is enabled
|
|
97
|
+
const portal = $derived(!!anchor || theirPortal)
|
|
98
|
+
|
|
99
|
+
$effect(() => {
|
|
100
|
+
if (anchor) setFloating(element ?? null)
|
|
101
|
+
untrack(() => context.setPanel(element))
|
|
102
|
+
})
|
|
103
|
+
const ownerDocument = $derived(getOwnerDocument(element))
|
|
104
|
+
|
|
105
|
+
$effect(() => {
|
|
106
|
+
id
|
|
107
|
+
return untrack(() => {
|
|
108
|
+
context.setPanelId(id)
|
|
109
|
+
return () => {
|
|
110
|
+
context.setPanelId(undefined)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const usesOpenClosedState = useOpenClosed()
|
|
116
|
+
const _transition = useTransition({
|
|
117
|
+
get enabled() {
|
|
118
|
+
return transition
|
|
119
|
+
},
|
|
120
|
+
get element() {
|
|
121
|
+
return element
|
|
122
|
+
},
|
|
123
|
+
get show() {
|
|
124
|
+
return usesOpenClosedState !== null
|
|
125
|
+
? (usesOpenClosedState.value & State.Open) === State.Open
|
|
126
|
+
: context.popoverState === PopoverStates.Open
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
const { visible, data: transitionData } = $derived(_transition)
|
|
130
|
+
|
|
131
|
+
// Ensure we close the popover as soon as the button becomes hidden
|
|
132
|
+
useOnDisappear({
|
|
133
|
+
get enabled() {
|
|
134
|
+
return visible
|
|
135
|
+
},
|
|
136
|
+
get ref() {
|
|
137
|
+
return context.button
|
|
138
|
+
},
|
|
139
|
+
ondisappear: () => {
|
|
140
|
+
context.closePopover()
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// Enable scroll locking when the popover is visible, and `modal` is enabled
|
|
145
|
+
const scrollLockEnabled = $derived(context.__demoMode ? false : modal && visible)
|
|
146
|
+
useScrollLock({
|
|
147
|
+
get enabled() {
|
|
148
|
+
return scrollLockEnabled
|
|
149
|
+
},
|
|
150
|
+
get ownerDocument() {
|
|
151
|
+
return ownerDocument
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
156
|
+
switch (event.key) {
|
|
157
|
+
case "Escape":
|
|
158
|
+
if (context.popoverState !== PopoverStates.Open) return
|
|
159
|
+
if (!element) return
|
|
160
|
+
if (ownerDocument?.activeElement && !element.contains(ownerDocument.activeElement)) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
event.preventDefault()
|
|
164
|
+
event.stopPropagation()
|
|
165
|
+
context.closePopover()
|
|
166
|
+
context.button?.focus()
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Unlink on "unmount" children
|
|
172
|
+
$effect(() => {
|
|
173
|
+
if (theirProps.static) return
|
|
174
|
+
|
|
175
|
+
if (context.popoverState === PopoverStates.Closed && (theirProps.unmount ?? true)) {
|
|
176
|
+
context.setPanel(undefined)
|
|
177
|
+
}
|
|
178
|
+
}) //, [state.popoverState, props.unmount, props.static, dispatch])
|
|
179
|
+
|
|
180
|
+
// Move focus within panel
|
|
181
|
+
$effect(() => {
|
|
182
|
+
if (context.__demoMode) return
|
|
183
|
+
if (!focus) return
|
|
184
|
+
if (context.popoverState !== PopoverStates.Open) return
|
|
185
|
+
if (!element) return
|
|
186
|
+
|
|
187
|
+
const activeElement = ownerDocument?.activeElement as HTMLElement
|
|
188
|
+
if (element.contains(activeElement)) return // Already focused within Dialog
|
|
189
|
+
|
|
190
|
+
focusIn(element, Focus.First)
|
|
191
|
+
}) //, [state.__demoMode, focus, internalPanelRef.current, state.popoverState])
|
|
192
|
+
|
|
193
|
+
const slot = $derived({
|
|
194
|
+
open: context.popoverState === PopoverStates.Open,
|
|
195
|
+
close,
|
|
196
|
+
} satisfies PanelRenderPropArg)
|
|
197
|
+
|
|
198
|
+
const buttonSize = useElementSize({
|
|
199
|
+
get element() {
|
|
200
|
+
return context.button ?? null
|
|
201
|
+
},
|
|
202
|
+
unit: true,
|
|
203
|
+
})
|
|
204
|
+
const ourProps: Record<string, any> = $derived(
|
|
205
|
+
mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
206
|
+
id,
|
|
207
|
+
onkeydown: handleKeyDown,
|
|
208
|
+
onblur:
|
|
209
|
+
focus && context.popoverState === PopoverStates.Open
|
|
210
|
+
? (event: FocusEvent) => {
|
|
211
|
+
let el = event.relatedTarget as HTMLElement
|
|
212
|
+
if (!el) return
|
|
213
|
+
if (!element) return
|
|
214
|
+
if (element.contains(el)) return
|
|
215
|
+
|
|
216
|
+
context.closePopover()
|
|
217
|
+
|
|
218
|
+
if (context.beforePanelSentinel?.contains?.(el) || context.afterPanelSentinel?.contains?.(el)) {
|
|
219
|
+
el.focus({ preventScroll: true })
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
: undefined,
|
|
223
|
+
tabIndex: -1,
|
|
224
|
+
style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; "),
|
|
225
|
+
...transitionDataAttributes(transitionData),
|
|
226
|
+
})
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
const direction = useTabDirection()
|
|
230
|
+
const handleBeforeFocus = () => {
|
|
231
|
+
let el = element as HTMLElement
|
|
232
|
+
if (!el) return
|
|
233
|
+
|
|
234
|
+
function run() {
|
|
235
|
+
match(direction.current, {
|
|
236
|
+
[TabDirection.Forwards]: () => {
|
|
237
|
+
// Try to focus the first thing in the panel. But if that fails (e.g.: there are no
|
|
238
|
+
// focusable elements, then we can move outside of the panel)
|
|
239
|
+
let result = focusIn(el, Focus.First)
|
|
240
|
+
if (result === FocusResult.Error) {
|
|
241
|
+
context.afterPanelSentinel?.focus()
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
[TabDirection.Backwards]: () => {
|
|
245
|
+
// Coming from the PopoverPanel (which is portalled to somewhere else). Let's redirect
|
|
246
|
+
// the focus to the PopoverButton again.
|
|
247
|
+
context.button?.focus({ preventScroll: true })
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// TODO: Cleanup once we are using real browser tests
|
|
253
|
+
if (process.env.NODE_ENV === "test") {
|
|
254
|
+
microTask(run)
|
|
255
|
+
} else {
|
|
256
|
+
run()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const handleAfterFocus = () => {
|
|
261
|
+
let el = element as HTMLElement
|
|
262
|
+
if (!el) return
|
|
263
|
+
|
|
264
|
+
function run() {
|
|
265
|
+
match(direction.current, {
|
|
266
|
+
[TabDirection.Forwards]: () => {
|
|
267
|
+
if (!context.button) return
|
|
268
|
+
|
|
269
|
+
const elements = getFocusableElements()
|
|
270
|
+
|
|
271
|
+
const idx = elements.indexOf(context.button)
|
|
272
|
+
const before = elements.slice(0, idx + 1)
|
|
273
|
+
const after = elements.slice(idx + 1)
|
|
274
|
+
|
|
275
|
+
const combined = [...after, ...before]
|
|
276
|
+
|
|
277
|
+
// Ignore sentinel buttons and items inside the panel
|
|
278
|
+
for (const element of combined.slice()) {
|
|
279
|
+
if (element.dataset.headlessuiFocusGuard === "true" || element?.contains(element)) {
|
|
280
|
+
let idx = combined.indexOf(element)
|
|
281
|
+
if (idx !== -1) combined.splice(idx, 1)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
focusIn(combined, Focus.First, { sorted: false })
|
|
286
|
+
},
|
|
287
|
+
[TabDirection.Backwards]: () => {
|
|
288
|
+
// Try to focus the first thing in the panel. But if that fails (e.g.: there are no
|
|
289
|
+
// focusable elements, then we can move outside of the panel)
|
|
290
|
+
let result = focusIn(el, Focus.Previous)
|
|
291
|
+
if (result === FocusResult.Error) {
|
|
292
|
+
context.button?.focus()
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// TODO: Cleanup once we are using real browser tests
|
|
299
|
+
if (process.env.NODE_ENV === "test") {
|
|
300
|
+
microTask(run)
|
|
301
|
+
} else {
|
|
302
|
+
run()
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
clearOpenClosedContext()
|
|
307
|
+
setContext<PopoverPanelContext>("PopoverPanelContext", {
|
|
308
|
+
get value() {
|
|
309
|
+
return id
|
|
310
|
+
},
|
|
311
|
+
})
|
|
312
|
+
setContext<PopoverAPIContext>("PopoverAPIContext", {
|
|
313
|
+
get close() {
|
|
314
|
+
return close
|
|
315
|
+
},
|
|
316
|
+
get isPortalled() {
|
|
317
|
+
return isPortalled
|
|
318
|
+
},
|
|
319
|
+
})
|
|
320
|
+
</script>
|
|
321
|
+
|
|
322
|
+
<Portal enabled={portal ? theirProps.static || visible : false}>
|
|
323
|
+
{#if visible && isPortalled}
|
|
324
|
+
<Hidden asChild id={beforePanelSentinelId} features={HiddenFeatures.Focusable}>
|
|
325
|
+
{#snippet children({ props })}
|
|
326
|
+
<button
|
|
327
|
+
{...props}
|
|
328
|
+
type="button"
|
|
329
|
+
data-headlessui-focus-guard
|
|
330
|
+
onfocus={handleBeforeFocus}
|
|
331
|
+
bind:this={context.beforePanelSentinel}>‌</button
|
|
332
|
+
>
|
|
333
|
+
{/snippet}
|
|
334
|
+
</Hidden>
|
|
335
|
+
{/if}
|
|
336
|
+
<ElementOrComponent
|
|
337
|
+
{ourProps}
|
|
338
|
+
{theirProps}
|
|
339
|
+
slots={slot}
|
|
340
|
+
defaultTag={DEFAULT_PANEL_TAG}
|
|
341
|
+
features={PanelRenderFeatures}
|
|
342
|
+
{visible}
|
|
343
|
+
name="PopoverPanel"
|
|
344
|
+
bind:element
|
|
345
|
+
/>
|
|
346
|
+
{#if visible && isPortalled}
|
|
347
|
+
<Hidden asChild id={afterPanelSentinelId} features={HiddenFeatures.Focusable}>
|
|
348
|
+
{#snippet children({ props })}
|
|
349
|
+
<button
|
|
350
|
+
{...props}
|
|
351
|
+
type="button"
|
|
352
|
+
data-headlessui-focus-guard
|
|
353
|
+
onfocus={handleAfterFocus}
|
|
354
|
+
bind:this={context.afterPanelSentinel}>‌</button
|
|
355
|
+
>
|
|
356
|
+
{/snippet}
|
|
357
|
+
</Hidden>
|
|
358
|
+
{/if}
|
|
359
|
+
</Portal>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Props } from "../utils/types.js";
|
|
2
|
+
declare const DEFAULT_PANEL_TAG: "div";
|
|
3
|
+
export type PanelRenderPropArg = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
close: (focusableElement?: HTMLElement) => void;
|
|
6
|
+
};
|
|
7
|
+
export type PopoverPanelOwnProps = {
|
|
8
|
+
element?: HTMLElement;
|
|
9
|
+
id?: string;
|
|
10
|
+
focus?: boolean;
|
|
11
|
+
anchor?: AnchorProps;
|
|
12
|
+
portal?: boolean;
|
|
13
|
+
modal?: boolean;
|
|
14
|
+
transition?: boolean;
|
|
15
|
+
static?: boolean;
|
|
16
|
+
unmount?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type PopoverPanelProps = Props<typeof DEFAULT_PANEL_TAG, PanelRenderPropArg, PopoverPanelOwnProps>;
|
|
19
|
+
import { type AnchorProps } from "../internal/floating.svelte.js";
|
|
20
|
+
declare const PopoverPanel: import("svelte").Component<PopoverPanelProps, {}, "element">;
|
|
21
|
+
type PopoverPanel = ReturnType<typeof PopoverPanel>;
|
|
22
|
+
export default PopoverPanel;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { MouseEventHandler } from "svelte/elements";
|
|
2
|
+
export type MouseEvent<T extends EventTarget> = Parameters<MouseEventHandler<T>>[0];
|
|
3
|
+
export declare enum PopoverStates {
|
|
4
|
+
Open = 0,
|
|
5
|
+
Closed = 1
|
|
6
|
+
}
|
|
7
|
+
export interface StateDefinition {
|
|
8
|
+
popoverState: PopoverStates;
|
|
9
|
+
buttons: symbol[];
|
|
10
|
+
button?: HTMLElement;
|
|
11
|
+
buttonId?: string;
|
|
12
|
+
panel?: HTMLElement;
|
|
13
|
+
panelId?: string;
|
|
14
|
+
beforePanelSentinel?: HTMLButtonElement;
|
|
15
|
+
afterPanelSentinel?: HTMLButtonElement;
|
|
16
|
+
afterButtonSentinel?: HTMLButtonElement;
|
|
17
|
+
__demoMode: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface ActionDefinition {
|
|
20
|
+
togglePopover(): void;
|
|
21
|
+
closePopover(): void;
|
|
22
|
+
setButton(button: HTMLElement): void;
|
|
23
|
+
setButtonId(buttonId: string | undefined): void;
|
|
24
|
+
setPanel(panel?: HTMLElement): void;
|
|
25
|
+
setPanelId(panelId?: string): void;
|
|
26
|
+
}
|
|
27
|
+
export type PopoverContext = StateDefinition & ActionDefinition;
|
|
28
|
+
export declare const createPopoverContext: (initialState: StateDefinition) => PopoverContext;
|
|
29
|
+
export declare function usePopoverContext(component: string): PopoverContext;
|
|
30
|
+
export type PopoverAPIContext = {
|
|
31
|
+
close(focusableElement?: HTMLElement | MouseEvent<HTMLElement>): void;
|
|
32
|
+
isPortalled: boolean;
|
|
33
|
+
};
|
|
34
|
+
export declare function usePopoverAPIContext(component: string): PopoverAPIContext;
|
|
35
|
+
export type PopoverGroupContext = {
|
|
36
|
+
registerPopover(registerBag: PopoverRegisterBag): void;
|
|
37
|
+
unregisterPopover(registerBag: PopoverRegisterBag): void;
|
|
38
|
+
isFocusWithinPopoverGroup(): boolean;
|
|
39
|
+
closeOthers(buttonId: string): void;
|
|
40
|
+
};
|
|
41
|
+
export declare function usePopoverGroupContext(): PopoverGroupContext | undefined;
|
|
42
|
+
export type PopoverPanelContext = {
|
|
43
|
+
value: string;
|
|
44
|
+
};
|
|
45
|
+
export declare function usePopoverPanelContext(): PopoverPanelContext | undefined;
|
|
46
|
+
export interface PopoverRegisterBag {
|
|
47
|
+
buttonId?: string;
|
|
48
|
+
panelId?: string;
|
|
49
|
+
close(): void;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getContext, setContext } from "svelte";
|
|
2
|
+
export var PopoverStates;
|
|
3
|
+
(function (PopoverStates) {
|
|
4
|
+
PopoverStates[PopoverStates["Open"] = 0] = "Open";
|
|
5
|
+
PopoverStates[PopoverStates["Closed"] = 1] = "Closed";
|
|
6
|
+
})(PopoverStates || (PopoverStates = {}));
|
|
7
|
+
export const createPopoverContext = (initialState) => {
|
|
8
|
+
const _state = $state(initialState);
|
|
9
|
+
const context = {
|
|
10
|
+
get popoverState() {
|
|
11
|
+
return _state.popoverState;
|
|
12
|
+
},
|
|
13
|
+
get buttons() {
|
|
14
|
+
return _state.buttons;
|
|
15
|
+
},
|
|
16
|
+
get button() {
|
|
17
|
+
return _state.button;
|
|
18
|
+
},
|
|
19
|
+
get buttonId() {
|
|
20
|
+
return _state.buttonId;
|
|
21
|
+
},
|
|
22
|
+
get panel() {
|
|
23
|
+
return _state.panel;
|
|
24
|
+
},
|
|
25
|
+
get panelId() {
|
|
26
|
+
return _state.panelId;
|
|
27
|
+
},
|
|
28
|
+
get beforePanelSentinel() {
|
|
29
|
+
return _state.beforePanelSentinel;
|
|
30
|
+
},
|
|
31
|
+
set beforePanelSentinel(value) {
|
|
32
|
+
_state.beforePanelSentinel = value;
|
|
33
|
+
},
|
|
34
|
+
get afterPanelSentinel() {
|
|
35
|
+
return _state.afterPanelSentinel;
|
|
36
|
+
},
|
|
37
|
+
set afterPanelSentinel(value) {
|
|
38
|
+
_state.afterPanelSentinel = value;
|
|
39
|
+
},
|
|
40
|
+
get afterButtonSentinel() {
|
|
41
|
+
return _state.afterButtonSentinel;
|
|
42
|
+
},
|
|
43
|
+
set afterButtonSentinel(value) {
|
|
44
|
+
_state.afterButtonSentinel = value;
|
|
45
|
+
},
|
|
46
|
+
get __demoMode() {
|
|
47
|
+
return _state.__demoMode;
|
|
48
|
+
},
|
|
49
|
+
togglePopover() {
|
|
50
|
+
_state.__demoMode = false;
|
|
51
|
+
_state.popoverState = _state.popoverState === PopoverStates.Closed ? PopoverStates.Open : PopoverStates.Closed;
|
|
52
|
+
},
|
|
53
|
+
closePopover() {
|
|
54
|
+
if (_state.popoverState === PopoverStates.Closed)
|
|
55
|
+
return;
|
|
56
|
+
_state.__demoMode = false;
|
|
57
|
+
_state.popoverState = PopoverStates.Closed;
|
|
58
|
+
},
|
|
59
|
+
setButton(button) {
|
|
60
|
+
if (_state.button === button)
|
|
61
|
+
return;
|
|
62
|
+
_state.button = button;
|
|
63
|
+
},
|
|
64
|
+
setButtonId(buttonId) {
|
|
65
|
+
if (_state.buttonId === buttonId)
|
|
66
|
+
return;
|
|
67
|
+
_state.buttonId = buttonId;
|
|
68
|
+
},
|
|
69
|
+
setPanel(panel) {
|
|
70
|
+
if (_state.panel === panel)
|
|
71
|
+
return;
|
|
72
|
+
_state.panel = panel;
|
|
73
|
+
},
|
|
74
|
+
setPanelId(panelId) {
|
|
75
|
+
if (_state.panelId === panelId)
|
|
76
|
+
return;
|
|
77
|
+
_state.panelId = panelId;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
setContext("PopoverContext", context);
|
|
81
|
+
return context;
|
|
82
|
+
};
|
|
83
|
+
export function usePopoverContext(component) {
|
|
84
|
+
const context = getContext("PopoverContext");
|
|
85
|
+
if (!context) {
|
|
86
|
+
const err = new Error(`<${component} /> is missing a parent <Popover /> component.`);
|
|
87
|
+
if (Error.captureStackTrace)
|
|
88
|
+
Error.captureStackTrace(err, usePopoverContext);
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
return context;
|
|
92
|
+
}
|
|
93
|
+
export function usePopoverAPIContext(component) {
|
|
94
|
+
const context = getContext("PopoverAPIContext");
|
|
95
|
+
if (!context) {
|
|
96
|
+
const err = new Error(`<${component} /> is missing a parent <Popover /> component.`);
|
|
97
|
+
if (Error.captureStackTrace)
|
|
98
|
+
Error.captureStackTrace(err, usePopoverAPIContext);
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
}
|
|
103
|
+
export function usePopoverGroupContext() {
|
|
104
|
+
return getContext("PopoverGroupContext");
|
|
105
|
+
}
|
|
106
|
+
export function usePopoverPanelContext() {
|
|
107
|
+
return getContext("PopoverPanelContext");
|
|
108
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Popover, type PopoverProps, type PopoverRenderPropArg as PopoverSlot, type PopoverOwnProps, } from "./Popover.svelte";
|
|
2
|
+
export { default as PopoverBackdrop, type PopoverBackdropProps, type BackdropRenderPropArg as PopoverBackdropSlot, type PopoverBackdropOwnProps, } from "./PopoverBackdrop.svelte";
|
|
3
|
+
export { default as PopoverButton, type PopoverButtonProps, type PopoverButtonSlot, type PopoverButtonOwnProps, } from "./PopoverButton.svelte";
|
|
4
|
+
export { default as PopoverGroup, type PopoverGroupProps, type PopoverGroupOwnProps } from "./PopoverGroup.svelte";
|
|
5
|
+
export { default as PopoverPanel, type PopoverPanelProps, type PanelRenderPropArg as PopoverPanelSlot, type PopoverPanelOwnProps, } from "./PopoverPanel.svelte";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Popover, } from "./Popover.svelte";
|
|
2
|
+
export { default as PopoverBackdrop, } from "./PopoverBackdrop.svelte";
|
|
3
|
+
export { default as PopoverButton, } from "./PopoverButton.svelte";
|
|
4
|
+
export { default as PopoverGroup } from "./PopoverGroup.svelte";
|
|
5
|
+
export { default as PopoverPanel, } from "./PopoverPanel.svelte";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { getOwnerDocument } from "../utils/owner.js"
|
|
4
4
|
import { getContext, onMount, setContext } from "svelte"
|
|
5
5
|
import { env } from "../utils/env.js"
|
|
6
|
-
import type {
|
|
6
|
+
import type { Props } from "../utils/types.js"
|
|
7
7
|
import type { PortalGroupContext } from "./PortalGroup.svelte"
|
|
8
8
|
|
|
9
9
|
function usePortalTarget(options: { element: HTMLElement | null }): { readonly target: HTMLElement | null } {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
|
|
57
57
|
// ---
|
|
58
58
|
|
|
59
|
-
type PortalParentContext = {
|
|
59
|
+
export type PortalParentContext = {
|
|
60
60
|
register: (portal: HTMLElement) => () => void
|
|
61
61
|
unregister: (portal: HTMLElement) => void
|
|
62
62
|
readonly portals: HTMLElement[]
|
|
@@ -85,7 +85,6 @@
|
|
|
85
85
|
return portals
|
|
86
86
|
},
|
|
87
87
|
}
|
|
88
|
-
setContext("PortalParentContext", context)
|
|
89
88
|
|
|
90
89
|
return context
|
|
91
90
|
}
|
|
@@ -93,27 +92,27 @@
|
|
|
93
92
|
// ---
|
|
94
93
|
|
|
95
94
|
export const DEFAULT_PORTAL_TAG = "div"
|
|
96
|
-
type PortalRenderPropArg = {}
|
|
95
|
+
export type PortalRenderPropArg = {}
|
|
97
96
|
type PortalPropsWeControl = never
|
|
98
97
|
|
|
99
|
-
export type PortalProps
|
|
100
|
-
|
|
98
|
+
export type PortalProps = Props<
|
|
99
|
+
typeof DEFAULT_PORTAL_TAG,
|
|
101
100
|
PortalRenderPropArg,
|
|
102
|
-
PortalPropsWeControl,
|
|
103
101
|
{
|
|
102
|
+
element?: HTMLElement
|
|
104
103
|
enabled?: boolean
|
|
105
104
|
}
|
|
106
105
|
>
|
|
107
106
|
</script>
|
|
108
107
|
|
|
109
|
-
<script lang="ts"
|
|
108
|
+
<script lang="ts">
|
|
110
109
|
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
111
110
|
|
|
112
|
-
let {
|
|
111
|
+
let { element = $bindable(), ...theirProps }: PortalProps = $props()
|
|
113
112
|
|
|
114
113
|
const portalTarget = usePortalTarget({
|
|
115
114
|
get element() {
|
|
116
|
-
return
|
|
115
|
+
return element ?? null
|
|
117
116
|
},
|
|
118
117
|
})
|
|
119
118
|
const { target } = $derived(portalTarget)
|
|
@@ -121,24 +120,24 @@
|
|
|
121
120
|
//const ready = useServerHandoffComplete()
|
|
122
121
|
|
|
123
122
|
$effect(() => {
|
|
124
|
-
if (!target || !
|
|
123
|
+
if (!target || !element) return
|
|
125
124
|
|
|
126
125
|
// Element already exists in target, always calling target.appendChild(element) will cause a
|
|
127
126
|
// brief unmount/remount.
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
target.appendChild(
|
|
127
|
+
if (element.parentNode !== target) {
|
|
128
|
+
element.setAttribute("data-headlessui-portal", "")
|
|
129
|
+
target.appendChild(element)
|
|
131
130
|
}
|
|
132
131
|
})
|
|
133
132
|
|
|
134
133
|
onMount(() => {
|
|
135
|
-
if (parent) parent.register(
|
|
134
|
+
if (parent) parent.register(element!)
|
|
136
135
|
|
|
137
136
|
return () => {
|
|
138
|
-
if (!target || !
|
|
137
|
+
if (!target || !element) return
|
|
139
138
|
|
|
140
|
-
if (
|
|
141
|
-
target.removeChild(
|
|
139
|
+
if (element instanceof Node && target.contains(element)) {
|
|
140
|
+
target.removeChild(element)
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
if (target.childNodes.length <= 0) {
|
|
@@ -149,5 +148,5 @@
|
|
|
149
148
|
</script>
|
|
150
149
|
|
|
151
150
|
{#if target}
|
|
152
|
-
<ElementOrComponent {theirProps} defaultTag={DEFAULT_PORTAL_TAG} name="InternalPortal" bind:
|
|
151
|
+
<ElementOrComponent {theirProps} defaultTag={DEFAULT_PORTAL_TAG} name="InternalPortal" bind:element />
|
|
153
152
|
{/if}
|