Repository: melt-ui/melt-ui
Pull request #1210 (2024-05-27 07:07:26)

feat: add rootMargin to TableOfContents builder
## Motivation
TableOfContents interaction observer allows passing in scroll offset, which can be used to account for fixed/sticky headers when scrolling, but there is no way to cater for that in interaction observer.

## Changes
This PR adds a rootMargin argument for TableOfContents builder, which is then passed to the InteractionObserver constructor, thus catering for viewport customisation and use cases like fixed headers/footers.

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 69ff226660e4dc1a96ef6427a7a14600a043bd6d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/bolstycjw/melt-ui/new/develop?filename=.changeset/rude-pugs-tease.md&value=---%0A%22%40melt-ui%2Fsvelte%22%3A%20patch%0A---%0A%0Afeat%3A%20add%20rootMargin%20to%20TableOfContents%20builder%0A)



Patch:
diff --git a/.changeset/old-bees-breathe.md b/.changeset/old-bees-breathe.md
deleted file mode 100644
index c85a55c4..00000000
--- a/.changeset/old-bees-breathe.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@melt-ui/svelte": minor
----
-
-fix: add `data-state` to select & combobox (closes #1199)
diff --git a/.changeset/rude-pugs-tease.md b/.changeset/rude-pugs-tease.md
new file mode 100644
index 00000000..106b4881
--- /dev/null
+++ b/.changeset/rude-pugs-tease.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": minor
+---
+
+feat: add rootMargin to TableOfContents builder
diff --git a/.changeset/silent-snakes-suffer.md b/.changeset/silent-snakes-suffer.md
deleted file mode 100644
index 9c562bf8..00000000
--- a/.changeset/silent-snakes-suffer.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@melt-ui/svelte": minor
----
-
-chore: change peer deps to support svelte 5
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1017617..36348cc4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,47 @@
 # @melt-ui/svelte
 
+## 0.82.0
+
+### Minor Changes
+
+- Added prop to createToaster() to pause all timers on hover ([#1178](https://github.com/melt-ui/melt-ui/pull/1178))
+
+- feat(tags-input): split on paste ([#1229](https://github.com/melt-ui/melt-ui/pull/1229))
+
+- add selection helpers to range calendar ([`cf20fc72`](https://github.com/melt-ui/melt-ui/commit/cf20fc72bf367da13a17daaa9807bd430ff99688))
+
+- add `name` prop to radio group builder hidden input element ([#1237](https://github.com/melt-ui/melt-ui/pull/1237))
+
+### Patch Changes
+
+- fix(Calendar): sometimes first day of next month is missing ([#1236](https://github.com/melt-ui/melt-ui/pull/1236))
+
+- fix(slider): `onValueCommitted` called if the slider had an active state ([#1218](https://github.com/melt-ui/melt-ui/pull/1218))
+
+## 0.81.0
+
+### Minor Changes
+
+- Mount each floating element into their own portal by default now that stack handling has been improved ([#1103](https://github.com/melt-ui/melt-ui/pull/1103))
+
+- Support all of Floating UI's FlipOptions at `positioning.flip` ([#1203](https://github.com/melt-ui/melt-ui/pull/1203))
+
+### Patch Changes
+
+- fix svelte peer deps ([`de0169dd`](https://github.com/melt-ui/melt-ui/commit/de0169dd840a4ea51dd0a0611b59797665095a8c))
+
+- fix undefined on portal update ([`87bce8a0`](https://github.com/melt-ui/melt-ui/commit/87bce8a0ec9d085715b8985c16158ebd3991b71a))
+
+## 0.80.0
+
+### Minor Changes
+
+- feat(slider): add `onValueCommitted` callback ([#1212](https://github.com/melt-ui/melt-ui/pull/1212))
+
+- fix: add `data-state` to select & combobox (closes #1199) ([#1200](https://github.com/melt-ui/melt-ui/pull/1200))
+
+- chore: change peer deps to support svelte 5 ([#1207](https://github.com/melt-ui/melt-ui/pull/1207))
+
 ## 0.79.1
 
 ### Patch Changes
diff --git a/package.json b/package.json
index d9bf4eb7..60716db3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@melt-ui/svelte",
-	"version": "0.79.1",
+	"version": "0.82.0",
 	"license": "MIT",
 	"repository": "github:melt-ui/melt-ui",
 	"author": "Thomas G. Lopes",
@@ -8,6 +8,7 @@
 		"dev": "vite dev",
 		"build": "vite build && npm run package",
 		"deploy": "vite build",
+		"prepare": "svelte-kit sync",
 		"preview": "vite preview",
 		"package": "svelte-kit sync && svelte-package && publint",
 		"prepublishOnly": "npm run package",
@@ -58,7 +59,7 @@
 		"!dist/**/tests"
 	],
 	"peerDependencies": {
-		"svelte": ">=3 <=5"
+		"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0-next.118"
 	},
 	"dependencies": {
 		"@floating-ui/core": "^1.3.1",
diff --git a/src/docs/constants.ts b/src/docs/constants.ts
index 5fe74aee..99b327a9 100644
--- a/src/docs/constants.ts
+++ b/src/docs/constants.ts
@@ -41,7 +41,7 @@ export const DESCRIPTIONS = {
 		`Whether or not to close the ${name} when the user clicks outside of it.`,
 	BUILDER: (name: string) => `The builder function used to create the ${name} component.`,
 	PORTAL: (name = 'floating element') =>
-		`The element or selector to render the ${name} into. Nested floating elements are automatically rendered into their parent if not specified. Pass in \`null\` to disable portalling.`,
+		`The element or selector to render the ${name} into. Nested floating elements are automatically rendered into their own portal if not specified. Pass in \`null\` to disable portalling. Pass in \`undefined\` to use parent portal.`,
 	FORCE_VISIBLE: (name = 'element') =>
 		`Whether or not to force the ${name} to always be visible. This is useful for custom transitions and animations using conditional blocks.`,
 	ON_CHANGE: (store: string) =>
diff --git a/src/docs/data/builders/combobox.ts b/src/docs/data/builders/combobox.ts
index 7e057994..39123596 100644
--- a/src/docs/data/builders/combobox.ts
+++ b/src/docs/data/builders/combobox.ts
@@ -31,6 +31,11 @@ const OPTION_PROPS = [
 		description:
 			'When true, hovering an option will update the `highlightedItem` store, and when the cursor leaves an option the store will be set to `null`',
 	},
+	{
+		name: 'name',
+		type: 'string',
+		description: 'The name to be used for the hidden input.',
+	},
 ];
 
 const BUILDER_NAME = 'combobox';
diff --git a/src/docs/data/builders/radio-group.ts b/src/docs/data/builders/radio-group.ts
index 66262751..9b9165cf 100644
--- a/src/docs/data/builders/radio-group.ts
+++ b/src/docs/data/builders/radio-group.ts
@@ -17,6 +17,11 @@ const OPTION_PROPS = [
 		default: '"vertical"',
 		description: 'The orientation of the radio group.',
 	},
+	{
+		name: 'name',
+		type: 'string',
+		description: 'The name to be used for the hidden input.',
+	},
 ];
 const BUILDER_NAME = 'radio group';
 
diff --git a/src/docs/data/builders/range-calendar.ts b/src/docs/data/builders/range-calendar.ts
index 3c749aae..d9f529f6 100644
--- a/src/docs/data/builders/range-calendar.ts
+++ b/src/docs/data/builders/range-calendar.ts
@@ -221,10 +221,20 @@ const builder = builderSchema(BUILDER_NAME, {
 			type: 'Readable<(date: DateValue) => boolean>',
 		},
 		{
-			name: 'isDateSelected',
+			name: 'isSelected',
 			description: 'A function that returns whether the given date is selected.',
 			type: 'Readable<(date: DateValue) => boolean>',
 		},
+		{
+			name: 'isSeletionStart',
+			description:
+				'A function that returns whether the given date is the date at the start of the selection range.',
+		},
+		{
+			name: 'isSeletionEnd',
+			description:
+				'A function that returns whether the given date is the date at the end of the selection range.',
+		},
 	],
 });
 
diff --git a/src/docs/data/builders/slider.ts b/src/docs/data/builders/slider.ts
index 78e0bee9..e9074875 100644
--- a/src/docs/data/builders/slider.ts
+++ b/src/docs/data/builders/slider.ts
@@ -72,6 +72,11 @@ const builder = builderSchema(BUILDER_NAME, {
 			description: 'A callback that is called when the value of the slider changes.',
 			see: SEE.CHANGE_FUNCTIONS,
 		},
+		{
+			name: 'onValueCommitted',
+			type: '(value: number[]) => void',
+			description: 'The callback invoked when the user has committed the value of the slider.',
+		},
 	],
 	elements: [
 		{
diff --git a/src/docs/data/builders/table-of-contents.ts b/src/docs/data/builders/table-of-contents.ts
index 7c6ab7b8..5c93e3ea 100644
--- a/src/docs/data/builders/table-of-contents.ts
+++ b/src/docs/data/builders/table-of-contents.ts
@@ -35,6 +35,12 @@ const builder: APISchema = {
 `'highest'` means the opposite.\n\
 `'lowest-parents'` means that parents of the heading with the lowest visible content are also considered active, and the same goes for `'highest-parents'`.",
 		},
+		{
+			name: 'rootMargin',
+			type: 'string',
+			description:
+				'The root margin for the intersection observer. Refer to the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) for more information.',
+		},
 		{
 			name: 'scrollOffset',
 			type: 'number',
diff --git a/src/docs/data/builders/toast.ts b/src/docs/data/builders/toast.ts
index 04f445dd..0653a39a 100644
--- a/src/docs/data/builders/toast.ts
+++ b/src/docs/data/builders/toast.ts
@@ -20,6 +20,12 @@ const OPTION_PROPS = [
 		default: "'foreground'",
 		description: 'The sensitivity of the toast for accessibility purposes.',
 	},
+	{
+		name: 'hover',
+		type: ["'pause'", "'pause-all'", 'null'],
+		default: "'pause'",
+		description: 'The behavior when a toast is hovered.',
+	},
 ];
 
 const BUILDER_NAME = 'toast';
@@ -129,7 +135,7 @@ const keyboard: KeyboardSchema = [
 ];
 
 const schemas = [builder, content, title, description, close];
-const features = ['Automatically closes', 'Resets closing on hover'];
+const features = ['Automatically closes', 'Pause closing on hover (single, all, none)'];
 
 export const toastData: BuilderData = {
 	schemas,
diff --git a/src/docs/data/long-types/floating-config.ts b/src/docs/data/long-types/floating-config.ts
index 029bf3b9..d7052823 100644
--- a/src/docs/data/long-types/floating-config.ts
+++ b/src/docs/data/long-types/floating-config.ts
@@ -1,3 +1,5 @@
+import type { FlipOptions } from '@floating-ui/core';
+
 type FloatingConfig = {
 	/**
 	 * The initial placement of the floating element.
@@ -56,7 +58,7 @@ type FloatingConfig = {
 	 *
 	 * @see https://floating-ui.com/docs/flip
 	 */
-	flip?: boolean;
+	flip?: boolean | FlipOptions;
 
 	/**
 	 * Whether the floating element can overlap the reference element.
diff --git a/src/docs/previews/toast/progress/tailwind/index.svelte b/src/docs/previews/toast/progress/tailwind/index.svelte
index e659ddda..58473fa8 100644
--- a/src/docs/previews/toast/progress/tailwind/index.svelte
+++ b/src/docs/previews/toast/progress/tailwind/index.svelte
@@ -7,16 +7,20 @@
 </script>
 
 <script lang="ts">
-	import { createToaster } from '$lib/index.js';
+	import { writable, type Writable } from 'svelte/store';
+	import { createToaster, type CreateToasterProps } from '$lib/index.js';
 	import { flip } from 'svelte/animate';
 	import Toast from './toast.svelte';
+	import SelectHover from './select-hover.svelte';
 
-	const {
+	const hover: Writable<CreateToasterProps['hover']> = writable('pause');
+
+	$: ({
 		elements,
 		helpers: { addToast },
 		states: { toasts },
 		actions: { portal },
-	} = createToaster<ToastData>();
+	} = createToaster<ToastData>({ hover: $hover }));
 
 	const toastData: ToastData[] = [
 		{
@@ -41,6 +45,8 @@
 	}
 </script>
 
+<SelectHover bind:value={$hover} />
+
 <button
 	class="inline-flex items-center justify-center rounded-xl bg-white px-4 py-3
 	font-medium leading-none text-magnum-700 shadow hover:opacity-75"
diff --git a/src/docs/previews/toast/progress/tailwind/select-hover.svelte b/src/docs/previews/toast/progress/tailwind/select-hover.svelte
new file mode 100644
index 00000000..104da266
--- /dev/null
+++ b/src/docs/previews/toast/progress/tailwind/select-hover.svelte
@@ -0,0 +1,82 @@
+<script lang="ts">
+	import { Check, ChevronDown } from '$icons/index.js';
+	import { createSelect, melt, type CreateToasterProps } from '$lib/index.js';
+	import { fade } from 'svelte/transition';
+
+	const options: { value: CreateToasterProps['hover']; label: string }[] = [
+		{ value: 'pause', label: 'pause' },
+		{ value: 'pause-all', label: 'pause-all' },
+		{ value: null, label: 'null' },
+	];
+
+	const {
+		elements: { trigger, menu, option, label },
+		states: { selected, selectedLabel, open },
+		helpers: { isSelected },
+	} = createSelect<CreateToasterProps['hover']>({
+		forceVisible: true,
+		positioning: {
+			placement: 'bottom',
+			fitViewport: true,
+			sameWidth: true,
+		},
+		defaultSelected: { value: 'pause', label: 'pause' },
+	});
+
+	export let value: CreateToasterProps['hover'];
+
+	$: value = $selected?.value;
+</script>
+
+<div class="absolute left-4 top-4">
+	<div class="flex flex-col gap-1">
+		<!-- svelte-ignore a11y-label-has-associated-control - $label contains the 'for' attribute -->
+		<label class="block text-white" use:melt={$label}> Hover behavior : </label>
+		<button
+			class="flex h-10 min-w-[220px] items-center justify-between rounded-lg bg-white px-3 py-2
+	text-magnum-700 shadow transition-opacity hover:opacity-90"
+			use:melt={$trigger}
+			aria-label="Hover behavior"
+		>
+			{$selectedLabel || 'Select hover behavior'}
+			<ChevronDown class="size-5" />
+		</button>
+		{#if $open}
+			<div
+				class="force-dark z-10 flex max-h-[300px] flex-col
+		overflow-y-auto rounded-lg bg-white p-1
+		shadow focus:!ring-0"
+				use:melt={$menu}
+				transition:fade={{ duration: 150 }}
+			>
+				{#each options as { value, label }}
+					<div
+						class="relative cursor-pointer rounded-lg py-1 pl-8 pr-4 text-neutral-800
+							hover:bg-magnum-100 focus:z-10
+							focus:text-magnum-700
+							data-[highlighted]:bg-magnum-200 data-[highlighted]:text-magnum-900
+							data-[disabled]:opacity-50"
+						use:melt={$option({ value, label })}
+					>
+						<div class="check {$isSelected(value) ? 'block' : 'hidden'}">
+							<Check class="size-4" />
+						</div>
+
+						{label}
+					</div>
+				{/each}
+			</div>
+		{/if}
+	</div>
+</div>
+
+<style lang="postcss">
+	.check {
+		position: absolute;
+		left: theme(spacing.2);
+		top: 50%;
+		z-index: theme(zIndex.20);
+		translate: 0 calc(-50% + 1px);
+		color: theme(colors.magnum.500);
+	}
+</style>
diff --git a/src/lib/builders/checkbox/create.ts b/src/lib/builders/checkbox/create.ts
index 2a394c76..323a27ef 100644
--- a/src/lib/builders/checkbox/create.ts
+++ b/src/lib/builders/checkbox/create.ts
@@ -6,11 +6,10 @@ import {
 	kbd,
 	omit,
 	overridable,
-	styleToString,
 	toWritableStores,
 } from '$lib/internal/helpers/index.js';
 import type { Defaults, MeltActionReturn } from '$lib/internal/types.js';
-import { derived, readable, writable } from 'svelte/store';
+import { derived, writable } from 'svelte/store';
 import type { CheckboxEvents } from './events.js';
 import type { CreateCheckboxProps } from './types.js';
 import { createHiddenInput } from '../hidden-input/create.js';
diff --git a/src/lib/builders/context-menu/create.ts b/src/lib/builders/context-menu/create.ts
index 3cd5ac40..07fbab4b 100644
--- a/src/lib/builders/context-menu/create.ts
+++ b/src/lib/builders/context-menu/create.ts
@@ -48,7 +48,7 @@ const defaults = {
 	preventScroll: true,
 	escapeBehavior: 'close',
 	closeOnOutsideClick: true,
-	portal: undefined,
+	portal: 'body',
 	loop: false,
 	dir: 'ltr',
 	defaultOpen: false,
diff --git a/src/lib/builders/dialog/create.ts b/src/lib/builders/dialog/create.ts
index 1dbeaea7..06799baf 100644
--- a/src/lib/builders/dialog/create.ts
+++ b/src/lib/builders/dialog/create.ts
@@ -21,7 +21,6 @@ import {
 } from '$lib/internal/helpers/index.js';
 import { withGet } from '$lib/internal/helpers/withGet.js';
 import type { Defaults, MeltActionReturn } from '$lib/internal/types.js';
-import { tick } from 'svelte';
 import { derived, writable } from 'svelte/store';
 import type { DialogEvents } from './events.js';
 import type { CreateDialogProps } from './types.js';
@@ -43,7 +42,7 @@ const defaults = {
 	closeOnOutsideClick: true,
 	role: 'dialog',
 	defaultOpen: false,
-	portal: undefined,
+	portal: 'body',
 	forceVisible: false,
 	openFocus: undefined,
 	closeFocus: undefined,
diff --git a/src/lib/builders/dialog/types.ts b/src/lib/builders/dialog/types.ts
index 39cc9562..99d5d7b1 100644
--- a/src/lib/builders/dialog/types.ts
+++ b/src/lib/builders/dialog/types.ts
@@ -2,6 +2,7 @@ import type { ChangeFn, FocusProp, IdObj } from '$lib/internal/helpers/index.js'
 import type { BuilderReturn } from '$lib/internal/types.js';
 import type { Writable } from 'svelte/store';
 import type { DialogIdParts, createDialog } from './create.js';
+import type { PortalConfig } from '$lib/internal/actions/portal.js';
 import type { EscapeBehaviorType } from '$lib/internal/actions/index.js';
 export type { DialogComponentEvents } from './events.js';
 export type CreateDialogProps = {
@@ -70,7 +71,7 @@ export type CreateDialogProps = {
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * If true, the dialog will be visible regardless of the open state.
diff --git a/src/lib/builders/dropdown-menu/create.ts b/src/lib/builders/dropdown-menu/create.ts
index d6f41228..39428146 100644
--- a/src/lib/builders/dropdown-menu/create.ts
+++ b/src/lib/builders/dropdown-menu/create.ts
@@ -13,7 +13,7 @@ const defaults = {
 	preventScroll: true,
 	escapeBehavior: 'close',
 	closeOnOutsideClick: true,
-	portal: undefined,
+	portal: 'body',
 	loop: false,
 	dir: 'ltr',
 	defaultOpen: false,
diff --git a/src/lib/builders/link-preview/create.ts b/src/lib/builders/link-preview/create.ts
index 6739cc9b..c6721151 100644
--- a/src/lib/builders/link-preview/create.ts
+++ b/src/lib/builders/link-preview/create.ts
@@ -42,7 +42,7 @@ const defaults = {
 	arrowSize: 8,
 	closeOnOutsideClick: true,
 	forceVisible: false,
-	portal: undefined,
+	portal: 'body',
 	escapeBehavior: 'close',
 	onOutsideClick: undefined,
 	preventTextSelectionOverflow: true,
diff --git a/src/lib/builders/link-preview/types.ts b/src/lib/builders/link-preview/types.ts
index ef6cae54..17b04ead 100644
--- a/src/lib/builders/link-preview/types.ts
+++ b/src/lib/builders/link-preview/types.ts
@@ -2,6 +2,7 @@ import type {
 	EscapeBehaviorType,
 	FloatingConfig,
 	InteractOutsideEvent,
+	PortalConfig,
 } from '$lib/internal/actions/index.js';
 import type { ChangeFn, IdObj } from '$lib/internal/helpers/index.js';
 import type { BuilderReturn } from '$lib/internal/types.js';
@@ -109,7 +110,7 @@ export type CreateLinkPreviewProps = {
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * Optionally override the default ids we assign to the elements
diff --git a/src/lib/builders/listbox/create.ts b/src/lib/builders/listbox/create.ts
index 88d27aee..ecdb8cb1 100644
--- a/src/lib/builders/listbox/create.ts
+++ b/src/lib/builders/listbox/create.ts
@@ -68,7 +68,7 @@ const defaults = {
 	preventScroll: true,
 	escapeBehavior: 'close',
 	forceVisible: false,
-	portal: undefined,
+	portal: 'body',
 	builder: 'listbox',
 	disabled: false,
 	required: false,
diff --git a/src/lib/builders/listbox/types.ts b/src/lib/builders/listbox/types.ts
index 62f14a9a..a1d06a7a 100644
--- a/src/lib/builders/listbox/types.ts
+++ b/src/lib/builders/listbox/types.ts
@@ -2,6 +2,7 @@ import type {
 	EscapeBehaviorType,
 	FloatingConfig,
 	InteractOutsideEvent,
+	PortalConfig,
 } from '$lib/internal/actions/index.js';
 import type { ChangeFn, IdObj } from '$lib/internal/helpers/index.js';
 import type { BuilderReturn, WhenTrue } from '$lib/internal/types.js';
@@ -146,7 +147,7 @@ export type CreateListboxProps<
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * Whether the menu content should be displayed even if it is not open.
diff --git a/src/lib/builders/menu/create.ts b/src/lib/builders/menu/create.ts
index f34a9e38..999479cd 100644
--- a/src/lib/builders/menu/create.ts
+++ b/src/lib/builders/menu/create.ts
@@ -73,7 +73,7 @@ const defaults = {
 	preventScroll: true,
 	escapeBehavior: 'close',
 	closeOnOutsideClick: true,
-	portal: undefined,
+	portal: 'body',
 	loop: false,
 	dir: 'ltr',
 	defaultOpen: false,
diff --git a/src/lib/builders/menu/types.ts b/src/lib/builders/menu/types.ts
index 1c7682ce..73500eeb 100644
--- a/src/lib/builders/menu/types.ts
+++ b/src/lib/builders/menu/types.ts
@@ -2,6 +2,7 @@ import type {
 	EscapeBehaviorType,
 	FloatingConfig,
 	InteractOutsideEvent,
+	PortalConfig,
 } from '$lib/internal/actions/index.js';
 import type { TextDirection } from '$lib/internal/types.js';
 import type { ChangeFn, FocusProp, IdObj } from '$lib/internal/helpers/index.js';
@@ -60,7 +61,7 @@ export type _CreateMenuProps = {
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * Whether or not to close the menu when a click occurs outside of it.
diff --git a/src/lib/builders/menubar/create.ts b/src/lib/builders/menubar/create.ts
index 6873819c..2c824d08 100644
--- a/src/lib/builders/menubar/create.ts
+++ b/src/lib/builders/menubar/create.ts
@@ -65,7 +65,7 @@ export function createMenubar(props?: CreateMenubarProps) {
 	const nextFocusable = withGet(writable<HTMLElement | null>(null));
 	const prevFocusable = withGet(writable<HTMLElement | null>(null));
 	const lastFocusedMenuTrigger = withGet(writable<HTMLElement | null>(null));
-	const closeTimer = withGet(writable(0));
+	// const closeTimer = withGet(writable(0));
 	let scrollRemoved = false;
 
 	const ids = toWritableStores({ ...generateIds(menubarIdParts), ...withDefaults.ids });
@@ -100,7 +100,7 @@ export function createMenubar(props?: CreateMenubarProps) {
 		loop: false,
 		escapeBehavior: 'close',
 		closeOnOutsideClick: true,
-		portal: undefined,
+		portal: 'body',
 		forceVisible: false,
 		defaultOpen: false,
 		typeahead: true,
diff --git a/src/lib/builders/popover/create.ts b/src/lib/builders/popover/create.ts
index 731eb3f0..e0135c6c 100644
--- a/src/lib/builders/popover/create.ts
+++ b/src/lib/builders/popover/create.ts
@@ -19,7 +19,6 @@ import {
 	portalAttr,
 	generateIds,
 	withGet,
-	sleep,
 } from '$lib/internal/helpers/index.js';
 
 import { usePopper, usePortal, type InteractOutsideEvent } from '$lib/internal/actions/index.js';
@@ -40,7 +39,7 @@ const defaults = {
 	preventScroll: false,
 	onOpenChange: undefined,
 	closeOnOutsideClick: true,
-	portal: undefined,
+	portal: 'body',
 	forceVisible: false,
 	openFocus: undefined,
 	closeFocus: undefined,
diff --git a/src/lib/builders/popover/types.ts b/src/lib/builders/popover/types.ts
index 7b528197..106b12d7 100644
--- a/src/lib/builders/popover/types.ts
+++ b/src/lib/builders/popover/types.ts
@@ -2,6 +2,7 @@ import type {
 	EscapeBehaviorType,
 	FloatingConfig,
 	InteractOutsideEvent,
+	PortalConfig,
 } from '$lib/internal/actions/index.js';
 import type { ChangeFn, FocusProp, IdObj } from '$lib/internal/helpers/index.js';
 import type { BuilderReturn } from '$lib/internal/types.js';
@@ -95,7 +96,7 @@ export type CreatePopoverProps = {
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * Whether the menu content should be displayed even if it is not open.
diff --git a/src/lib/builders/radio-group/create.ts b/src/lib/builders/radio-group/create.ts
index 331a5fdf..0b19c758 100644
--- a/src/lib/builders/radio-group/create.ts
+++ b/src/lib/builders/radio-group/create.ts
@@ -16,7 +16,7 @@ import {
 } from '$lib/internal/helpers/index.js';
 import { safeOnMount } from '$lib/internal/helpers/lifecycle.js';
 import type { Defaults, MeltActionReturn } from '$lib/internal/types.js';
-import { derived, writable } from 'svelte/store';
+import { derived, readonly, writable } from 'svelte/store';
 import { createHiddenInput } from '../hidden-input/create.js';
 import type { RadioGroupEvents } from './events.js';
 import type { CreateRadioGroupProps, RadioGroupItemProps } from './types.js';
@@ -27,6 +27,7 @@ const defaults = {
 	disabled: false,
 	required: false,
 	defaultValue: undefined,
+	name: undefined,
 } satisfies Defaults<CreateRadioGroupProps>;
 
 type RadioGroupParts = 'item' | 'hidden-input';
@@ -38,7 +39,7 @@ export function createRadioGroup(props?: CreateRadioGroupProps) {
 
 	// options
 	const options = toWritableStores(omit(withDefaults, 'value'));
-	const { disabled, required, loop, orientation } = options;
+	const { disabled, required, loop, orientation, name: nameProp } = options;
 
 	const valueWritable = withDefaults.value ?? writable(withDefaults.defaultValue);
 	const value = overridable(valueWritable, withDefaults?.onValueChange);
@@ -177,6 +178,7 @@ export function createRadioGroup(props?: CreateRadioGroupProps) {
 
 	const hiddenInput = createHiddenInput({
 		value,
+		name: readonly(nameProp),
 		disabled,
 		required,
 	});
diff --git a/src/lib/builders/radio-group/types.ts b/src/lib/builders/radio-group/types.ts
index f41ae499..6a743655 100644
--- a/src/lib/builders/radio-group/types.ts
+++ b/src/lib/builders/radio-group/types.ts
@@ -20,6 +20,8 @@ export type CreateRadioGroupProps = {
 	 */
 	required?: boolean;
 
+	name?: string;
+
 	/**
 	 * Whether or not the radio group should loop around when the end
 	 * is reached.
diff --git a/src/lib/builders/range-calendar/create.ts b/src/lib/builders/range-calendar/create.ts
index 1353d0b5..bcb34bd0 100644
--- a/src/lib/builders/range-calendar/create.ts
+++ b/src/lib/builders/range-calendar/create.ts
@@ -1096,6 +1096,9 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 			setMonth,
 			isDateDisabled: _isDateDisabled,
 			isDateUnavailable,
+			isSelectionStart,
+			isSelectionEnd,
+			isSelected,
 		},
 		options,
 		ids,
diff --git a/src/lib/builders/slider/create.ts b/src/lib/builders/slider/create.ts
index 124915bf..1046870f 100644
--- a/src/lib/builders/slider/create.ts
+++ b/src/lib/builders/slider/create.ts
@@ -42,7 +42,9 @@ const { name } = createElHelpers('slider');
 export const createSlider = (props?: CreateSliderProps) => {
 	const withDefaults = { ...defaults, ...props } satisfies CreateSliderProps;
 
-	const options = toWritableStores(omit(withDefaults, 'value', 'onValueChange', 'defaultValue'));
+	const options = toWritableStores(
+		omit(withDefaults, 'value', 'onValueChange', 'onValueCommitted', 'defaultValue')
+	);
 	const { min, max, step, orientation, dir, disabled, autoSort } = options;
 
 	const valueWritable = withDefaults.value ?? writable(withDefaults.defaultValue);
@@ -323,6 +325,10 @@ export const createSlider = (props?: CreateSliderProps) => {
 						break;
 					}
 				}
+
+				if (withDefaults?.onValueCommitted) {
+					withDefaults.onValueCommitted(value.get());
+				}
 			});
 
 			return {
@@ -515,6 +521,10 @@ export const createSlider = (props?: CreateSliderProps) => {
 			};
 
 			const pointerUp = () => {
+				if (withDefaults?.onValueCommitted && isActive.get()) {
+					withDefaults.onValueCommitted(value.get());
+				}
+
 				isActive.set(false);
 			};
 
diff --git a/src/lib/builders/slider/types.ts b/src/lib/builders/slider/types.ts
index 678367c1..df2451b8 100644
--- a/src/lib/builders/slider/types.ts
+++ b/src/lib/builders/slider/types.ts
@@ -27,6 +27,11 @@ export type CreateSliderProps = {
 	 */
 	onValueChange?: ChangeFn<number[]>;
 
+	/**
+	 * The callback invoked when the user has committed the value of the slider.
+	 */
+	onValueCommitted?: (value: number[]) => void;
+
 	/**
 	 * The minimum value of the slider.
 	 *
diff --git a/src/lib/builders/table-of-contents/create.ts b/src/lib/builders/table-of-contents/create.ts
index 978d7345..6a91767a 100644
--- a/src/lib/builders/table-of-contents/create.ts
+++ b/src/lib/builders/table-of-contents/create.ts
@@ -32,6 +32,7 @@ export function createTableOfContents(args: CreateTableOfContentsArgs) {
 		selector,
 		exclude,
 		activeType,
+		rootMargin,
 		scrollBehaviour,
 		scrollOffset,
 		headingFilterFn,
@@ -301,6 +302,7 @@ export function createTableOfContents(args: CreateTableOfContentsArgs) {
 			observer = new IntersectionObserver(handleElementObservation, {
 				root: null,
 				threshold: observer_threshold,
+				rootMargin,
 			});
 			elementsList.forEach((el) => observer?.observe(el));
 		}
diff --git a/src/lib/builders/table-of-contents/types.ts b/src/lib/builders/table-of-contents/types.ts
index 4a422a7e..1bce7dc7 100644
--- a/src/lib/builders/table-of-contents/types.ts
+++ b/src/lib/builders/table-of-contents/types.ts
@@ -48,6 +48,10 @@ export type CreateTableOfContentsArgs = {
 	 * - 'highest-parents': Parents of the heading with the highest visible content are also considered active.
 	 */
 	activeType?: ActiveType;
+	/**
+	 * The root margin for the intersection observer. Refer to the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) for more information.
+	 */
+	rootMargin?: string;
 	/**
 	 * A custom filter function for headings.
 	 */
diff --git a/src/lib/builders/tags-input/create.ts b/src/lib/builders/tags-input/create.ts
index ec7b0ba4..85646946 100644
--- a/src/lib/builders/tags-input/create.ts
+++ b/src/lib/builders/tags-input/create.ts
@@ -339,11 +339,17 @@ export function createTagsInput(props?: CreateTagsInputProps) {
 					if (!addOnPaste.get()) return;
 					e.preventDefault();
 
-					// Update value with the pasted text or set invalid
-					if (isInputValid(pastedText) && (await addTag(pastedText))) {
-						node.value = '';
-					} else {
-						inputInvalid.set(true);
+					const newTags = pastedText.split(',');
+					addTag: for (let i = 0; i < newTags.length; i++) {
+						const newTag = newTags[i];
+						// Update value with the pasted tag or set invalid
+						if (isInputValid(newTag) && (await addTag(newTag))) {
+							continue addTag;
+						} else {
+							node.value = newTags.slice(i).join(',');
+							inputInvalid.set(true);
+							return;
+						}
 					}
 				}),
 				addMeltEventListener(node, 'keydown', async (e) => {
diff --git a/src/lib/builders/toast/create.ts b/src/lib/builders/toast/create.ts
index 2576e73a..640ce466 100644
--- a/src/lib/builders/toast/create.ts
+++ b/src/lib/builders/toast/create.ts
@@ -21,13 +21,14 @@ const { name } = createElHelpers<ToastParts>('toast');
 const defaults = {
 	closeDelay: 5000,
 	type: 'foreground',
+	hover: 'pause',
 } satisfies CreateToasterProps;
 
 export function createToaster<T = object>(props?: CreateToasterProps) {
 	const withDefaults = { ...defaults, ...props } satisfies CreateToasterProps;
 
 	const options = toWritableStores(withDefaults);
-	const { closeDelay, type } = options;
+	const { closeDelay, type, hover } = options;
 
 	const toastsMap = writable(new Map<string, Toast<T>>());
 
@@ -98,6 +99,23 @@ export function createToaster<T = object>(props?: CreateToasterProps) {
 		});
 	};
 
+	const pauseToastTimer = (currentToast: Toast<T>) => {
+		if (currentToast.timeout !== null) {
+			window.clearTimeout(currentToast.timeout);
+		}
+		currentToast.pausedAt = performance.now();
+	};
+	const restartToastTimer = (currentToast: Toast<T>) => {
+		const pausedAt = currentToast.pausedAt ?? currentToast.createdAt;
+		const elapsed = pausedAt - currentToast.createdAt - currentToast.pauseDuration;
+		const remaining = currentToast.closeDelay - elapsed;
+		currentToast.timeout = window.setTimeout(() => {
+			removeToast(currentToast.id);
+		}, remaining);
+		currentToast.pauseDuration += performance.now() - pausedAt;
+		currentToast.pausedAt = undefined;
+	};
+
 	const content = makeElement(name('content'), {
 		stores: toastsMap,
 		returned: ($toasts) => {
@@ -123,31 +141,42 @@ export function createToaster<T = object>(props?: CreateToasterProps) {
 				addMeltEventListener(node, 'pointerenter', (e) => {
 					if (isTouch(e)) return;
 					toastsMap.update((currentMap) => {
-						const currentToast = currentMap.get(node.id);
-						if (!currentToast || currentToast.closeDelay === 0) return currentMap;
-
-						if (currentToast.timeout !== null) {
-							window.clearTimeout(currentToast.timeout);
+						switch (hover.get()) {
+							case 'pause': {
+								const currentToast = currentMap.get(node.id);
+								if (!currentToast || currentToast.closeDelay === 0) return currentMap;
+								pauseToastTimer(currentToast);
+								break;
+							}
+							case 'pause-all':
+								for (const [, currentToast] of currentMap) {
+									if (!currentToast || currentToast.closeDelay === 0) continue;
+									pauseToastTimer(currentToast);
+								}
+								break;
 						}
-						currentToast.pausedAt = performance.now();
 						return new Map(currentMap);
 					});
 				}),
 				addMeltEventListener(node, 'pointerleave', (e) => {
 					if (isTouch(e)) return;
 					toastsMap.update((currentMap) => {
-						const currentToast = currentMap.get(node.id);
-						if (!currentToast || currentToast.closeDelay === 0) return currentMap;
-
-						const pausedAt = currentToast.pausedAt ?? currentToast.createdAt;
-						const elapsed = pausedAt - currentToast.createdAt - currentToast.pauseDuration;
-						const remaining = currentToast.closeDelay - elapsed;
-						currentToast.timeout = window.setTimeout(() => {
-							removeToast(node.id);
-						}, remaining);
-
-						currentToast.pauseDuration += performance.now() - pausedAt;
-						currentToast.pausedAt = undefined;
+						switch (hover.get()) {
+							case 'pause': {
+								const currentToast = currentMap.get(node.id);
+								if (!currentToast || currentToast.closeDelay === 0) return currentMap;
+								restartToastTimer(currentToast);
+								break;
+							}
+
+							case 'pause-all':
+								for (const [, currentToast] of currentMap) {
+									if (!currentToast || currentToast.closeDelay === 0) continue;
+									restartToastTimer(currentToast);
+								}
+								break;
+						}
+
 						return new Map(currentMap);
 					});
 				}),
diff --git a/src/lib/builders/toast/types.ts b/src/lib/builders/toast/types.ts
index 82af1ec8..fd56622b 100644
--- a/src/lib/builders/toast/types.ts
+++ b/src/lib/builders/toast/types.ts
@@ -8,9 +8,10 @@ export type CreateToasterProps = {
 	// If set to 0, the toast will not be automatically closed.
 	closeDelay?: number;
 	type?: 'foreground' | 'background';
+	hover?: 'pause' | 'pause-all' | null;
 };
 
-export type AddToastProps<T = object> = CreateToasterProps & {
+export type AddToastProps<T = object> = Omit<CreateToasterProps, 'hover'> & {
 	data: T;
 };
 
diff --git a/src/lib/builders/tooltip/create.ts b/src/lib/builders/tooltip/create.ts
index 31aa5c78..a07a336f 100644
--- a/src/lib/builders/tooltip/create.ts
+++ b/src/lib/builders/tooltip/create.ts
@@ -43,7 +43,7 @@ const defaults = {
 	openDelay: 1000,
 	closeDelay: 0,
 	forceVisible: false,
-	portal: undefined,
+	portal: 'body',
 	escapeBehavior: 'close',
 	disableHoverableContent: false,
 	group: undefined,
diff --git a/src/lib/builders/tooltip/types.ts b/src/lib/builders/tooltip/types.ts
index 224ad831..45d40aa4 100644
--- a/src/lib/builders/tooltip/types.ts
+++ b/src/lib/builders/tooltip/types.ts
@@ -1,4 +1,8 @@
-import type { EscapeBehaviorType, FloatingConfig } from '$lib/internal/actions/index.js';
+import type {
+	EscapeBehaviorType,
+	FloatingConfig,
+	PortalConfig,
+} from '$lib/internal/actions/index.js';
 import type { ChangeFn, IdObj } from '$lib/internal/helpers/index.js';
 import type { BuilderReturn } from '$lib/internal/types.js';
 import type { Writable } from 'svelte/store';
@@ -37,7 +41,7 @@ export type CreateTooltipProps = {
 	 *
 	 * @default 'body'
 	 */
-	portal?: HTMLElement | string | null;
+	portal?: PortalConfig | null;
 
 	/**
 	 * Optionally override the default ids we assign to the elements
diff --git a/src/lib/internal/actions/floating/action.ts b/src/lib/internal/actions/floating/action.ts
index 4847a13e..4ba816f8 100644
--- a/src/lib/internal/actions/floating/action.ts
+++ b/src/lib/internal/actions/floating/action.ts
@@ -13,7 +13,7 @@ import {
 	autoUpdate,
 } from '@floating-ui/dom';
 import type { FloatingConfig } from './types.js';
-import { isHTMLElement, noop } from '$lib/internal/helpers/index.js';
+import { isHTMLElement, isObject, noop } from '$lib/internal/helpers/index.js';
 import type { Placement, VirtualElement } from '@floating-ui/core';
 
 const defaultConfig = {
@@ -58,6 +58,7 @@ export function useFloating(
 			flip({
 				boundary: options.boundary,
 				padding: options.overflowPadding,
+				...(isObject(options.flip) && options.flip),
 			})
 		);
 	}
diff --git a/src/lib/internal/actions/floating/types.ts b/src/lib/internal/actions/floating/types.ts
index 0fa7346d..c7d02585 100644
--- a/src/lib/internal/actions/floating/types.ts
+++ b/src/lib/internal/actions/floating/types.ts
@@ -2,6 +2,7 @@
 // Source: https://github.com/grail-ui/grail-ui
 // https://github.com/grail-ui/grail-ui/tree/master/packages/grail-ui/src/floating/floating.types.ts
 
+import type { FlipOptions } from '@floating-ui/core';
 import type { Boundary } from '@floating-ui/dom';
 
 /**
@@ -67,7 +68,7 @@ export type FloatingConfig = {
 	 *
 	 * @see https://floating-ui.com/docs/flip
 	 */
-	flip?: boolean;
+	flip?: boolean | FlipOptions;
 
 	/**
 	 * Whether the floating element can overlap the reference element.
diff --git a/src/lib/internal/actions/portal.ts b/src/lib/internal/actions/portal.ts
index f2581099..a762abb6 100644
--- a/src/lib/internal/actions/portal.ts
+++ b/src/lib/internal/actions/portal.ts
@@ -13,8 +13,9 @@ export const usePortal = ((el, target = 'body') => {
 		};
 	}
 
-	async function update(newTarget: HTMLElement | string | undefined) {
+	async function update(newTarget: PortalConfig = 'body') {
 		target = newTarget;
+
 		if (typeof target === 'string') {
 			targetEl = document.querySelector(target);
 			if (targetEl === null) {
diff --git a/src/lib/internal/helpers/date/calendar.ts b/src/lib/internal/helpers/date/calendar.ts
index 4e056364..532cf6c8 100644
--- a/src/lib/internal/helpers/date/calendar.ts
+++ b/src/lib/internal/helpers/date/calendar.ts
@@ -94,7 +94,7 @@ function createMonth(props: CreateMonthProps): Month<DateValue> {
 		let startFrom = nextMonthDays[nextMonthDays.length - 1];
 
 		if (!startFrom) {
-			startFrom = dateObj.add({ months: 1 }).set({ day: 1 });
+			startFrom = endOfMonth(dateObj);
 		}
 
 		const extraDaysArray = Array.from({ length: extraDays }, (_, i) => {
diff --git a/src/lib/internal/helpers/object.ts b/src/lib/internal/helpers/object.ts
index 49add7e2..fffcc644 100644
--- a/src/lib/internal/helpers/object.ts
+++ b/src/lib/internal/helpers/object.ts
@@ -57,6 +57,7 @@ export function removeUndefined<T extends object>(
 	for (const key in obj) {
 		const value = obj[key];
 		if (value !== undefined) {
+			// eslint-disable-next-line @typescript-eslint/no-explicit-any
 			result[key] = value as any;
 		}
 	}
diff --git a/src/lib/internal/helpers/store/toReadableStores.ts b/src/lib/internal/helpers/store/toReadableStores.ts
index cfd5f0f0..bc7c7078 100644
--- a/src/lib/internal/helpers/store/toReadableStores.ts
+++ b/src/lib/internal/helpers/store/toReadableStores.ts
@@ -3,6 +3,7 @@ import { isReadable } from '../is.js';
 import { withGet, type WithGet } from '../withGet.js';
 import type { MaybeReadable } from '$lib/internal/types.js';
 
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
 type TODO = any;
 
 export type ToReadableStores<T extends Record<string, unknown>> = {
@@ -34,5 +35,5 @@ export function toReadableStores<T extends Record<string, unknown>>(
 		}
 	});
 
-	return result as any;
+	return result as TODO;
 }


Test patch:
diff --git a/src/tests/calendar/CalendarTest.svelte b/src/tests/calendar/CalendarTest.svelte
index 81b5246f..e3aaff46 100644
--- a/src/tests/calendar/CalendarTest.svelte
+++ b/src/tests/calendar/CalendarTest.svelte
@@ -32,6 +32,7 @@
 		states: { value: insideValue, months, headingValue, weekdays },
 		options: {
 			weekdayFormat: weekdayFormatOption,
+			// eslint-disable-next-line @typescript-eslint/no-unused-vars
 			numberOfMonths: numberOfMonthsOption,
 			fixedWeeks: fixedWeeksOption,
 			weekStartsOn: weekStartsOnOption,
diff --git a/src/tests/date-picker/DatePickerTest.svelte b/src/tests/date-picker/DatePickerTest.svelte
index 56a2ece7..e7beeb78 100644
--- a/src/tests/date-picker/DatePickerTest.svelte
+++ b/src/tests/date-picker/DatePickerTest.svelte
@@ -49,6 +49,7 @@
 		options: {
 			locale: insideLocale,
 			weekdayFormat: weekdayFormatOption,
+			// eslint-disable-next-line @typescript-eslint/no-unused-vars
 			numberOfMonths: numberOfMonthsOption,
 			fixedWeeks: fixedWeeksOption,
 			weekStartsOn: weekStartsOnOption,
diff --git a/src/tests/portal/PopoverSelect.svelte b/src/tests/portal/PopoverSelect.svelte
index 28020e73..893c6df7 100644
--- a/src/tests/portal/PopoverSelect.svelte
+++ b/src/tests/portal/PopoverSelect.svelte
@@ -1,5 +1,5 @@
 <script lang="ts">
-	import { createPopover, createSelect, melt, type CreateSelectProps } from '$lib/index.js';
+	import { createPopover, createSelect, melt } from '$lib/index.js';
 	import { Settings2 } from '$icons/index.js';
 	import type { PortalConfig } from '$lib/internal/actions/portal.js';
 
diff --git a/src/tests/radio-group/RadioGroup.spec.ts b/src/tests/radio-group/RadioGroup.spec.ts
index deab96dd..29018ee2 100644
--- a/src/tests/radio-group/RadioGroup.spec.ts
+++ b/src/tests/radio-group/RadioGroup.spec.ts
@@ -84,4 +84,9 @@ describe('Radio Group', () => {
 		expect(els[2]).toHaveFocus();
 		expect(els[1]).not.toHaveFocus();
 	});
+
+	it('has specified name on hidden input', async () => {
+		const { getByTestId } = setup({ name: 'name' });
+		expect(getByTestId('input')).toHaveAttribute('name', 'name');
+	});
 });
diff --git a/src/tests/radio-group/RadioGroupTest.svelte b/src/tests/radio-group/RadioGroupTest.svelte
index 111c1785..b1acb7ab 100644
--- a/src/tests/radio-group/RadioGroupTest.svelte
+++ b/src/tests/radio-group/RadioGroupTest.svelte
@@ -16,6 +16,7 @@
 	export let disabled: CreateRadioGroupProps['disabled'] = undefined;
 	export let onValueChange: CreateRadioGroupProps['onValueChange'] = undefined;
 	export let required: CreateRadioGroupProps['required'] = undefined;
+	export let name: CreateRadioGroupProps['name'] = undefined;
 	export let items: Item[] = [
 		{ value: 'a', disabled: false },
 		{ value: 'b', disabled: false },
@@ -24,7 +25,7 @@
 	];
 
 	const {
-		elements: { root, item },
+		elements: { root, item, hiddenInput },
 		states: { value: localValue },
 	} = createRadioGroup({
 		value,
@@ -32,6 +33,7 @@
 		onValueChange,
 		disabled,
 		required,
+		name,
 		...removeUndefined($$restProps),
 	});
 </script>
@@ -39,6 +41,7 @@
 <main>
 	<div data-testid="value">{$localValue}</div>
 	<form>
+		<input use:melt={$hiddenInput} data-testid="input" />
 		<label id="radio-group-label" for="radio-group" data-testid="label"> Airplane mode </label>
 		<div use:melt={$root} data-testid="root">
 			{#each items as radioItem}
diff --git a/src/tests/range-calendar/RangeCalendarTest.svelte b/src/tests/range-calendar/RangeCalendarTest.svelte
index 4961f63b..7c0a6a10 100644
--- a/src/tests/range-calendar/RangeCalendarTest.svelte
+++ b/src/tests/range-calendar/RangeCalendarTest.svelte
@@ -29,6 +29,7 @@
 		states: { value: insideValue, months, headingValue, weekdays },
 		options: {
 			weekdayFormat: weekdayFormatOption,
+			// eslint-disable-next-line @typescript-eslint/no-unused-vars
 			numberOfMonths: numberOfMonthsOption,
 			fixedWeeks: fixedWeeksOption,
 			locale: localeOption,