-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(scroll-area): ts to sfc (#543)
* refactor(scroll-area): ts to sfc * fix: lint issues * revert: pnpm lock * fix(story): scroll-area fix props * fix(scroll-area): use useResizeObserver from '@vueuse/core' * feat(use-composable): add useResizeObserver * fix: lint issues
- Loading branch information
1 parent
8be294a
commit 08b2011
Showing
62 changed files
with
1,914 additions
and
2,376 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
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 |
---|---|---|
|
@@ -4,5 +4,6 @@ export { | |
} from './Direction.vue' | ||
|
||
export { | ||
type Direction, | ||
useDirection, | ||
} from './utils' |
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 |
---|---|---|
@@ -1,10 +1,10 @@ | ||
import { computed, inject, unref } from 'vue' | ||
import type { InjectionKey, MaybeRef, Ref } from 'vue' | ||
import { computed, inject, toValue } from 'vue' | ||
import type { InjectionKey, MaybeRefOrGetter, Ref } from 'vue' | ||
|
||
export type Direction = 'ltr' | 'rtl' | ||
export const DirectionContextSymbol = Symbol('OkuDirectionProvider') as InjectionKey<Ref<Direction>> | ||
|
||
export function useDirection(localDir?: MaybeRef<Direction | undefined>) { | ||
export function useDirection(localDir?: MaybeRefOrGetter<Direction | undefined>) { | ||
const globalDir = inject(DirectionContextSymbol, null) | ||
return computed(() => unref(localDir) ?? globalDir?.value ?? 'ltr') | ||
return computed(() => toValue(localDir) ?? globalDir?.value ?? 'ltr') | ||
} |
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,51 @@ | ||
import type { PrimitiveProps } from '@oku-ui/primitive' | ||
import type { Ref } from 'vue' | ||
import type { Direction } from '@oku-ui/direction' | ||
import { createScope } from '@oku-ui/provide' | ||
import { SCROLL_AREA_NAME } from './constants' | ||
import type { ScrollAreaElement, ScrollAreaScopeProps, ScrollAreaScrollbarElement, ScrollAreaViewportElement } from './types' | ||
|
||
// Props | ||
|
||
export interface ScrollAreaProps extends PrimitiveProps, ScrollAreaScopeProps { | ||
/** | ||
* Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars. | ||
* | ||
* `auto` - means that scrollbars are visible when content is overflowing on the corresponding orientation. <br> | ||
* `always` - means that scrollbars are always visible regardless of whether the content is overflowing.<br> | ||
* `scroll` - means that scrollbars are visible when the user is scrolling along its corresponding orientation.<br> | ||
* `hover` - when the user is scrolling along its corresponding orientation and when the user is hovering over the scroll area. | ||
*/ | ||
type?: 'auto' | 'always' | 'scroll' | 'hover' | ||
/** The reading direction of the combobox when applicable. <br> If omitted, inherits globally from `DirectionProvider` or assumes LTR (left-to-right) reading mode. */ | ||
dir?: Direction | ||
/** If type is set to either `scroll` or `hover`, this prop determines the length of time, in milliseconds, <br> before the scrollbars are hidden after the user stops interacting with scrollbars. */ | ||
scrollHideDelay?: number | ||
} | ||
|
||
// Context | ||
|
||
export interface ScrollAreaContext { | ||
type: Ref<NonNullable<ScrollAreaProps['type']>> | ||
dir: Ref<NonNullable<ScrollAreaProps['dir']>> | ||
scrollHideDelay: Ref<number> | ||
scrollArea: Ref<ScrollAreaElement | undefined> | ||
viewport: Ref<ScrollAreaViewportElement | undefined> | ||
onViewportChange: (viewport: ScrollAreaViewportElement | undefined) => void | ||
content: Ref<HTMLElement | undefined> | ||
onContentChange: (content: HTMLDivElement) => void | ||
scrollbarX: Ref<ScrollAreaScrollbarElement | undefined> | ||
onScrollbarXChange: (scrollbar: ScrollAreaScrollbarElement | undefined) => void | ||
scrollbarXEnabled: Ref<boolean> | ||
onScrollbarXEnabledChange: (rendered: boolean) => void | ||
scrollbarY: Ref<ScrollAreaScrollbarElement | undefined> | ||
onScrollbarYChange: (scrollbar: ScrollAreaScrollbarElement | undefined) => void | ||
scrollbarYEnabled: Ref<boolean> | ||
onScrollbarYEnabledChange: (rendered: boolean) => void | ||
onCornerWidthChange: (width: number) => void | ||
onCornerHeightChange: (height: number) => void | ||
} | ||
|
||
export const [createScrollAreaContext, createScrollAreaScope] = createScope(SCROLL_AREA_NAME) | ||
|
||
export const [provideScrollAreaContext, useScrollAreaContext] = createScrollAreaContext<ScrollAreaContext>(SCROLL_AREA_NAME) |
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,88 @@ | ||
<script setup lang="ts"> | ||
import { shallowRef, toRef } from 'vue' | ||
import type { ScrollAreaProps } from './ScrollArea' | ||
import type { ScrollAreaElement, ScrollAreaScrollbarElement, ScrollAreaViewportElement } from './types' | ||
import { useDirection } from '@oku-ui/direction' | ||
import { provideScrollAreaContext } from './ScrollArea' | ||
import { usePrimitiveElement } from '@oku-ui/use-composable' | ||
import { SCROLL_AREA_NAME } from './constants' | ||
import { Primitive } from '@oku-ui/primitive' | ||
defineOptions({ | ||
name: SCROLL_AREA_NAME, | ||
}) | ||
const props = withDefaults(defineProps<ScrollAreaProps>(), { | ||
type: 'hover', | ||
scrollHideDelay: 600, | ||
}) | ||
const [scrollArea, setScrollArea] = usePrimitiveElement<ScrollAreaElement>() | ||
const viewport = shallowRef<ScrollAreaViewportElement>() | ||
const content = shallowRef<HTMLElement>() | ||
const scrollbarX = shallowRef<ScrollAreaScrollbarElement>() | ||
const scrollbarY = shallowRef<ScrollAreaScrollbarElement>() | ||
const cornerWidth = shallowRef(0) | ||
const cornerHeight = shallowRef(0) | ||
const scrollbarXEnabled = shallowRef(false) | ||
const scrollbarYEnabled = shallowRef(false) | ||
const direction = useDirection(() => props.dir) | ||
provideScrollAreaContext({ | ||
scope: props.scopeOkuScrollArea, | ||
type: toRef(props, 'type'), | ||
dir: direction, | ||
scrollHideDelay: toRef(props, 'scrollHideDelay'), | ||
scrollArea, | ||
viewport, | ||
onViewportChange(payload) { | ||
viewport.value = payload | ||
}, | ||
content, | ||
onContentChange(payload) { | ||
content.value = payload | ||
}, | ||
scrollbarX, | ||
onScrollbarXChange(payload) { | ||
scrollbarX.value = payload | ||
}, | ||
scrollbarXEnabled, | ||
onScrollbarXEnabledChange(payload) { | ||
scrollbarXEnabled.value = payload | ||
}, | ||
scrollbarY, | ||
onScrollbarYChange(payload) { | ||
scrollbarY.value = payload | ||
}, | ||
scrollbarYEnabled, | ||
onScrollbarYEnabledChange(payload) { | ||
scrollbarYEnabled.value = payload | ||
}, | ||
onCornerWidthChange(payload) { | ||
cornerWidth.value = payload | ||
}, | ||
onCornerHeightChange(payload) { | ||
cornerHeight.value = payload | ||
}, | ||
}) | ||
</script> | ||
|
||
<template> | ||
<Primitive | ||
:is="is" | ||
:ref="setScrollArea" | ||
:as-child="asChild" | ||
:dir="direction" | ||
:style="{ | ||
position: 'relative', | ||
// Pass corner sizes as CSS vars to reduce re-renders of context consumers | ||
['--oku-scroll-area-corner-width']: `${cornerWidth}px`, | ||
['--oku-scroll-area-corner-height']: `${cornerHeight}px`, | ||
}" | ||
> | ||
<slot /> | ||
</Primitive> | ||
</template> |
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 @@ | ||
import type { ScrollAreaCornerImplProps } from './ScrollAreaCornerImpl' | ||
|
||
// Props | ||
|
||
export interface ScrollAreaCornerProps extends ScrollAreaCornerImplProps {} |
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,24 @@ | ||
<script setup lang="ts"> | ||
import { computed } from 'vue' | ||
import { useScrollAreaContext } from './ScrollArea' | ||
import { SCROLL_AREA_CORNER_NAME } from './constants' | ||
import type { ScrollAreaCornerImplProps } from './ScrollAreaCornerImpl' | ||
import ScrollAreaCornerImpl from './ScrollAreaCornerImpl.vue' | ||
defineOptions({ | ||
name: SCROLL_AREA_CORNER_NAME, | ||
}) | ||
const props = defineProps<ScrollAreaCornerImplProps>() | ||
const context = useScrollAreaContext(SCROLL_AREA_CORNER_NAME, props.scopeOkuScrollArea) | ||
const hasBothScrollbarsVisible = computed(() => Boolean(context.scrollbarX.value && context.scrollbarY.value)) | ||
const hasCorner = computed(() => context.type.value !== 'scroll' && hasBothScrollbarsVisible.value) | ||
</script> | ||
|
||
<template> | ||
<ScrollAreaCornerImpl v-if="hasCorner"> | ||
<slot /> | ||
</ScrollAreaCornerImpl> | ||
</template> |
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,8 @@ | ||
import type { PrimitiveProps } from '@oku-ui/primitive' | ||
import type { ScrollAreaScopeProps } from './types' | ||
|
||
// Props | ||
|
||
export interface ScrollAreaCornerImplProps extends PrimitiveProps, ScrollAreaScopeProps { | ||
|
||
} |
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,50 @@ | ||
<script setup lang="ts"> | ||
import { computed, ref } from 'vue' | ||
import { useScrollAreaContext } from './ScrollArea' | ||
import { SCROLL_AREA_CORNER_IMPL_NAME, SCROLL_AREA_CORNER_NAME } from './constants' | ||
import type { ScrollAreaCornerImplProps } from './ScrollAreaCornerImpl' | ||
import { Primitive } from '@oku-ui/primitive' | ||
import { useResizeObserver } from '@oku-ui/use-composable' | ||
defineOptions({ | ||
name: SCROLL_AREA_CORNER_IMPL_NAME, | ||
}) | ||
const props = defineProps<ScrollAreaCornerImplProps>() | ||
const context = useScrollAreaContext(SCROLL_AREA_CORNER_NAME, props.scopeOkuScrollArea) | ||
const width = ref(0) | ||
const height = ref(0) | ||
const hasSize = computed(() => Boolean(width.value && height.value)) | ||
useResizeObserver(context.scrollbarX, () => { | ||
const _height = context.scrollbarX.value?.offsetHeight || 0 | ||
context.onCornerHeightChange(_height) | ||
height.value = _height | ||
}) | ||
useResizeObserver(context.scrollbarY, () => { | ||
const _width = context.scrollbarY.value?.offsetWidth || 0 | ||
context.onCornerWidthChange(_width) | ||
width.value = _width | ||
}) | ||
</script> | ||
|
||
<template> | ||
<Primitive | ||
v-if="hasSize" | ||
:style="{ | ||
width: `${width}px`, | ||
height: `${height}px`, | ||
position: 'absolute', | ||
right: context.dir.value === 'ltr' ? 0 : undefined, | ||
left: context.dir.value === 'rtl' ? 0 : undefined, | ||
bottom: 0, | ||
}" | ||
v-bind="$parent?.$props" | ||
> | ||
<slot /> | ||
</Primitive> | ||
</template> |
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,7 @@ | ||
import type { ScrollAreaScrollbarVisibleProps } from './ScrollAreaScrollbarVisible' | ||
|
||
// Props | ||
|
||
export interface ScrollAreaScrollbarProps extends ScrollAreaScrollbarVisibleProps { | ||
forceMount?: true | ||
} |
Oops, something went wrong.