@pzerelles/headlessui-svelte 2.1.2-next.2 → 2.1.2-next.4
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 +84 -54
- package/dist/checkbox/Checkbox.svelte +174 -120
- package/dist/close-button/CloseButton.svelte +12 -6
- package/dist/combobox/Combobox.svelte +50 -3
- package/dist/data-interactive/DataInteractive.svelte +57 -29
- package/dist/description/Description.svelte +32 -21
- package/dist/dialog/Dialog.svelte +69 -34
- package/dist/dialog/DialogBackdrop.svelte +29 -12
- package/dist/dialog/DialogPanel.svelte +49 -26
- package/dist/dialog/DialogTitle.svelte +38 -23
- package/dist/dialog/InternalDialog.svelte +263 -202
- package/dist/field/Field.svelte +49 -26
- package/dist/fieldset/Fieldset.svelte +50 -29
- package/dist/focus-trap/FocusTrap.svelte +436 -290
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/input/Input.svelte +85 -53
- package/dist/internal/FocusSentinel.svelte +16 -8
- package/dist/internal/ForcePortalRoot.svelte +7 -3
- package/dist/internal/FormFields.svelte +31 -20
- package/dist/internal/FormResolver.svelte +20 -15
- package/dist/internal/Hidden.svelte +44 -27
- package/dist/internal/Hidden.svelte.d.ts +2 -5
- package/dist/internal/HiddenFeatures.d.ts +5 -0
- package/dist/internal/HiddenFeatures.js +9 -0
- package/dist/internal/HoistFormFields.svelte +7 -4
- package/dist/internal/MainTreeProvider.svelte +89 -36
- package/dist/internal/Portal.svelte +18 -14
- package/dist/label/Label.svelte +91 -57
- package/dist/legend/Legend.svelte +18 -3
- package/dist/listbox/Listbox.svelte +600 -409
- package/dist/listbox/ListboxButton.svelte +176 -127
- package/dist/listbox/ListboxOption.svelte +166 -125
- package/dist/listbox/ListboxOptions.svelte +340 -244
- package/dist/listbox/ListboxSelectedOption.svelte +38 -15
- package/dist/menu/Menu.svelte +307 -218
- package/dist/menu/MenuButton.svelte +157 -115
- package/dist/menu/MenuHeading.svelte +34 -14
- package/dist/menu/MenuItem.svelte +145 -107
- package/dist/menu/MenuItems.svelte +298 -224
- package/dist/menu/MenuSection.svelte +26 -9
- package/dist/menu/MenuSeparator.svelte +20 -4
- package/dist/portal/InternalPortal.svelte +141 -85
- package/dist/portal/Portal.svelte +5 -2
- package/dist/portal/PortalGroup.svelte +30 -9
- package/dist/switch/Switch.svelte +179 -122
- package/dist/switch/Switch.svelte.d.ts +4 -4
- package/dist/switch/SwitchGroup.svelte +44 -31
- package/dist/tabs/Tab.svelte +195 -143
- package/dist/tabs/TabGroup.svelte +292 -205
- package/dist/tabs/TabList.svelte +31 -11
- package/dist/tabs/TabPanel.svelte +68 -43
- package/dist/tabs/TabPanels.svelte +18 -7
- package/dist/textarea/Textarea.svelte +97 -0
- package/dist/textarea/Textarea.svelte.d.ts +47 -0
- package/dist/textarea/index.d.ts +1 -0
- package/dist/textarea/index.js +1 -0
- package/dist/transition/InternalTransitionChild.svelte +259 -170
- package/dist/transition/Transition.svelte +96 -66
- package/dist/transition/TransitionChild.svelte +31 -11
- package/dist/utils/ElementOrComponent.svelte +44 -23
- package/dist/utils/Generic.svelte +29 -17
- package/dist/utils/StableCollection.svelte +54 -36
- package/package.json +10 -10
|
@@ -1,178 +1,267 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
props.children !== void 0
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
</script>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { compact, RenderStrategy } from "../utils/render.js"
|
|
3
|
+
import type { ElementType } from "../utils/types.js"
|
|
4
|
+
import { onMount, setContext, untrack } from "svelte"
|
|
5
|
+
import {
|
|
6
|
+
hasChildren,
|
|
7
|
+
TreeStates,
|
|
8
|
+
useNesting,
|
|
9
|
+
useParentNesting,
|
|
10
|
+
useTransitionContext,
|
|
11
|
+
type NestingContextValues,
|
|
12
|
+
type TransitionDirection,
|
|
13
|
+
} from "./context.svelte.js"
|
|
14
|
+
import type { TransitionRootProps } from "./Transition.svelte"
|
|
15
|
+
import { match } from "../utils/match.js"
|
|
16
|
+
import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js"
|
|
17
|
+
import { classNames } from "../utils/class-names.js"
|
|
18
|
+
import { createOpenClosedContext, State } from "../internal/open-closed.js"
|
|
19
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
20
|
+
import { DEFAULT_TRANSITION_CHILD_TAG, type TransitionChildProps } from "./TransitionChild.svelte"
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const { register, unregister } = $derived(parentNesting);
|
|
56
|
-
onMount(() => {
|
|
57
|
-
if (requiresRef) {
|
|
58
|
-
container.current = ref ?? null;
|
|
59
|
-
containerElement = ref;
|
|
60
|
-
}
|
|
61
|
-
return register(container);
|
|
62
|
-
});
|
|
63
|
-
$effect(() => {
|
|
64
|
-
if (strategy !== RenderStrategy.Hidden) return;
|
|
65
|
-
if (!container.current) return;
|
|
66
|
-
if (show && _state !== TreeStates.Visible) {
|
|
67
|
-
_state = TreeStates.Visible;
|
|
68
|
-
return;
|
|
22
|
+
/**
|
|
23
|
+
* Check if we should forward the ref to the child element or not. This is to
|
|
24
|
+
* prevent crashes when the `as` prop is a Fragment _and_ the component just acts
|
|
25
|
+
* as a state container (aka, there is no actual transition happening).
|
|
26
|
+
*
|
|
27
|
+
* E.g.:
|
|
28
|
+
*
|
|
29
|
+
* ```tsx
|
|
30
|
+
* <Transition show={true}>
|
|
31
|
+
* <Transition.Child enter="duration-100"><div>Child 1</div></Transition.Child>
|
|
32
|
+
* <Transition.Child enter="duration-200"><div>Child 2</div></Transition.Child>
|
|
33
|
+
* </Transition>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* In this scenario, the child components are transitioning, but the
|
|
37
|
+
* `Transition` parent, which is a `Fragment`, is not. So we should not forward
|
|
38
|
+
* the ref to the `Fragment`.
|
|
39
|
+
*/
|
|
40
|
+
export function shouldForwardRef<TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG>(
|
|
41
|
+
props: TransitionRootProps<TTag>
|
|
42
|
+
) {
|
|
43
|
+
return (
|
|
44
|
+
// If we have any of the enter/leave classes
|
|
45
|
+
Boolean(props.enter || props.enterFrom || props.enterTo || props.leave || props.leaveFrom || props.leaveTo) ||
|
|
46
|
+
// If the `as` prop is not a Fragment
|
|
47
|
+
(props.as ?? DEFAULT_TRANSITION_CHILD_TAG) !== "svelte:fragment" ||
|
|
48
|
+
// If we have a single child, then we can forward the ref directly
|
|
49
|
+
props.children !== undefined
|
|
50
|
+
)
|
|
69
51
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">
|
|
55
|
+
let { ref = $bindable(), ..._props }: { as?: TTag } & TransitionChildProps<TTag> = $props()
|
|
56
|
+
const {
|
|
57
|
+
// Whether or not to enable transitions on the current element (by exposing
|
|
58
|
+
// transition data). When set to false, the `Transition` component still
|
|
59
|
+
// acts as a transition boundary for `TransitionChild` components.
|
|
60
|
+
transition = true,
|
|
61
|
+
|
|
62
|
+
// Event "handlers"
|
|
63
|
+
beforeEnter,
|
|
64
|
+
afterEnter,
|
|
65
|
+
beforeLeave,
|
|
66
|
+
afterLeave,
|
|
67
|
+
|
|
68
|
+
// Class names
|
|
69
|
+
enter,
|
|
70
|
+
enterFrom,
|
|
71
|
+
enterTo,
|
|
72
|
+
entered,
|
|
73
|
+
leave,
|
|
74
|
+
leaveFrom,
|
|
75
|
+
leaveTo,
|
|
76
|
+
|
|
77
|
+
...theirProps
|
|
78
|
+
} = $derived(_props)
|
|
79
|
+
let containerElement = $state<HTMLElement>()
|
|
80
|
+
let container = $state<{ current: HTMLElement | null }>({ current: null })
|
|
81
|
+
const requiresRef = $derived(shouldForwardRef(_props))
|
|
82
|
+
|
|
83
|
+
const strategy = $derived((theirProps.unmount ?? true) ? RenderStrategy.Unmount : RenderStrategy.Hidden)
|
|
84
|
+
|
|
85
|
+
const _transitionContext = useTransitionContext()
|
|
86
|
+
const { show, appear, initial } = $derived(_transitionContext)
|
|
87
|
+
|
|
88
|
+
let _state = $state(untrack(() => show) ? TreeStates.Visible : TreeStates.Hidden)
|
|
89
|
+
|
|
90
|
+
const parentNesting = useParentNesting()
|
|
91
|
+
const { register, unregister } = $derived(parentNesting)
|
|
92
|
+
|
|
93
|
+
onMount(() => {
|
|
94
|
+
if (requiresRef) {
|
|
95
|
+
container.current = ref ?? null
|
|
96
|
+
containerElement = ref
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return register(container)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
$effect(() => {
|
|
103
|
+
// If we are in another mode than the Hidden mode then ignore
|
|
104
|
+
if (strategy !== RenderStrategy.Hidden) return
|
|
105
|
+
if (!container.current) return
|
|
106
|
+
|
|
107
|
+
// Make sure that we are visible
|
|
108
|
+
if (show && _state !== TreeStates.Visible) {
|
|
109
|
+
_state = TreeStates.Visible
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
match(_state, {
|
|
114
|
+
[TreeStates.Hidden]: () => unregister(container),
|
|
115
|
+
[TreeStates.Visible]: () => register(container),
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
//[state, container, register, unregister, show, strategy]
|
|
119
|
+
|
|
120
|
+
$effect(() => {
|
|
121
|
+
if (!requiresRef) return
|
|
122
|
+
|
|
123
|
+
if (_state === TreeStates.Visible && container.current === null) {
|
|
124
|
+
throw new Error("Did you forget to passthrough the `ref` to the actual DOM node?")
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// Skipping initial transition
|
|
129
|
+
const skip = $derived(initial && !appear)
|
|
130
|
+
const immediate = $derived(appear && show && initial)
|
|
131
|
+
|
|
132
|
+
let isTransitioning = $state(false)
|
|
133
|
+
|
|
134
|
+
let nesting = useNesting({
|
|
135
|
+
done: () => {
|
|
136
|
+
// When all children have been unmounted we can only hide ourselves if and
|
|
137
|
+
// only if we are not transitioning ourselves. Otherwise we would unmount
|
|
138
|
+
// before the transitions are finished.
|
|
139
|
+
if (isTransitioning) return
|
|
140
|
+
|
|
141
|
+
_state = TreeStates.Hidden
|
|
142
|
+
unregister(container)
|
|
143
|
+
},
|
|
144
|
+
get parent() {
|
|
145
|
+
return parentNesting
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const start = (show: boolean) => {
|
|
150
|
+
isTransitioning = true
|
|
151
|
+
const direction: TransitionDirection = show ? "enter" : "leave"
|
|
152
|
+
|
|
153
|
+
nesting.onStart(container, direction, (direction) => {
|
|
154
|
+
if (direction === "enter") beforeEnter?.()
|
|
155
|
+
else if (direction === "leave") beforeLeave?.()
|
|
156
|
+
})
|
|
92
157
|
}
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (direction === "leave" && !hasChildren(nesting)) {
|
|
110
|
-
_state = TreeStates.Hidden;
|
|
111
|
-
unregister(container);
|
|
158
|
+
|
|
159
|
+
const end = (show: boolean) => {
|
|
160
|
+
let direction: TransitionDirection = show ? "enter" : "leave"
|
|
161
|
+
|
|
162
|
+
isTransitioning = false
|
|
163
|
+
nesting.onStop(container, direction, (direction) => {
|
|
164
|
+
if (direction === "enter") afterEnter?.()
|
|
165
|
+
else if (direction === "leave") afterLeave?.()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
if (direction === "leave" && !hasChildren(nesting)) {
|
|
169
|
+
// When we don't have children anymore we can safely unregister from the
|
|
170
|
+
// parent and hide ourselves.
|
|
171
|
+
_state = TreeStates.Hidden
|
|
172
|
+
unregister(container)
|
|
173
|
+
}
|
|
112
174
|
}
|
|
113
|
-
|
|
114
|
-
$effect(() => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!requiresRef) return false;
|
|
122
|
-
if (skip) return false;
|
|
123
|
-
return true;
|
|
124
|
-
});
|
|
125
|
-
const _transition = useTransition({
|
|
126
|
-
get enabled() {
|
|
127
|
-
return enabled;
|
|
128
|
-
},
|
|
129
|
-
get element() {
|
|
130
|
-
return containerElement;
|
|
131
|
-
},
|
|
132
|
-
get show() {
|
|
133
|
-
return show;
|
|
134
|
-
},
|
|
135
|
-
events: { start, end }
|
|
136
|
-
});
|
|
137
|
-
const { data: transitionData } = $derived(_transition);
|
|
138
|
-
const ourProps = $derived(
|
|
139
|
-
compact({
|
|
140
|
-
class: classNames(
|
|
141
|
-
// Incoming classes if any
|
|
142
|
-
// all components accept className (but all HTML elements do)
|
|
143
|
-
theirProps.class,
|
|
144
|
-
// Apply these classes immediately
|
|
145
|
-
immediate && enter,
|
|
146
|
-
immediate && enterFrom,
|
|
147
|
-
// Map data attributes to `enter`, `enterFrom` and `enterTo` classes
|
|
148
|
-
transitionData.enter && enter,
|
|
149
|
-
transitionData.enter && transitionData.closed && enterFrom,
|
|
150
|
-
transitionData.enter && !transitionData.closed && enterTo,
|
|
151
|
-
// Map data attributes to `leave`, `leaveFrom` and `leaveTo` classes
|
|
152
|
-
transitionData.leave && leave,
|
|
153
|
-
transitionData.leave && !transitionData.closed && leaveFrom,
|
|
154
|
-
transitionData.leave && transitionData.closed && leaveTo,
|
|
155
|
-
// Map data attributes to `entered` class (backwards compatibility)
|
|
156
|
-
!transitionData.transition && show && entered
|
|
157
|
-
)?.trim() || void 0,
|
|
158
|
-
// If `class` is an empty string, we can omit it
|
|
159
|
-
...transitionDataAttributes(transitionData)
|
|
175
|
+
|
|
176
|
+
$effect(() => {
|
|
177
|
+
if (requiresRef && transition) return
|
|
178
|
+
|
|
179
|
+
// When we don't transition, then we can complete the transition
|
|
180
|
+
// immediately.
|
|
181
|
+
untrack(() => start(show))
|
|
182
|
+
untrack(() => end(show))
|
|
160
183
|
})
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
184
|
+
|
|
185
|
+
const enabled = $derived.by(() => {
|
|
186
|
+
// Should the current component transition? If not, then we can still
|
|
187
|
+
// orchestrate the child transitions.
|
|
188
|
+
if (!transition) return false
|
|
189
|
+
|
|
190
|
+
// If we don't require a ref, then we can't transition.
|
|
191
|
+
if (!requiresRef) return false
|
|
192
|
+
|
|
193
|
+
// If the server handoff isn't completed yet, we can't transition.
|
|
194
|
+
//if (!ready) return false
|
|
195
|
+
|
|
196
|
+
// If we start in a `show` state but without the `appear` prop, then we skip
|
|
197
|
+
// the initial transition.
|
|
198
|
+
if (skip) return false
|
|
199
|
+
|
|
200
|
+
return true
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// Ignoring the `visible` state because this doesn't handle the hierarchy. If
|
|
204
|
+
// a leave transition on the `<Transition>` is done, but there is still a
|
|
205
|
+
// child `<TransitionChild>` busy, then `visible` would be `false`, while
|
|
206
|
+
// `state` would still be `TreeStates.Visible`.
|
|
207
|
+
const _transition = useTransition({
|
|
208
|
+
get enabled() {
|
|
209
|
+
return enabled
|
|
210
|
+
},
|
|
211
|
+
get element() {
|
|
212
|
+
return containerElement
|
|
213
|
+
},
|
|
214
|
+
get show() {
|
|
215
|
+
return show
|
|
216
|
+
},
|
|
217
|
+
events: { start, end },
|
|
218
|
+
})
|
|
219
|
+
const { data: transitionData } = $derived(_transition)
|
|
220
|
+
|
|
221
|
+
const ourProps = $derived(
|
|
222
|
+
compact({
|
|
223
|
+
class:
|
|
224
|
+
classNames(
|
|
225
|
+
// Incoming classes if any
|
|
226
|
+
// all components accept className (but all HTML elements do)
|
|
227
|
+
theirProps.class,
|
|
228
|
+
|
|
229
|
+
// Apply these classes immediately
|
|
230
|
+
immediate && enter,
|
|
231
|
+
immediate && enterFrom,
|
|
232
|
+
|
|
233
|
+
// Map data attributes to `enter`, `enterFrom` and `enterTo` classes
|
|
234
|
+
transitionData.enter && enter,
|
|
235
|
+
transitionData.enter && transitionData.closed && enterFrom,
|
|
236
|
+
transitionData.enter && !transitionData.closed && enterTo,
|
|
237
|
+
|
|
238
|
+
// Map data attributes to `leave`, `leaveFrom` and `leaveTo` classes
|
|
239
|
+
transitionData.leave && leave,
|
|
240
|
+
transitionData.leave && !transitionData.closed && leaveFrom,
|
|
241
|
+
transitionData.leave && transitionData.closed && leaveTo,
|
|
242
|
+
|
|
243
|
+
// Map data attributes to `entered` class (backwards compatibility)
|
|
244
|
+
!transitionData.transition && show && entered
|
|
245
|
+
)?.trim() || undefined, // If `class` is an empty string, we can omit it
|
|
246
|
+
...transitionDataAttributes(transitionData),
|
|
247
|
+
})
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
const openClosedState = $derived.by(() => {
|
|
251
|
+
let openClosedState = 0
|
|
252
|
+
if (_state === TreeStates.Visible) openClosedState |= State.Open
|
|
253
|
+
if (_state === TreeStates.Hidden) openClosedState |= State.Closed
|
|
254
|
+
if (transitionData.enter) openClosedState |= State.Opening
|
|
255
|
+
if (transitionData.leave) openClosedState |= State.Closing
|
|
256
|
+
return openClosedState
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
createOpenClosedContext({
|
|
260
|
+
get value() {
|
|
261
|
+
return openClosedState
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
setContext<NestingContextValues>("NestingContext", nesting)
|
|
176
265
|
</script>
|
|
177
266
|
|
|
178
267
|
<ElementOrComponent {ourProps} {theirProps} defaultTag={DEFAULT_TRANSITION_CHILD_TAG} name="TransitionChild" bind:ref />
|
|
@@ -1,75 +1,105 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { State, useOpenClosed } from "../internal/open-closed.js"
|
|
3
|
+
import type { ElementType } from "../utils/types.js"
|
|
4
|
+
import { setContext, untrack, type Component } from "svelte"
|
|
5
|
+
import {
|
|
6
|
+
type TransitionChildProps,
|
|
7
|
+
DEFAULT_TRANSITION_CHILD_TAG,
|
|
8
|
+
TransitionChildRenderFeatures,
|
|
9
|
+
} from "./TransitionChild.svelte"
|
|
10
|
+
|
|
11
|
+
export type TransitionRootProps<TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG> =
|
|
12
|
+
TransitionChildProps<TTag> & {
|
|
13
|
+
show?: boolean
|
|
14
|
+
appear?: boolean
|
|
15
|
+
}
|
|
7
16
|
</script>
|
|
8
17
|
|
|
9
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
done: () => {
|
|
29
|
-
if (show) return;
|
|
30
|
-
_state = TreeStates.Hidden;
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
let initial = $state(true);
|
|
34
|
-
let changes = $state([show]);
|
|
35
|
-
$effect(() => {
|
|
36
|
-
if (untrack(() => initial) === false) {
|
|
37
|
-
return;
|
|
18
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">
|
|
19
|
+
import InternalTransitionChild, { shouldForwardRef } from "./InternalTransitionChild.svelte"
|
|
20
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
21
|
+
import {
|
|
22
|
+
hasChildren,
|
|
23
|
+
TreeStates,
|
|
24
|
+
useNesting,
|
|
25
|
+
type NestingContextValues,
|
|
26
|
+
type TransitionContextValues,
|
|
27
|
+
} from "./context.svelte.js"
|
|
28
|
+
|
|
29
|
+
let { ref = $bindable(), show, ..._props }: { as?: TTag } & TransitionRootProps<TTag> = $props()
|
|
30
|
+
const { appear = false, unmount = true, ...theirProps } = $derived(_props)
|
|
31
|
+
const requiresRef = shouldForwardRef(_props)
|
|
32
|
+
|
|
33
|
+
const usesOpenClosedState = useOpenClosed()
|
|
34
|
+
|
|
35
|
+
if (show === undefined && usesOpenClosedState !== null) {
|
|
36
|
+
show = (usesOpenClosedState.value & State.Open) === State.Open
|
|
38
37
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
|
|
39
|
+
if (show === undefined) {
|
|
40
|
+
throw new Error("A <Transition /> is used but it is missing a `show={true | false}` prop.")
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
$
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
|
|
43
|
+
let _state = $state(show ? TreeStates.Visible : TreeStates.Hidden)
|
|
44
|
+
|
|
45
|
+
const nestingBag = useNesting({
|
|
46
|
+
done: () => {
|
|
47
|
+
if (show) return
|
|
48
|
+
_state = TreeStates.Hidden
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
let initial = $state(true)
|
|
53
|
+
|
|
54
|
+
// Change the `initial` value
|
|
55
|
+
let changes = $state([show])
|
|
56
|
+
$effect(() => {
|
|
57
|
+
// We can skip this effect
|
|
58
|
+
if (untrack(() => initial) === false) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Track the changes
|
|
63
|
+
if (changes[changes.length - 1] !== show) {
|
|
64
|
+
changes.push(show)
|
|
65
|
+
initial = false
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
$effect(() => {
|
|
70
|
+
if (show) {
|
|
71
|
+
_state = TreeStates.Visible
|
|
72
|
+
} else if (!hasChildren(nestingBag) && untrack(() => ref)) {
|
|
73
|
+
_state = TreeStates.Hidden
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const sharedProps = $derived({ unmount })
|
|
78
|
+
|
|
79
|
+
const beforeEnter = () => {
|
|
80
|
+
if (initial) initial = false
|
|
81
|
+
_props.beforeEnter?.()
|
|
49
82
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
_props.beforeEnter?.();
|
|
55
|
-
};
|
|
56
|
-
const beforeLeave = () => {
|
|
57
|
-
if (initial) initial = false;
|
|
58
|
-
_props.beforeLeave?.();
|
|
59
|
-
};
|
|
60
|
-
setContext("NestingContext", nestingBag);
|
|
61
|
-
setContext("TransitionContext", {
|
|
62
|
-
get show() {
|
|
63
|
-
return show;
|
|
64
|
-
},
|
|
65
|
-
get appear() {
|
|
66
|
-
return appear;
|
|
67
|
-
},
|
|
68
|
-
get initial() {
|
|
69
|
-
return initial;
|
|
83
|
+
|
|
84
|
+
const beforeLeave = () => {
|
|
85
|
+
if (initial) initial = false
|
|
86
|
+
_props.beforeLeave?.()
|
|
70
87
|
}
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
|
|
89
|
+
setContext<NestingContextValues>("NestingContext", nestingBag)
|
|
90
|
+
setContext<TransitionContextValues>("TransitionContext", {
|
|
91
|
+
get show() {
|
|
92
|
+
return show
|
|
93
|
+
},
|
|
94
|
+
get appear() {
|
|
95
|
+
return appear
|
|
96
|
+
},
|
|
97
|
+
get initial() {
|
|
98
|
+
return initial
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const InternalChild = InternalTransitionChild as Component<TransitionChildProps<TTag>, any>
|
|
73
103
|
</script>
|
|
74
104
|
|
|
75
105
|
{#snippet children()}
|
|
@@ -1,16 +1,36 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { ElementType, Props } from "../utils/types.js"
|
|
3
|
+
import { RenderFeatures, type PropsForFeatures } from "../utils/render.js"
|
|
4
|
+
import type { TransitionEvents, TransitionClasses } from "./context.svelte.js"
|
|
5
|
+
|
|
6
|
+
type TransitionChildPropsWeControl = never
|
|
7
|
+
|
|
8
|
+
export type TransitionChildProps<TTag extends ElementType> = Props<
|
|
9
|
+
TTag,
|
|
10
|
+
TransitionChildRenderPropArg,
|
|
11
|
+
TransitionChildPropsWeControl,
|
|
12
|
+
PropsForFeatures<typeof TransitionChildRenderFeatures> &
|
|
13
|
+
TransitionClasses &
|
|
14
|
+
TransitionEvents & { transition?: boolean; appear?: boolean }
|
|
15
|
+
>
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_TRANSITION_CHILD_TAG = "svelte:fragment"
|
|
18
|
+
export type TransitionChildRenderPropArg = HTMLElement
|
|
19
|
+
export const TransitionChildRenderFeatures = RenderFeatures.RenderStrategy
|
|
4
20
|
</script>
|
|
5
21
|
|
|
6
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
22
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">
|
|
23
|
+
import { useOpenClosed } from "../internal/open-closed.js"
|
|
24
|
+
import { getContext } from "svelte"
|
|
25
|
+
import InternalTransitionChild from "./InternalTransitionChild.svelte"
|
|
26
|
+
import Transition from "./Transition.svelte"
|
|
27
|
+
|
|
28
|
+
const hasTransitionContext = !!getContext("TransitionContext")
|
|
29
|
+
const hasOpenClosedContext = useOpenClosed() !== null
|
|
30
|
+
|
|
31
|
+
let { ref = $bindable(), as, ...props }: { as?: TTag } & TransitionChildProps<TTag> = $props()
|
|
32
|
+
|
|
33
|
+
const TransitionRootOrChild = !hasTransitionContext && hasOpenClosedContext ? Transition : InternalTransitionChild
|
|
14
34
|
</script>
|
|
15
35
|
|
|
16
36
|
<TransitionRootOrChild bind:ref {...props} />
|