Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
0e196e6
feat: ts types for colors (#3957) (#4270)
Fsss126 Jun 27, 2024
69e3ab2
feat(sticky-scrollbar): init component (#4286)
m0ksem Jun 27, 2024
de9a907
Color css variables must be rendered on app root element, not body (#…
Fsss126 Jun 27, 2024
4aac12a
feat: remove lodash (#4316)
m0ksem Jun 27, 2024
e91f248
feat: remove colortranslator (#4310)
m0ksem Jun 27, 2024
3d770cd
chore(storybook): fix add text method
m0ksem Jun 27, 2024
0d65f7e
fix(data-table): correct start case
m0ksem Jun 27, 2024
df62c4b
fix(utils/merge): create empty object if object is undefined
m0ksem Jun 27, 2024
999ee9e
fix(resize-observer): correctly normalize observed elements
m0ksem Jun 27, 2024
288c611
fix(VaConfig): correctly copy regex values
m0ksem Jun 27, 2024
cf3d2d1
Added ability to apply multiple presets (#4303)
Fsss126 Jun 27, 2024
30e739e
chore(deps): bump ws from 6.2.2 to 6.2.3 (#4328)
dependabot[bot] Jun 27, 2024
b8eb22d
feat: use custom color names in button
m0ksem Jun 27, 2024
e87e580
feat(icon): icon name extendable type (#4045)
m0ksem Jun 27, 2024
fa49653
feat: masks (#4332)
m0ksem Jul 1, 2024
eaee0ee
docs(sticky-scrollbar): add example with data table
m0ksem Jul 3, 2024
a6a80f0
feat(sticky-headers): init sticky table headers composable
m0ksem Jul 3, 2024
6541335
fix: remove empty changelogs
m0ksem Jul 3, 2024
3d483b6
docs: add changelogs
m0ksem Jul 3, 2024
24b642c
docs: add more changelogs for services
m0ksem Jul 3, 2024
8a2c4bb
fix: improve docs SSR
m0ksem Jul 4, 2024
513af47
fix: render css colors on body root
m0ksem Jul 4, 2024
666dfc6
fix: correctly split numbers in color names
m0ksem Jul 8, 2024
d471eb6
chore: remove cleave (#4334)
m0ksem Jul 8, 2024
c53bce9
Feat/devtools and compiler (#4340)
m0ksem Jul 8, 2024
6d752d9
feat(devtools): improve dx and component tree parsing and docs (#4345)
m0ksem Jul 15, 2024
440da3e
fix(input/stories): correctly handle input query selector
m0ksem Jul 16, 2024
217bbf2
fix(compiler): fix build
m0ksem Jul 16, 2024
900cbfc
chore(compiler): release beta3
m0ksem Jul 16, 2024
fc5a0f1
docs(compiler/css-layers): added css layers docs page
m0ksem Jul 16, 2024
61c1ba5
feat(compiler): add config support
m0ksem Jul 17, 2024
a90bfcb
docs: added compiler/vuestic-config docs
m0ksem Jul 17, 2024
2f170b1
fix(compiler): resolve virtual vuestic-config
m0ksem Jul 17, 2024
28629bf
chore: bump @vuestic/compiler
m0ksem Jul 17, 2024
5541a16
fix(devtools): correct file path for windows
m0ksem Jul 23, 2024
c6c47ed
chore: update yarn.lock
m0ksem Jul 23, 2024
ddb052c
bump(compiler): 0.0.1-beta5
m0ksem Jul 23, 2024
91127bc
fix(masks): correctly handle months (feb) (#4347)
m0ksem Jul 29, 2024
573a927
fix(VaColorInput): added full length color input (#4348)
ahmadJT Aug 6, 2024
9a0f6fc
fix(input): correct placeholder color for textarea
m0ksem Aug 6, 2024
0660438
docs: correct components config code examples
m0ksem Aug 6, 2024
c6b0b3c
chore: improve select breaking layout
m0ksem Aug 6, 2024
8d7bf76
fix(badge): center content by default
m0ksem Aug 6, 2024
f390a98
chore: indicate compatibility with new v4 major (#4323)
danielroe Aug 19, 2024
653cecd
fix: augment `vue` rather than `@vue/runtime-core` (#4354)
danielroe Aug 19, 2024
48a4e6b
chore: improve select option render time (#4355)
padinko Aug 19, 2024
6882d6d
chore(deps): bump @nuxt/devtools from 1.1.5 to 1.3.9 (#4350)
dependabot[bot] Aug 19, 2024
f0f84d1
fix(nuxt): store config in runtime config for plugin instead of JSON
m0ksem Aug 19, 2024
086787a
chore(nuxt): bump 1.0.21
m0ksem Aug 19, 2024
eb93b68
Add Support & Consulting page to docs (#4359)
raichev-dima Aug 21, 2024
5241e0f
Update the "Support & Consulting" page links (#4360)
raichev-dima Aug 22, 2024
d23e8a9
Update readme with "Support & Consulting" page info (#4362)
raichev-dima Aug 22, 2024
0a30532
minor
asvae Aug 23, 2024
9d2b125
chore: rename inconsistent mask names
m0ksem Aug 25, 2024
b7983ed
chore(docs): reorder sidebar items
m0ksem Aug 25, 2024
ab414f9
feat(sticky-scroll): add offset prop
m0ksem Aug 25, 2024
8794018
chore(deps): bump nuxt from 3.11.1 to 3.12.4 (#4349)
dependabot[bot] Aug 26, 2024
c1eb7f8
feat(devtools): init layout editor (#4363)
m0ksem Aug 26, 2024
682fc16
chore(compiler): disabled devtools by default and turn on config
m0ksem Aug 26, 2024
cee8f9d
chore: use docker compose instead of deprecated docker-compose
m0ksem Aug 26, 2024
61f9657
chore: bump version to v1.10.0
m0ksem Aug 26, 2024
3d07e7c
chore: add Netlify link to README.md (#4365)
raichev-dima Aug 28, 2024
435c85e
chore(compiler): bump 0.1.0
m0ksem Aug 26, 2024
3f35953
Basic set up for Netlify (#4368)
raichev-dima Aug 29, 2024
a003dfc
chore: set up Netlify config for the monorepo (#4369)
raichev-dima Sep 2, 2024
56efd30
fix: enable the build information under Netlify environment
raichev-dima Sep 5, 2024
66709a0
fix(tree-view): react on expanded prop for nested children
m0ksem Sep 10, 2024
b11491d
fix(#4346): throw warn and error if observable target is not element
m0ksem Sep 11, 2024
15c6691
feat(toast#4373): add bottom-center and top-center positions
m0ksem Sep 11, 2024
3f1a17a
Fix#4374/allow-more-types-for-select-clear-value (#4375)
m0ksem Sep 11, 2024
ff822e7
feat(input): add native autocomplete attribute support (#4370)
padinko Sep 13, 2024
4f00151
chore: bump version to v1.10.1
m0ksem Sep 13, 2024
280534b
fix(useForm): remove extra computed from formData
m0ksem Sep 23, 2024
5b53670
feat(VaToast #4373): add bottom-center, top-center position options (…
tom00502 Sep 23, 2024
cdf8654
fix: create-vuestic crossplatform paths (#4379)
shpingalet007 Sep 23, 2024
db2644d
chore: bump version to v1.10.2
m0ksem Sep 24, 2024
2cd0c39
fix(#4394): correct button dropdown teleport when split is used (#4395)
m0ksem Oct 15, 2024
1773f27
fix(VaFormField): fix not working errorCount prop (#4387)
padinko Oct 15, 2024
39fe880
fix: do not apply extra styles when non-headless (#4393)
m0ksem Oct 15, 2024
e9084f6
chore(deps-dev): bump webpack from 5.91.0 to 5.94.0 (#4367)
dependabot[bot] Oct 15, 2024
6aecd46
fix: useMask makes input dirty and add decimal char option (#4399)
m0ksem Oct 15, 2024
712a7b1
Introducing Vuestic UI Guru on Gurubase.io (#4400)
kursataktas Oct 17, 2024
6a02309
feat(#4396): add custom search function for select search (#4401)
m0ksem Oct 17, 2024
7c9d87a
chore(deps): bump express from 4.19.2 to 4.21.0 (#4378)
dependabot[bot] Oct 17, 2024
e7c27b9
chore(deps-dev): bump vite from 4.5.3 to 4.5.5 (#4380)
dependabot[bot] Oct 17, 2024
51fa22d
chore(deps-dev): bump vite from 5.3.3 to 5.3.6 in /packages/compiler/…
dependabot[bot] Oct 17, 2024
2f1b373
chore(deps): bump rollup from 4.18.0 to 4.22.4 in /packages/compiler/…
dependabot[bot] Oct 17, 2024
0170cf2
chore(deps-dev): bump rollup from 3.29.4 to 3.29.5
dependabot[bot] Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(sticky-scrollbar): init component (#4286)
* feat(sticky-scrollbar): init component

* fix: expect scroll content to change

* fix: remove extra console logs

* fix: improve perf
  • Loading branch information
m0ksem committed Jul 23, 2024
commit 69e3ab289d7a2372a523be57c5b14b5b403f1239
7 changes: 7 additions & 0 deletions packages/docs/page-config/navigationRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,13 @@ export const navigationRoutes: NavigationRoute[] = [
badge : navigationBadge.new('1.6.0 '),
}
},
{
name: 'sticky-scrollbar',
displayName: 'Sticky Scrollbar',
meta: {
badge : navigationBadge.new('1.9.10'),
}
},
{
name: "hover",
displayName: "Hover",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<template>
<div class="h-[110vh] w-full overflow-auto">
<VaStickyScrollbar />

<div class="h-full w-screen bg-gradient-to-l from-slate-300 to-slate-700" />
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default definePageConfig({
blocks: [
block.title("StickyScrollbar"),
block.paragraph("This component adds floating scrollbar to element if it doesn't fit the screen. In case if you have large scroll container and want your scrollbar to be always visible, you need to use this component."),

block.example('Horizontal')
],
});
3 changes: 2 additions & 1 deletion packages/nuxt/src/config/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,6 @@ export default [
'VaMenuList',
'VaMenuItem',
'VaMenuGroup',
'VaFormField'
'VaFormField',
'VaStickyScrollbar'
]
1 change: 1 addition & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@ export * from './va-file-upload'
export * from './va-textarea'
export * from './va-menu'
export * from './va-form-field'
export * from './va-sticky-scrollbar'
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { defineComponent } from 'vue'
import { defineStory } from '../../../.storybook/types'
import VaStickyScrollbar from './StickyScrollbar.vue'

export default {
title: 'VaStickyScrollbar',
component: VaStickyScrollbar,
}

export const Horizontal = defineStory({
story: () => ({
components: { VaStickyScrollbar },

template: `
<div style="width: 200px; height: 200vh; overflow: auto; position: relative;">
<div style="width: 300px; height: 300vh; background: linear-gradient(45deg, #fff, #000);" />
<VaStickyScrollbar direction="horizontal" />
</div>
`,
}),
})

export const Vertical = defineStory({
story: () => ({
components: { VaStickyScrollbar },

template: `
<div style="width: 200vh; height: 200px; overflow: auto; position: relative;">
<div style="width: 300vh; height: 300px; background: linear-gradient(45deg, #fff, #000);" />
<VaStickyScrollbar direction="vertical" />
</div>
`,
}),
})

/** Scrollbar reacts to content changes */
export const DynamicContent = defineStory({
story: () => ({
data () {
return {
showBlock2: false,
}
},

mounted () {
setInterval(() => {
this.showBlock2 = !this.showBlock2
}, 2000)
},

components: { VaStickyScrollbar },

template: `
<div style="width: 200vh; height: 200px; overflow: auto; position: relative;">
<div v-if="showBlock2" style="width: 500vh; height: 300px; background: linear-gradient(45deg, #f0f, #0f0);" />
<div v-else style="width: 300vh; height: 300px; background: linear-gradient(45deg, #fff, #000);" />
<VaStickyScrollbar direction="vertical" />
</div>
`,
}),
})
122 changes: 122 additions & 0 deletions packages/ui/src/components/va-sticky-scrollbar/StickyScrollbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { getScrollbarSize } from '../../utils/scrollbar-size'
import { useEvent, useElementRect, useResizeObserver } from '../../composables'

const props = withDefaults(defineProps<{
el?: HTMLElement | null
direction: 'vertical' | 'horizontal'
}>(), {
direction: 'horizontal',
})
const currentEl = ref(null as HTMLElement | null)

const parentElement = computed(() => {
if (props.el) { return props.el }

return currentEl.value?.parentNode as HTMLElement ?? null
})

const parentRect = useElementRect(parentElement)

const stickyScrollWrapperStyle = computed(() => {
const el = parentElement.value

if (!el) { return {} }

const parentEl = el as HTMLElement

const scrollSize = getScrollbarSize(parentEl)

const { bottom, left, right, top } = parentRect.value

if (props.direction === 'vertical') {
if (left > window.innerWidth) { return { display: 'none' } }
if (right < window.innerWidth) { return { display: 'none' } }

return {
position: 'fixed' as const,
top: `${top}px`,
right: 0,
height: `${parentEl.clientHeight}px`,
overflowY: 'auto' as const,
overflowX: 'hidden' as const,
}
}

if (top > window.innerHeight) { return { display: 'none' } }
if (bottom < window.innerHeight) { return { display: 'none' } }

return {
position: 'fixed' as const,
top: `${Math.min(bottom, window.innerHeight) - scrollSize}px`,
width: `${parentEl.clientWidth}px`,
overflowX: 'auto' as const,
overflowY: 'hidden' as const,
}
})

useEvent('scroll', (e) => {
if (!currentEl.value) { return }

if (props.direction === 'horizontal') {
parentElement.value?.scrollTo({
left: currentEl.value.scrollLeft,
})
} else {
parentElement.value?.scrollTo({
top: currentEl.value.scrollTop,
})
}
}, currentEl)

useEvent('scroll', (e) => {
if (!currentEl.value) { return }

if (props.direction === 'horizontal') {
if (parentElement.value?.scrollLeft === currentEl.value.scrollLeft) { return }

currentEl.value.scrollTo({
left: parentElement.value?.scrollLeft,
})
} else {
if (parentElement.value?.scrollTop === currentEl.value.scrollTop) { return }

currentEl.value.scrollTo({
top: parentElement.value?.scrollTop,
})
}
}, parentElement)

const scrollWidth = ref(0)
const scrollHeight = ref(0)

useResizeObserver(computed(() => {
if (!parentElement.value) { return [] }

return [...parentElement.value.children] as HTMLElement[]
}), () => {
scrollWidth.value = parentElement.value.scrollWidth
scrollHeight.value = parentElement.value.scrollHeight
})

const fakeContentStyle = computed(() => {
if (props.direction === 'vertical') {
return {
width: '1px',
height: `${scrollHeight.value}px`,
}
}

return {
height: '1px',
width: `${scrollWidth.value}px`,
}
})
</script>

<template>
<div :style="stickyScrollWrapperStyle" ref="currentEl">
<div :style="fakeContentStyle"></div>
</div>
</template>
1 change: 1 addition & 0 deletions packages/ui/src/components/va-sticky-scrollbar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as VaStickyScrollbar } from './StickyScrollbar.vue'
1 change: 1 addition & 0 deletions packages/ui/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,4 @@ export * from './useElementTextColor'
export * from './useElementBackground'
export * from './useImmediateFocus'
export * from './useNumericProp'
export * from './useElementRect'
41 changes: 41 additions & 0 deletions packages/ui/src/composables/useElementRect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Ref, onBeforeUnmount, onMounted, ref } from 'vue'

export const useElementRect = (element: Ref<HTMLElement | null>) => {
const rect = ref({ top: 0, left: 0, width: 0, height: 0, bottom: 0, right: 0 }) satisfies Ref<{
top: number
left: number
width: number
height: number
bottom: number
right: number
}>

let resizeObserver: ResizeObserver | undefined
let mutationObserver: MutationObserver | undefined

const updateRect = () => {
if (element.value) {
rect.value = element.value.getBoundingClientRect()
}
}

onMounted(() => {
resizeObserver = new ResizeObserver(updateRect)
mutationObserver = new MutationObserver(updateRect)

element.value && resizeObserver.observe(element.value)
element.value && mutationObserver.observe(element.value, { attributes: true, childList: true, subtree: true })

updateRect()
})

onBeforeUnmount(() => {
resizeObserver?.disconnect()
mutationObserver?.disconnect()

resizeObserver = undefined
mutationObserver = undefined
})

return rect
}
15 changes: 12 additions & 3 deletions packages/ui/src/composables/useResizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ import { onBeforeUnmount, onMounted, ref, Ref, unref, watch } from 'vue'
type MaybeRef<T> = T | Ref<T>
type MaybeArray<T> = T | T[]

export const useResizeObserver = <T extends HTMLElement | undefined>(elementsList: MaybeRef<T>[] | Ref<T>, cb: ResizeObserverCallback) => {
const normalizeElements = <T>(elements: MaybeRef<T>[] | Ref<MaybeArray<T>>) => {
return Array.isArray(elements)
? elements
: Array.isArray(elements.value)
? elements.value
: [elements.value]
}

export const useResizeObserver = <T extends HTMLElement | undefined>(elementsList: MaybeRef<T>[] | Ref<MaybeArray<T>>, cb: ResizeObserverCallback) => {
let resizeObserver: ResizeObserver | undefined

const observeAll = (elementsList: MaybeRef<T>[]) => {
Expand All @@ -16,12 +24,13 @@ export const useResizeObserver = <T extends HTMLElement | undefined>(elementsLis

watch(elementsList, (newValue) => {
resizeObserver?.disconnect()
observeAll(Array.isArray(newValue) ? newValue : [newValue])

observeAll(normalizeElements(newValue))
})

onMounted(() => {
resizeObserver = new ResizeObserver(cb)
observeAll(Array.isArray(elementsList) ? elementsList : [elementsList])
observeAll(normalizeElements(elementsList))
})

onBeforeUnmount(() => resizeObserver?.disconnect())
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/services/vue-plugin/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ export {
VaMenuItem,
VaMenuGroup,
VaFormField,
VaStickyScrollbar,
} from '../../components'
7 changes: 7 additions & 0 deletions packages/ui/src/utils/scrollbar-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const getScrollbarSize = (element: HTMLElement | null | undefined) => {
if (!element) { return 0 }

const scrollbarWidth = element.offsetWidth - element.clientWidth
const scrollbarHeight = element.offsetHeight - element.clientHeight
return Math.max(scrollbarWidth, scrollbarHeight)
}