@pzerelles/headlessui-svelte 2.1.2-next.3 → 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.
Files changed (59) hide show
  1. package/dist/button/Button.svelte +84 -54
  2. package/dist/checkbox/Checkbox.svelte +174 -120
  3. package/dist/close-button/CloseButton.svelte +12 -6
  4. package/dist/combobox/Combobox.svelte +50 -3
  5. package/dist/data-interactive/DataInteractive.svelte +57 -29
  6. package/dist/description/Description.svelte +32 -21
  7. package/dist/dialog/Dialog.svelte +69 -34
  8. package/dist/dialog/DialogBackdrop.svelte +29 -12
  9. package/dist/dialog/DialogPanel.svelte +49 -26
  10. package/dist/dialog/DialogTitle.svelte +38 -23
  11. package/dist/dialog/InternalDialog.svelte +263 -202
  12. package/dist/field/Field.svelte +49 -26
  13. package/dist/fieldset/Fieldset.svelte +50 -29
  14. package/dist/focus-trap/FocusTrap.svelte +436 -290
  15. package/dist/input/Input.svelte +85 -53
  16. package/dist/internal/FocusSentinel.svelte +16 -8
  17. package/dist/internal/ForcePortalRoot.svelte +7 -3
  18. package/dist/internal/FormFields.svelte +31 -20
  19. package/dist/internal/FormResolver.svelte +20 -15
  20. package/dist/internal/Hidden.svelte +44 -27
  21. package/dist/internal/Hidden.svelte.d.ts +2 -5
  22. package/dist/internal/HiddenFeatures.d.ts +5 -0
  23. package/dist/internal/HiddenFeatures.js +9 -0
  24. package/dist/internal/HoistFormFields.svelte +7 -4
  25. package/dist/internal/MainTreeProvider.svelte +89 -36
  26. package/dist/internal/Portal.svelte +18 -14
  27. package/dist/label/Label.svelte +91 -57
  28. package/dist/legend/Legend.svelte +18 -3
  29. package/dist/listbox/Listbox.svelte +600 -409
  30. package/dist/listbox/ListboxButton.svelte +176 -127
  31. package/dist/listbox/ListboxOption.svelte +166 -125
  32. package/dist/listbox/ListboxOptions.svelte +340 -244
  33. package/dist/listbox/ListboxSelectedOption.svelte +38 -15
  34. package/dist/menu/Menu.svelte +307 -218
  35. package/dist/menu/MenuButton.svelte +157 -115
  36. package/dist/menu/MenuHeading.svelte +34 -14
  37. package/dist/menu/MenuItem.svelte +145 -107
  38. package/dist/menu/MenuItems.svelte +298 -224
  39. package/dist/menu/MenuSection.svelte +26 -9
  40. package/dist/menu/MenuSeparator.svelte +20 -4
  41. package/dist/portal/InternalPortal.svelte +141 -85
  42. package/dist/portal/Portal.svelte +5 -2
  43. package/dist/portal/PortalGroup.svelte +30 -9
  44. package/dist/switch/Switch.svelte +179 -122
  45. package/dist/switch/Switch.svelte.d.ts +4 -4
  46. package/dist/switch/SwitchGroup.svelte +44 -31
  47. package/dist/tabs/Tab.svelte +195 -143
  48. package/dist/tabs/TabGroup.svelte +292 -205
  49. package/dist/tabs/TabList.svelte +31 -11
  50. package/dist/tabs/TabPanel.svelte +68 -43
  51. package/dist/tabs/TabPanels.svelte +18 -7
  52. package/dist/textarea/Textarea.svelte +83 -53
  53. package/dist/transition/InternalTransitionChild.svelte +259 -170
  54. package/dist/transition/Transition.svelte +96 -66
  55. package/dist/transition/TransitionChild.svelte +31 -11
  56. package/dist/utils/ElementOrComponent.svelte +44 -23
  57. package/dist/utils/Generic.svelte +29 -17
  58. package/dist/utils/StableCollection.svelte +54 -36
  59. package/package.json +10 -10
@@ -1,178 +1,267 @@
1
- <script lang="ts" module>import { compact, RenderStrategy } from "../utils/render.js";
2
- import { onMount, setContext, untrack } from "svelte";
3
- import {
4
- hasChildren,
5
- TreeStates,
6
- useNesting,
7
- useParentNesting,
8
- useTransitionContext
9
- } from "./context.svelte.js";
10
- import { match } from "../utils/match.js";
11
- import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js";
12
- import { classNames } from "../utils/class-names.js";
13
- import { createOpenClosedContext, State } from "../internal/open-closed.js";
14
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
15
- import { DEFAULT_TRANSITION_CHILD_TAG } from "./TransitionChild.svelte";
16
- export function shouldForwardRef(props) {
17
- return (
18
- // If we have any of the enter/leave classes
19
- Boolean(props.enter || props.enterFrom || props.enterTo || props.leave || props.leaveFrom || props.leaveTo) || // If the `as` prop is not a Fragment
20
- (props.as ?? DEFAULT_TRANSITION_CHILD_TAG) !== "svelte:fragment" || // If we have a single child, then we can forward the ref directly
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
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG">let { ref = $bindable(), ..._props } = $props();
27
- const {
28
- // Whether or not to enable transitions on the current element (by exposing
29
- // transition data). When set to false, the `Transition` component still
30
- // acts as a transition boundary for `TransitionChild` components.
31
- transition = true,
32
- // Event "handlers"
33
- beforeEnter,
34
- afterEnter,
35
- beforeLeave,
36
- afterLeave,
37
- // Class names
38
- enter,
39
- enterFrom,
40
- enterTo,
41
- entered,
42
- leave,
43
- leaveFrom,
44
- leaveTo,
45
- ...theirProps
46
- } = $derived(_props);
47
- let containerElement = $state();
48
- let container = $state({ current: null });
49
- const requiresRef = $derived(shouldForwardRef(_props));
50
- const strategy = $derived(theirProps.unmount ?? true ? RenderStrategy.Unmount : RenderStrategy.Hidden);
51
- const _transitionContext = useTransitionContext();
52
- const { show, appear, initial } = $derived(_transitionContext);
53
- let _state = $state(untrack(() => show) ? TreeStates.Visible : TreeStates.Hidden);
54
- const parentNesting = useParentNesting();
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
- match(_state, {
71
- [TreeStates.Hidden]: () => unregister(container),
72
- [TreeStates.Visible]: () => register(container)
73
- });
74
- });
75
- $effect(() => {
76
- if (!requiresRef) return;
77
- if (_state === TreeStates.Visible && container.current === null) {
78
- throw new Error("Did you forget to passthrough the `ref` to the actual DOM node?");
79
- }
80
- });
81
- const skip = $derived(initial && !appear);
82
- const immediate = $derived(appear && show && initial);
83
- let isTransitioning = $state(false);
84
- let nesting = useNesting({
85
- done: () => {
86
- if (isTransitioning) return;
87
- _state = TreeStates.Hidden;
88
- unregister(container);
89
- },
90
- get parent() {
91
- return parentNesting;
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 start = (show2) => {
95
- isTransitioning = true;
96
- const direction = show2 ? "enter" : "leave";
97
- nesting.onStart(container, direction, (direction2) => {
98
- if (direction2 === "enter") beforeEnter?.();
99
- else if (direction2 === "leave") beforeLeave?.();
100
- });
101
- };
102
- const end = (show2) => {
103
- let direction = show2 ? "enter" : "leave";
104
- isTransitioning = false;
105
- nesting.onStop(container, direction, (direction2) => {
106
- if (direction2 === "enter") afterEnter?.();
107
- else if (direction2 === "leave") afterLeave?.();
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
- if (requiresRef && transition) return;
116
- untrack(() => start(show));
117
- untrack(() => end(show));
118
- });
119
- const enabled = $derived.by(() => {
120
- if (!transition) return false;
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 openClosedState = $derived.by(() => {
163
- let openClosedState2 = 0;
164
- if (_state === TreeStates.Visible) openClosedState2 |= State.Open;
165
- if (_state === TreeStates.Hidden) openClosedState2 |= State.Closed;
166
- if (transitionData.enter) openClosedState2 |= State.Opening;
167
- if (transitionData.leave) openClosedState2 |= State.Closing;
168
- return openClosedState2;
169
- });
170
- createOpenClosedContext({
171
- get value() {
172
- return openClosedState;
173
- }
174
- });
175
- setContext("NestingContext", nesting);
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>import { State, useOpenClosed } from "../internal/open-closed.js";
2
- import { setContext, untrack } from "svelte";
3
- import {
4
- DEFAULT_TRANSITION_CHILD_TAG,
5
- TransitionChildRenderFeatures
6
- } from "./TransitionChild.svelte";
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">import InternalTransitionChild, { shouldForwardRef } from "./InternalTransitionChild.svelte";
10
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
11
- import {
12
- hasChildren,
13
- TreeStates,
14
- useNesting
15
- } from "./context.svelte.js";
16
- let { ref = $bindable(), show, ..._props } = $props();
17
- const { appear = false, unmount = true, ...theirProps } = $derived(_props);
18
- const requiresRef = shouldForwardRef(_props);
19
- const usesOpenClosedState = useOpenClosed();
20
- if (show === void 0 && usesOpenClosedState !== null) {
21
- show = (usesOpenClosedState.value & State.Open) === State.Open;
22
- }
23
- if (show === void 0) {
24
- throw new Error("A <Transition /> is used but it is missing a `show={true | false}` prop.");
25
- }
26
- let _state = $state(show ? TreeStates.Visible : TreeStates.Hidden);
27
- const nestingBag = useNesting({
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
- if (changes[changes.length - 1] !== show) {
40
- changes.push(show);
41
- initial = false;
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
- $effect(() => {
45
- if (show) {
46
- _state = TreeStates.Visible;
47
- } else if (!hasChildren(nestingBag) && untrack(() => ref)) {
48
- _state = TreeStates.Hidden;
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 sharedProps = $derived({ unmount });
52
- const beforeEnter = () => {
53
- if (initial) initial = false;
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
- const InternalChild = InternalTransitionChild;
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>import { RenderFeatures } from "../utils/render.js";
2
- export const DEFAULT_TRANSITION_CHILD_TAG = "svelte:fragment";
3
- export const TransitionChildRenderFeatures = RenderFeatures.RenderStrategy;
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">import { useOpenClosed } from "../internal/open-closed.js";
7
- import { getContext } from "svelte";
8
- import InternalTransitionChild from "./InternalTransitionChild.svelte";
9
- import Transition from "./Transition.svelte";
10
- const hasTransitionContext = !!getContext("TransitionContext");
11
- const hasOpenClosedContext = useOpenClosed() !== null;
12
- let { ref = $bindable(), as, ...props } = $props();
13
- const TransitionRootOrChild = !hasTransitionContext && hasOpenClosedContext ? Transition : InternalTransitionChild;
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} />