Skip to content

Commit

Permalink
refactor(scroll-area): ts to sfc (#543)
Browse files Browse the repository at this point in the history
* 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
teleskop150750 authored Mar 17, 2024
1 parent 8be294a commit 08b2011
Show file tree
Hide file tree
Showing 62 changed files with 1,914 additions and 2,376 deletions.
64 changes: 32 additions & 32 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@
"scripts:genpackage": "esno scripts/generateAliasCode.ts"
},
"devDependencies": {
"@antfu/eslint-config": "^2.8.0",
"@antfu/eslint-config": "^2.6.3",
"@clack/prompts": "^0.7.0",
"@egoist/tailwindcss-icons": "^1.7.4",
"@floating-ui/vue": "^1.0.6",
"@iconify-json/ph": "^1.1.11",
"@egoist/tailwindcss-icons": "^1.7.2",
"@floating-ui/vue": "^1.0.5",
"@iconify-json/ph": "^1.1.10",
"@oku-ui/accordion": "workspace:^",
"@oku-ui/alert-dialog": "workspace:^",
"@oku-ui/arrow": "workspace:^",
Expand Down Expand Up @@ -84,48 +84,48 @@
"@oku-ui/use-composable": "workspace:^",
"@oku-ui/utils": "workspace:^",
"@oku-ui/visually-hidden": "workspace:^",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-interactions": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
"@storybook/blocks": "^7.6.17",
"@storybook/addon-essentials": "^7.6.10",
"@storybook/addon-interactions": "^7.6.10",
"@storybook/addon-links": "^7.6.10",
"@storybook/blocks": "^7.6.10",
"@storybook/testing-library": "^0.2.2",
"@storybook/vue3": "^7.6.17",
"@storybook/vue3-vite": "^7.6.17",
"@types/node": "^20.11.25",
"@vitejs/plugin-vue": "^5.0.4",
"@vitest/coverage-v8": "^1.3.1",
"@storybook/vue3": "^7.6.10",
"@storybook/vue3-vite": "^7.6.10",
"@types/node": "^20.11.7",
"@vitejs/plugin-vue": "^5.0.3",
"@vitest/coverage-v8": "^1.2.1",
"@vue/test-utils": "^2.4.4",
"autoprefixer": "^10.4.18",
"bumpp": "^9.4.0",
"autoprefixer": "^10.4.17",
"bumpp": "^9.3.0",
"changelogen": "^0.5.5",
"chokidar": "^3.6.0",
"chromatic": "^11.0.7",
"eslint": "^8.57.0",
"chokidar": "^3.5.3",
"chromatic": "^10.6.0",
"eslint": "^8.56.0",
"eslint-plugin-storybook": "^0.8.0",
"esno": "^4.7.0",
"globby": "^14.0.1",
"happy-dom": "^13.7.0",
"esno": "^4.0.0",
"globby": "^14.0.0",
"happy-dom": "^13.0.0",
"jiti": "^1.21.0",
"jsdom": "^24.0.0",
"lint-staged": "^15.2.2",
"nx": "^18.0.8",
"lint-staged": "^15.2.0",
"nx": "^18.0.0",
"ofetch": "^1.3.3",
"pathe": "^1.1.2",
"postcss": "^8.4.35",
"postcss": "^8.4.33",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rimraf": "^5.0.5",
"simple-git-hooks": "^2.10.0",
"storybook": "^7.6.17",
"simple-git-hooks": "^2.9.0",
"storybook": "^7.6.10",
"storybook-dark-mode": "^3.0.3",
"tailwindcss": "^3.4.1",
"tsup": "^8.0.2",
"typescript": "^5.4.2",
"tsup": "^8.0.1",
"typescript": "^5.3.3",
"unbuild": "^2.0.0",
"vite": "5.1.5",
"vite-plugin-dts": "^3.7.3",
"vitest": "^1.3.1",
"vitest-axe": "1.0.0-pre.3",
"vite": "5.1.4",
"vite-plugin-dts": "^3.7.0",
"vitest": "^1.1.3",
"vitest-axe": "^1.0.0-pre.3",
"vue": "3.4.21"
},
"pnpm": {
Expand Down
1 change: 1 addition & 0 deletions packages/vue/src/direction/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export {
} from './Direction.vue'

export {
type Direction,
useDirection,
} from './utils'
8 changes: 4 additions & 4 deletions packages/vue/src/direction/utils.ts
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')
}
51 changes: 51 additions & 0 deletions packages/vue/src/scroll-area/ScrollArea.ts
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)
88 changes: 88 additions & 0 deletions packages/vue/src/scroll-area/ScrollArea.vue
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>
5 changes: 5 additions & 0 deletions packages/vue/src/scroll-area/ScrollAreaCorner.ts
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 {}
24 changes: 24 additions & 0 deletions packages/vue/src/scroll-area/ScrollAreaCorner.vue
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>
8 changes: 8 additions & 0 deletions packages/vue/src/scroll-area/ScrollAreaCornerImpl.ts
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 {

}
50 changes: 50 additions & 0 deletions packages/vue/src/scroll-area/ScrollAreaCornerImpl.vue
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>
7 changes: 7 additions & 0 deletions packages/vue/src/scroll-area/ScrollAreaScrollbar.ts
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
}
Loading

0 comments on commit 08b2011

Please sign in to comment.