forked from melt-ui/melt-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Builder: Scroll Area (melt-ui#908)
Co-authored-by: tglide <26071571+TGlide@users.noreply.github.com> Co-authored-by: anatolzak <53095479+anatolzak@users.noreply.github.com>
- Loading branch information
1 parent
b9d9ba3
commit b9e8486
Showing
23 changed files
with
1,809 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@melt-ui/svelte": minor | ||
--- | ||
|
||
New Builder: Scroll Area |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
title: Scroll Area | ||
description: Provides consistent scrollbars across platforms. | ||
--- | ||
|
||
<script> | ||
import { APIReference, Preview, Callout } from '$docs/components' | ||
import { A } from '$docs/components/markdown'; | ||
export let snippets | ||
export let previews | ||
export let schemas | ||
</script> | ||
|
||
## Anatomy | ||
|
||
- **Root**: The container that wraps all parts of the scroll area | ||
- **Viewport**: A container that wraps the scrollable content | ||
- **Content**: The scrollable content | ||
- **Corner**: The corner element displayed when both scrollbars are visible | ||
- **ScrollbarX**: The track of the X scrollbar | ||
- **ThumbX**: The thumb of the X scrollbar | ||
- **ScrollbarY**: The track of the Y scrollbar | ||
- **ThumbY**: The thumb of the Y scrollbar | ||
|
||
## Examples | ||
|
||
### Always | ||
|
||
When the `type` is set to `always`, the scrollbars will always be visible. | ||
|
||
<Preview code={snippets.always} variant="dark" size="auto"> | ||
<svelte:component this={previews.always} /> | ||
</Preview> | ||
|
||
### Auto | ||
|
||
When the `type` is set to `auto`, the scrollbars will only be visible when the content overflows. | ||
|
||
<Preview code={snippets.auto} variant="dark" size="auto"> | ||
<svelte:component this={previews.auto} /> | ||
</Preview> | ||
|
||
### Hover | ||
|
||
When the `type` is set to `hover`, the scrollbars will only be visible when the mouse is over the | ||
scroll area. | ||
|
||
<Preview code={snippets.hover} variant="dark" size="auto"> | ||
<svelte:component this={previews.hover} /> | ||
</Preview> | ||
|
||
### Scroll | ||
|
||
When the `type` is set to `scroll`, the scrollbars will only be visible when the user is scrolling. | ||
|
||
<Preview code={snippets.scroll} variant="dark" size="auto"> | ||
<svelte:component this={previews.scroll} /> | ||
</Preview> | ||
|
||
## API Reference | ||
|
||
<APIReference {schemas} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { ATTRS } from '$docs/constants.js'; | ||
import { builderSchema, elementSchema } from '$docs/utils/index.js'; | ||
import type { BuilderData } from './index.js'; | ||
import { scrollAreaIdParts } from '$lib/builders/scroll-area/create.js'; | ||
|
||
/** | ||
* Props that are also returned in the form of stores via the `options` property. | ||
*/ | ||
const OPTION_PROPS = [ | ||
{ | ||
name: 'type', | ||
type: ['"auto"', '"always"', '"scroll"', '"hover"'], | ||
default: '"hover"', | ||
description: 'Determins when the scrollbar should be visible.', | ||
}, | ||
{ | ||
name: 'hideDelay', | ||
type: 'number', | ||
default: '600', | ||
description: | ||
'When the `type` is `"scroll"` or `"hover"`, this determines how long the scrollbar should be visible after the user either stops scrolling or stops hovering over the scroll area.', | ||
}, | ||
{ | ||
name: 'dir', | ||
type: ['ltr', 'rtl'], | ||
default: 'ltr', | ||
description: 'The reading direction of the scroll area.', | ||
}, | ||
]; | ||
|
||
const BUILDER_NAME = 'scroll area'; | ||
|
||
const builder = builderSchema(BUILDER_NAME, { | ||
ids: scrollAreaIdParts, | ||
title: 'createScrollArea', | ||
props: OPTION_PROPS, | ||
elements: [ | ||
{ | ||
name: 'root', | ||
description: 'The container that wraps all parts of the scroll area.', | ||
}, | ||
{ | ||
name: 'viewport', | ||
description: | ||
'A container that wraps the scrollable content and is used to calculate the scrollbar size.', | ||
}, | ||
{ | ||
name: 'content', | ||
description: 'The scrollable content.', | ||
}, | ||
{ | ||
name: 'scrollbarX', | ||
description: 'The track of the horizontal scrollbar.', | ||
}, | ||
{ | ||
name: 'thumbX', | ||
description: 'The thumb of the horizontal scrollbar.', | ||
}, | ||
{ | ||
name: 'scrollbarY', | ||
description: 'The track of the vertical scrollbar.', | ||
}, | ||
{ | ||
name: 'thumbY', | ||
description: 'The thumb of the vertical scrollbar.', | ||
}, | ||
], | ||
options: OPTION_PROPS, | ||
}); | ||
|
||
const root = elementSchema('root', { | ||
description: 'The container that wraps all parts of the scroll area.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-melt-scroll-area', | ||
value: ATTRS.MELT('scroll area root'), | ||
}, | ||
], | ||
}); | ||
|
||
const viewport = elementSchema('viewport', { | ||
description: | ||
'The container that wraps the scrollable content and is used to calculate the scrollbar size.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-melt-scroll-area-viewport', | ||
value: ATTRS.MELT('scroll area viewport'), | ||
}, | ||
], | ||
}); | ||
|
||
const content = elementSchema('content', { | ||
description: 'The scrollable content. This is the element that will be scrolled.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-melt-scroll-area-content', | ||
value: ATTRS.MELT('scroll area content'), | ||
}, | ||
], | ||
}); | ||
|
||
const scrollbarX = elementSchema('scrollbarX', { | ||
description: 'The track of the horizontal scrollbar.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-state', | ||
value: '`"visible" | "hidden"`', | ||
}, | ||
{ | ||
name: 'data-melt-scroll-area-scrollbar', | ||
value: ATTRS.MELT('scroll area scrollbar'), | ||
}, | ||
], | ||
events: ['pointerdown', 'pointerup', 'pointermove'], | ||
}); | ||
const thumbX = elementSchema('thumbX', { | ||
description: 'The thumb of the horizontal scrollbar.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-state', | ||
value: '`"visible" | "hidden"`', | ||
}, | ||
{ | ||
name: 'data-melt-scroll-area-thumb', | ||
value: ATTRS.MELT('scroll area thumb'), | ||
}, | ||
], | ||
events: ['pointerdown', 'pointerup'], | ||
}); | ||
|
||
const scrollbarY = elementSchema('scrollbarY', { | ||
description: 'The track of the vertical scrollbar.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-state', | ||
value: '`"visible" | "hidden"`', | ||
}, | ||
{ | ||
name: 'data-melt-scroll-area-scrollbar', | ||
value: ATTRS.MELT('scroll area scrollbar'), | ||
}, | ||
], | ||
events: ['pointerdown', 'pointerup', 'pointermove'], | ||
}); | ||
|
||
const thumbY = elementSchema('thumbY', { | ||
description: 'The thumb of the vertical scrollbar.', | ||
dataAttributes: [ | ||
{ | ||
name: 'data-state', | ||
value: '`"visible" | "hidden"`', | ||
}, | ||
{ | ||
name: 'data-melt-scroll-area-thumb', | ||
value: ATTRS.MELT('scroll area thumb'), | ||
}, | ||
], | ||
events: ['pointerdown', 'pointerup'], | ||
}); | ||
|
||
const schemas: BuilderData['schemas'] = [ | ||
builder, | ||
root, | ||
viewport, | ||
content, | ||
scrollbarY, | ||
thumbY, | ||
scrollbarX, | ||
thumbX, | ||
]; | ||
|
||
const features: BuilderData['features'] = [ | ||
'Scrolling behavior is native to the platform', | ||
'Scrollbar is positioned above the content so no layout shifting occurs', | ||
'Keyboard controls are unaffected and follow platform conventions', | ||
]; | ||
|
||
export const scrollAreaData: BuilderData = { | ||
schemas, | ||
features, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export const flavors = [ | ||
'Vanilla', | ||
'Chocolate', | ||
'Strawberry', | ||
'Mint Chocolate Chip', | ||
'Cookies and Cream', | ||
'Rocky Road', | ||
'Pistachio', | ||
'Neapolitan', | ||
'Butter Pecan', | ||
'Salted Caramel', | ||
'Coffee', | ||
'Mango', | ||
'Raspberry Ripple', | ||
'Lemon Sorbet', | ||
'Green Tea', | ||
'Coconut', | ||
'Black Cherry', | ||
'Banana', | ||
'Almond Fudge', | ||
'Cinnamon', | ||
'Blueberry Cheesecake', | ||
'Tiramisu', | ||
'Red Velvet', | ||
'Matcha', | ||
'Peanut Butter Cup', | ||
'Cookie Dough', | ||
'Rum Raisin', | ||
'Birthday Cake', | ||
'Lychee', | ||
'Honey Lavender', | ||
]; |
40 changes: 40 additions & 0 deletions
40
src/docs/previews/scroll-area/always/tailwind/index.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<script lang="ts"> | ||
import { createScrollArea, melt } from '$lib/index.js'; | ||
import { flavors } from './flavors.js'; | ||
const { | ||
elements: { root, content, viewport, corner, scrollbarY, thumbY }, | ||
} = createScrollArea({ | ||
type: 'always', | ||
dir: 'ltr', | ||
}); | ||
</script> | ||
|
||
<div | ||
use:melt={$root} | ||
class="relative h-72 w-56 overflow-hidden rounded-md border border-neutral-700 bg-neutral-800/90 text-white shadow-lg" | ||
> | ||
<div use:melt={$viewport} class="h-full w-full rounded-[inherit]"> | ||
<div use:melt={$content}> | ||
<div class="p-7"> | ||
<h4 class="mb-4 font-semibold leading-none">Endless Flavors</h4> | ||
{#each flavors as flavor (flavor)} | ||
<div class="text-sm"> | ||
{flavor} | ||
</div> | ||
<div role="separator" class="my-2 h-px w-full bg-magnum-800/30" /> | ||
{/each} | ||
</div> | ||
</div> | ||
</div> | ||
<div | ||
use:melt={$scrollbarY} | ||
class="flex h-full w-2.5 touch-none select-none border-l border-l-transparent bg-neutral-300/10 p-px transition-colors" | ||
> | ||
<div | ||
use:melt={$thumbY} | ||
class="relative flex-1 rounded-full bg-neutral-300/50" | ||
/> | ||
</div> | ||
<div use:melt={$corner} /> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export const flavors = [ | ||
'Vanilla', | ||
'Chocolate', | ||
'Strawberry', | ||
'Mint Chocolate Chip', | ||
'Cookies and Cream', | ||
'Rocky Road', | ||
'Pistachio', | ||
'Neapolitan', | ||
'Butter Pecan', | ||
'Salted Caramel', | ||
'Coffee', | ||
'Mango', | ||
'Raspberry Ripple', | ||
'Lemon Sorbet', | ||
'Green Tea', | ||
'Coconut', | ||
'Black Cherry', | ||
'Banana', | ||
'Almond Fudge', | ||
'Cinnamon', | ||
'Blueberry Cheesecake', | ||
'Tiramisu', | ||
'Red Velvet', | ||
'Matcha', | ||
'Peanut Butter Cup', | ||
'Cookie Dough', | ||
'Rum Raisin', | ||
'Birthday Cake', | ||
'Lychee', | ||
'Honey Lavender', | ||
]; |
Oops, something went wrong.