Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
remove implicit ODS registration
Browse files Browse the repository at this point in the history
add vue-composition-api
add feature to render table cells lazy
  • Loading branch information
fschade committed Dec 28, 2021
1 parent b66cf95 commit dd1798c
Show file tree
Hide file tree
Showing 13 changed files with 320 additions and 10 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/change-remove-implicit-registration
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Change: Remove implicit ODS registration

Remove implicit registration of ODS, from now on applications using ODS must register it explicit via `Vue.use`.

https://github.com/owncloud/owncloud-design-system/pull/1848
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-add-composition-api
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: make Vue-Composition-API available

To support upcoming Vue composition-api we`ve added the compatibility layer from the creators.
From now on all features described here `https://github.com/vuejs/composition-api` can be used.

https://github.com/owncloud/owncloud-design-system/pull/1848
14 changes: 14 additions & 0 deletions changelog/unreleased/enhancement-lazy-table-cells
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Enhancement: Add option to render table cells lazy

In cases where the table (`OcTable only`) has multiple child rows with many cells, it can be a bottleneck to rendered all of them immediately.
With this in mind we've added the lazy option to the table fields object where the consuming app can decide how lazy rendering should behave.

By default lazy cell rendering is disabled, to enable it add a lazy object to the field.

following options are available:
* `delay: 250` - when the cell visibility on screen is below given ms value rendering gets skipped.
* `mode: show` - cell gets rendered and stays painted, no de-rendering happens.
* `mode: showHide` - cell gets rendered when it enters the screen and de-rendered when its off.
* `rootMargin: 100px` - given value will be added to the outer area of the element which then increases the visibility detection radius

https://github.com/owncloud/owncloud-design-system/pull/1848
2 changes: 2 additions & 0 deletions docs/docs.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* You can add more things if/when needed.
*/
import Vue from "vue"
import VueCompositionAPI from "@vue/composition-api"
import statusLabels from "./utils/statusLabels"
import activeNav from "./utils/activeNav"
import filterSearch from "./utils/filterSearch"
Expand All @@ -13,6 +14,7 @@ import GetTextPlugin from "vue-gettext"
Vue.config.productionTip = false
Vue.mixin(statusLabels)
Vue.use(GetTextPlugin, { translations: {} })
Vue.use(VueCompositionAPI)

document.addEventListener("DOMContentLoaded", () => {
filterSearch.methods.init()
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@babel/plugin-transform-runtime": "^7.16.5",
"@babel/preset-env": "^7.14.4",
"@popperjs/core": "^2.4.0",
"@vue/composition-api": "^1.4.3",
"@vue/test-utils": "^1.2.0",
"autoprefixer": "^9.7.4",
"babel-core": "^7.0.0-bridge.0",
Expand Down Expand Up @@ -135,6 +136,7 @@
},
"peerDependencies": {
"@popperjs/core": "^2.4.0",
"@vue/composition-api": "^1.4.3",
"filesize": "^8.0.0",
"focus-trap": "^6.4.0",
"focus-trap-vue": "^1.1.1",
Expand Down
74 changes: 73 additions & 1 deletion src/components/atoms/_OcTableCellData/_OcTableCellData.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
<template>
<oc-table-cell
ref="observerTarget"
type="td"
:align-h="alignH"
:align-v="alignV"
:width="width"
:wrap="wrap"
class="oc-td"
>
<slot />
<slot v-if="isVisible" />
<span v-else class="shimmer"></span>
</oc-table-cell>
</template>
<script>
import OcTableCell from "../_OcTableCell/_OcTableCell.vue"
import { customRef, ref } from "@vue/composition-api"
import { useIsVisible } from "../../../composables"
export default {
name: "OcTd",
Expand Down Expand Up @@ -39,6 +43,74 @@ export default {
default: null,
validator: wrap => (wrap ? /(break|nowrap|truncate)/.test(wrap) : true),
},
lazy: {
type: Object,
default: null,
},
},
setup(props) {
const observerTarget = customRef((track, trigger) => {
let $el
return {
get() {
track()
return $el
},
set(value) {
$el = value.$el
trigger()
},
}
})
const { isVisible } = props.lazy
? useIsVisible({
...props.lazy,
target: observerTarget,
})
: { isVisible: ref(true) }
return {
observerTarget,
isVisible,
}
},
}
</script>
<style lang="scss">
.shimmer {
background-color: var(--oc-color-input-text-muted);
bottom: 12px;
display: inline-block;
left: 10px;
opacity: 0.2;
overflow: hidden;
position: absolute;
right: 10px;
top: 12px;
&::after {
animation: shimmer 2s infinite;
background-image: linear-gradient(
90deg,
rgba(#fff, 0) 0,
rgba(#fff, 0.2) 20%,
rgba(#fff, 0.5) 60%,
rgba(#fff, 0)
);
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
transform: translateX(-100%);
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
}
</style>
10 changes: 7 additions & 3 deletions src/components/molecules/OcTable/OcTable.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { shallowMount, mount } from "@vue/test-utils"
const { axe, toHaveNoViolations } = require("jest-axe")

import { shallowMount, mount, createLocalVue } from "@vue/test-utils"
import VueCompositionAPI from "@vue/composition-api"
import { axe, toHaveNoViolations } from "jest-axe"
import Table from "./OcTable.vue"

const localVue = createLocalVue()
localVue.use(VueCompositionAPI)

expect.extend(toHaveNoViolations)

const fields = [
Expand Down Expand Up @@ -50,6 +53,7 @@ const data = [
describe("OcTable", () => {
it("displays all field types", async () => {
const wrapper = mount(Table, {
localVue,
propsData: {
fields,
data,
Expand Down
9 changes: 8 additions & 1 deletion src/components/molecules/OcTable/OcTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ export default {
props["aria-label"] = field.accessibleLabelCallback(item)
}
if (Object.prototype.hasOwnProperty.call(field, "lazy")) {
props.lazy = field.lazy
}
return props
},
extractCellProps(field) {
Expand Down Expand Up @@ -538,7 +542,10 @@ export default {
return [{
name: "resource",
title: "Resource",
alignH: "left"
alignH: "left",
lazy: {
delay: 1500
}
}, {
name: "last_modified",
title: "Last modified",
Expand Down
1 change: 1 addition & 0 deletions src/composables/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useIsVisible"
68 changes: 68 additions & 0 deletions src/composables/useIsVisible/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { onBeforeUnmount, ref, watch } from "@vue/composition-api"

/**
* once ODS has lodash this debounce implementation can be replaced with the one from lodash.
* @param delay
* @param callback
* @returns {(function(...[*]=): void)|*}
*/
const debounce = (delay = 0, callback) => {
let id = null
return (...args) => {
window.clearTimeout(id)
id = window.setTimeout(() => {
callback.apply(null, args)
}, delay)
}
}

/**
*
* @param {Ref<Element>} target - ref with element to be observed
* @param {('show'|'showHide')} mode - showHide shows and hides the element on screen enter or leave, show only detects entering the screen and the keeps it rendered
* @param {string} rootMargin - margin that will be added around the element to detect visibility
* @param {number} delay - defines the debounce delay of the visibility detection
* @returns {{isVisible: Ref<boolean>}}
*/
export const useIsVisible = ({ target, mode = "show", rootMargin = "100px", delay = 0 }) => {
const isSupported = window && "IntersectionObserver" in window
if (!isSupported) {
return {
isVisible: ref(true),
}
}

const isVisible = ref(false)
const observer = new IntersectionObserver(
debounce(delay, ([{ isIntersecting }]) => {
isVisible.value = isIntersecting
/**
* if given mode is `showHide` we need to keep the observation alive.
*/
if (mode === "showHide") {
return
}
/**
* if the mode is `show` which is the default, the implementation needs to unsubscribe the target from the observer
*/
if (!isVisible.value) {
return
}

observer.unobserve(target.value)
}),
{
rootMargin,
}
)

watch(target, () => {
observer.observe(target.value)
})

onBeforeUnmount(() => observer.disconnect())

return {
isVisible,
}
}
Loading

0 comments on commit dd1798c

Please sign in to comment.