{"_id":"@bottom-sheet-kit/svelte","_rev":"2-073ea1cac247a9de005de812368c207f","name":"@bottom-sheet-kit/svelte","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@bottom-sheet-kit/svelte","version":"0.1.0","keywords":["svelte","svelte5","bottom-sheet","modal","drawer","daisyui","tailwindcss","rtl","a11y"],"license":"MIT","_id":"@bottom-sheet-kit/svelte@0.1.0","maintainers":[{"name":"karbal","email":"mehdi.karbal@gmail.com"}],"dist":{"shasum":"85b2ccc7ca169aaaac0f897904bc4ebbe9a83a8f","tarball":"https://registry.npmjs.org/@bottom-sheet-kit/svelte/-/svelte-0.1.0.tgz","fileCount":16,"integrity":"sha512-SYH6yTL8yi7/gVAjLPP6yjOdE7OH+ZOIH3GPPMY4JVfuPrehCx8A/ZmFOZGxeG8qJ4N1farlrsSzi+y+H/S7EA==","signatures":[{"sig":"MEQCIBxlWw0W6GlIhYQXwJL89ILnPp6de+bcUVYSzwzclJn5AiBoNtYsoJ+FQ5zXbJnn84UXU/fBN/6xEDN/TANXhI9JCA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":90005},"type":"module","_from":"file:bottom-sheet-kit-svelte-0.1.0.tgz","types":"./dist/index.d.ts","svelte":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","svelte":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"node scripts/build.mjs","typecheck":"svelte-check --tsconfig ./tsconfig.json","test:watch":"vitest","typecheck:test":"tsc -p tsconfig.test.json"},"_npmUser":{"name":"karbal","email":"mehdi.karbal@gmail.com"},"_resolved":"/private/var/folders/b7/dw7hld9n75zf5nhnx_q08mqh0000gn/T/f341d9d18e531a0d3e55666f99ffb179/bottom-sheet-kit-svelte-0.1.0.tgz","_integrity":"sha512-SYH6yTL8yi7/gVAjLPP6yjOdE7OH+ZOIH3GPPMY4JVfuPrehCx8A/ZmFOZGxeG8qJ4N1farlrsSzi+y+H/S7EA==","_npmVersion":"10.9.8","description":"A primitive, headless-friendly bottom sheet component for Svelte 5 — DaisyUI styled, RTL-native, fully overridable via snippets.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^25.0.0","svelte":"^5.0.0","vitest":"^2.1.0","esbuild":"^0.24.0","typescript":"^5.6.0","@types/node":"^22.0.0","svelte-check":"^4.0.0","@sveltejs/package":"^2.3.0","dts-bundle-generator":"^9.5.1","@testing-library/svelte":"^5.2.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0","@sveltejs/vite-plugin-svelte":"^4.0.0"},"peerDependencies":{"svelte":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/svelte_0.1.0_1788616888248_0.5960071553843971","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"_id":"@bottom-sheet-kit/svelte@0.1.1","dist":{"shasum":"2adcf2cf571b85ab0f824ed1d583a553dd867b0a","tarball":"https://registry.npmjs.org/@bottom-sheet-kit/svelte/-/svelte-0.1.1.tgz","fileCount":16,"integrity":"sha512-HU5NT19beuGHbEGav0zvCFwdf3vYLHZMw88Pd7mA8R/BQUVF+SgygUuqmHIxEeRrwwRyygIOTqUC0MDfgI62+w==","signatures":[{"sig":"MEQCIFC7Ut8RT46NTakJb2ebjeMv6xVQU6ku0+ruk+o5EI2DAiAVSDbW5GKeGPSfVMDEK8d05fgLuYsh/rLDroijBbbJ+Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDe3UYYi20SwVazdtY3Q686J7EcFw87j3MVUwWPmQCghgIgXsK5LotHhyQcczpAdwGp2dCB/8GdVTyJJZ8/EXp62+U="}],"unpackedSize":112208},"name":"@bottom-sheet-kit/svelte","type":"module","_from":"file:bottom-sheet-kit-svelte-0.1.1.tgz","types":"./dist/index.d.ts","svelte":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","svelte":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"test":"vitest run","build":"node scripts/build.mjs","typecheck":"svelte-check --tsconfig ./tsconfig.json","test:watch":"vitest","typecheck:test":"tsc -p tsconfig.test.json"},"version":"0.1.1","_npmUser":{"name":"karbal","email":"mehdi.karbal@gmail.com"},"keywords":["svelte","svelte5","bottom-sheet","modal","drawer","daisyui","tailwindcss","rtl","a11y"],"_resolved":"/private/var/folders/b7/dw7hld9n75zf5nhnx_q08mqh0000gn/T/c24562fab8f6259a4450afce9b638a4b/bottom-sheet-kit-svelte-0.1.1.tgz","_integrity":"sha512-HU5NT19beuGHbEGav0zvCFwdf3vYLHZMw88Pd7mA8R/BQUVF+SgygUuqmHIxEeRrwwRyygIOTqUC0MDfgI62+w==","_npmVersion":"10.9.8","description":"A primitive, headless-friendly bottom sheet component for Svelte 5 — DaisyUI styled, RTL-native, fully overridable via snippets.","directories":{},"maintainers":[{"name":"karbal","email":"mehdi.karbal@gmail.com"}],"sideEffects":false,"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^25.0.0","svelte":"^5.0.0","vitest":"^2.1.0","esbuild":"^0.24.0","typescript":"^5.6.0","@types/node":"^22.0.0","svelte-check":"^4.0.0","@sveltejs/package":"^2.3.0","dts-bundle-generator":"^9.5.1","@testing-library/svelte":"^5.2.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0","@sveltejs/vite-plugin-svelte":"^4.0.0"},"peerDependencies":{"svelte":"^5.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/svelte_0.1.1_1788630390318_0.06050459239077721"}}},"time":{"created":"2026-09-05T14:01:28.021Z","modified":"2026-09-05T17:46:30.611Z","0.1.0":"2026-09-05T14:01:28.393Z","0.1.1":"2026-09-05T17:46:30.437Z"},"license":"MIT","keywords":["svelte","svelte5","bottom-sheet","modal","drawer","daisyui","tailwindcss","rtl","a11y"],"description":"A primitive, headless-friendly bottom sheet component for Svelte 5 — DaisyUI styled, RTL-native, fully overridable via snippets.","maintainers":[{"name":"karbal","email":"mehdi.karbal@gmail.com"}],"readme":"# @bottom-sheet-kit/svelte\n\nA primitive, headless-friendly bottom sheet for **Svelte 5** (runes), SSR-safe.\nStyled with **DaisyUI** + **Tailwind CSS v4**, native **RTL** support, and every\npart overridable via snippets. `dist/index.js` bundles the pure logic\n(constants, utils, types) into one minified file, plus one rolled-up\n`dist/index.d.ts`; `.svelte` component files and the `SheetController` reactive\nmodule ship as source (the latter is a `.svelte.js`-suffixed file, Svelte 5's\nmechanism for a package to share reactive state — it's compiled by your own\nVite/SvelteKit setup, same as the components) so SSR keeps working correctly.\n\n- **Flutter-inspired** — free-resize drag, named detents (`peek`, `half`, `full`, …), velocity-aware snap/close\n- **Composable** — use the pre-wired `<BottomSheet>` shell, or the raw primitives (`SheetPanel`, `SheetHandle`, `SheetBackdrop`, `SheetContent`) plus an injectable `SheetController` to build a fully custom sheet\n- **Fully overridable** — replace the handle or backdrop entirely via snippets; the content area is just a slot\n- **Accessible** — `role=\"dialog\"`, `aria-modal`, `aria-expanded`, keyboard toggle (Enter/Space) on the handle, focus-visible ring\n- **RTL-native** — uses logical (`inset-inline`) Tailwind utilities; flips automatically under `dir=\"rtl\"`\n- **Dark-mode-native** — uses DaisyUI semantic color tokens (`base-100`, `base-content`, `base-300`), so it follows whatever DaisyUI theme is active\n- **Responsive** — full-width sheet on small screens, capped and centered on `sm:` and above\n- **SSR-safe** — every DOM/`window`/`document` access is guarded; portal + controller no-op during server render\n\n## Install\n\n```bash\nnpm install @bottom-sheet-kit/svelte\n```\n\n`svelte@^5` is a peer dependency. Tailwind CSS v4 + DaisyUI v5 must be\nconfigured in the host app, since this package ships only class names, not CSS.\n\n## Quick start\n\n```svelte\n<script lang=\"ts\">\n\timport { BottomSheet } from '@bottom-sheet-kit/svelte';\n\n\tlet open = $state(false);\n</script>\n\n<button onclick={() => (open = true)}>Open</button>\n\n{#if open}\n\t<BottomSheet startOpen initialPercent={50} onClose={() => (open = false)}>\n\t\t{#snippet children(ctrl)}\n\t\t\t<div class=\"p-5\">\n\t\t\t\t<button onclick={() => ctrl.close()}>Close</button>\n\t\t\t</div>\n\t\t{/snippet}\n\t</BottomSheet>\n{/if}\n```\n\n## `<BottomSheet>` props\n\n| Prop                  | Type                              | Default   | Notes                                                            |\n| --------------------- | ---------------------------------- | --------- | ------------------------------------------------------------------ |\n| `controller`          | `SheetController`                 | —         | Provide your own to control the sheet from a sibling button.      |\n| `initialPercent`      | `number`                          | `50`      | Forwarded to the internal controller when none is given.          |\n| `minPercent`          | `number`                          | `15`      | Below this, releasing the drag auto-closes.                       |\n| `maxPercent`          | `number`                          | `100`     | Sheet cannot be dragged above this.                                |\n| `snapPoints`          | `number[]`                        | —         | Omit for free-resize mode (sheet stays wherever released).        |\n| `closeVelocity`       | `number`                          | `500`     | px/s flick speed that force-closes regardless of position.        |\n| `draggable`           | `boolean`                         | `true`    | Disable for programmatic-only control.                            |\n| `closeOnOutsideClick` | `boolean`                         | `true`    | Backdrop tap closes the sheet.                                     |\n| `showBackdrop`        | `boolean`                         | `true`    |                                                                     |\n| `startOpen`           | `boolean`                         | `false`   |                                                                     |\n| `onOpen` / `onClose`  | `() => void`                      | —         |                                                                     |\n| `onPositionChange`    | `(percent: number) => void`       | —         | Fires continuously during drag/animation.                          |\n| `handleVariant`       | `'bar' \\| 'dots' \\| 'none'`       | `'bar'`   |                                                                     |\n| `handle` / `backdrop` | `Snippet<[SheetController]>`      | —         | Full override of the built-in handle/backdrop.                     |\n| `class` / `sheetClass`| `string`                          | —         | Extra classes on the portal root / panel respectively.             |\n| `hidden`              | `boolean`                         | `false`   | Keeps the sheet mounted (so its `ResizeObserver` stays alive) but visually hidden — e.g. desktop mode. |\n\n### Named detents\n\n```ts\nimport { sheetDetent } from '@bottom-sheet-kit/svelte';\n// hidden=0, peek=10, quarter=25, half=50, threeQuarters=75, full=100\n\n<BottomSheet snapPoints={[sheetDetent.peek, sheetDetent.half, sheetDetent.full]}>\n```\n\n### Raw primitives (fully custom UI)\n\n```svelte\n<script lang=\"ts\">\n\timport { SheetController, SheetPanel, SheetHandle, SheetContent } from '@bottom-sheet-kit/svelte';\n\n\tconst ctrl = new SheetController({ snapPoints: [25, 50, 100] });\n\tlet containerEl = $state<HTMLElement>();\n</script>\n\n<div bind:this={containerEl}>\n\t{#if containerEl}\n\t\t<SheetPanel controller={ctrl} {containerEl}>\n\t\t\t<SheetHandle controller={ctrl} variant=\"dots\" />\n\t\t\t<SheetContent controller={ctrl}>Custom content…</SheetContent>\n\t\t</SheetPanel>\n\t{/if}\n</div>\n```\n\n## `SheetController`\n\nThe state/behaviour brain — a plain class using `$state` runes, with no DOM or\ntemplate of its own. Create it outside any component to share it with sibling\ntrigger buttons, headers, etc.\n\n**Reactive state**: `currentPercent`, `state` (`closed│open│dragging│animating`), `backdropOpacity`, `isDragging`, `isAnimating`, `isOpen`.\n\n**Methods**: `open(percent?)`, `close()`, `snapTo(percent)`.\n\n## Snap & release algorithm\n\nOn pointer release, in priority order:\n\n1. **Velocity close** — a downward flick faster than `closeVelocity` closes unconditionally.\n2. **Position close** — below `minPercent` (and not rescued by an upward flick) closes.\n3. **Snap to nearest** (only when `snapPoints` is explicit) — with velocity bias toward the next point in the drag direction. Without explicit `snapPoints`, the sheet stays wherever it was released (\"free-resize\" mode).\n\n## Scroll-lock coordination\n\n`SheetContent` prevents inner scrolling from fighting the drag-to-resize gesture:\nat scroll-top a downward drag resizes the sheet; once scrolled, a downward drag\nscrolls the content instead. Scroll position resets to top whenever the sheet closes.\n\n## Low-level utils\n\nThe pure math (`percentToTranslateY`, `resolveReleaseTarget`, `computeVelocity`,\n`normaliseSnapPoints`, …) is exported from the package root for custom\nintegrations or testing — see `src/utils/sheet.ts`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}