-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add supporting code for Kolibri loaders #448
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<template> | ||
|
||
<DocsPageTemplate apiDocs> | ||
<DocsPageSection title="Overview" anchor="#overview"> | ||
<p>Exposes predefined set of transitions built on top of Vue's <code><transition></code>.</p> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Usage" anchor="#usage"> | ||
<ul> | ||
<li>Don't forget to define <code>key</code> on child elements of <code>KTransition</code> as described <DocsExternalLink text="in Vue documentation" href="https://v2.vuejs.org/v2/guide/transitions#Transitioning-Between-Elements" />.</li> | ||
</ul> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Available transitions" anchor="#overview"> | ||
<section> | ||
<h3><code>component-fade-out-in</code></h3> | ||
<p>Suitable when switching between two elements/components.</p> | ||
|
||
<DocsShowCode language="html"> | ||
<KTransition kind="component-fade-out-in"> | ||
<div v-if="isTruthy" key="key-1"> | ||
First component | ||
</div> | ||
<div v-else key="key-2"> | ||
Second component | ||
</div> | ||
</KTransition> | ||
</DocsShowCode> | ||
|
||
<p>Output:</p> | ||
<DocsShow block language="html"> | ||
<KTransition kind="component-fade-out-in"> | ||
<div v-if="isTruthy" key="key-1"> | ||
First component | ||
</div> | ||
<div v-else key="key-2"> | ||
Second component | ||
</div> | ||
</KTransition> | ||
</DocsShow> | ||
</section> | ||
|
||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Related" anchor="#related"> | ||
<ul> | ||
<li> | ||
<DocsExternalLink text="Vue's transitions documentation" href="https://v2.vuejs.org/v2/guide/transitions" /> | ||
</li> | ||
</ul> | ||
</DocsPageSection> | ||
</DocsPageTemplate> | ||
|
||
</template> | ||
|
||
|
||
<script> | ||
|
||
export default { | ||
data() { | ||
return { | ||
isTruthy: true, | ||
intervalId: null, | ||
}; | ||
}, | ||
mounted() { | ||
this.intervalId = setInterval(() => { | ||
this.isTruthy = !this.isTruthy; | ||
}, 2000); | ||
}, | ||
beforeDestroy() { | ||
clearInterval(this.intervalId); | ||
}, | ||
}; | ||
|
||
</script> | ||
|
||
|
||
<style lang="scss" scoped></style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
<template> | ||
|
||
<DocsPageTemplate apiDocs> | ||
|
||
<DocsPageSection title="Overview" anchor="#overview"> | ||
<p>A composable that offers the <code>show</code> reactive function. This function guarantees that something will be displayed at least for a specified duration after an initial trigger. This is typically used to prevent a jarring user experience when showing or hiding certain elements. For example, it can be used to ensure that a loader remains visible for a certain amount of time, even when the related data has already been loaded.</p> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Usage" anchor="#usage"> | ||
<code>show(key, shouldShow, minVisibleTime)</code> | ||
|
||
<DocsShowCode language="html"> | ||
<div v-if="show('key-1', isLoading, minVisibleTime)"> | ||
Loading... | ||
</div> | ||
<div v-else> | ||
Loaded! | ||
</div> | ||
</DocsShowCode> | ||
<!-- eslint-disable --> | ||
<!-- prevent prettier from changing indentation --> | ||
<DocsShowCode language="javascript"> | ||
import useKShow from 'kolibri-design-system/lib/composables/useKShow'; | ||
|
||
export default { | ||
setup() { | ||
const { show } = useKShow(); | ||
return { show }; | ||
} | ||
}; | ||
</DocsShowCode> | ||
<!-- eslint-enable --> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Example" anchor="#example"> | ||
<p>This is a simulation of a typical use-case of showing a loader while fetching data. You can set your own fetch request length and minimum visible time, and then hit the fetch button to see the output.</p> | ||
|
||
<DocsShowCode language="html"> | ||
<KTransition kind="component-fade-out-in"> | ||
<KCircularLoader | ||
v-if="show('key-1', isFetching, minVisibleTime )" | ||
/> | ||
<div v-else> | ||
Loaded! | ||
</div> | ||
</KTransition> | ||
</DocsShowCode> | ||
|
||
<div :style="{ marginTop: '24px', display: 'flex' }"> | ||
<div> | ||
<span :style="{ marginLeft: '8px' }">Output:</span> | ||
<DocsShow> | ||
<div :style="{ width: '200px', height: '160px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '12px 2px 4px 2px' }"> | ||
<div> | ||
<KTransition kind="component-fade-out-in"> | ||
<KCircularLoader | ||
v-if="show('key-1', isFetching, minVisibleTime )" | ||
key="loader" | ||
disableDefaultTransition | ||
/> | ||
<div v-else key="message" :style="{ textAlign: 'center' }"> | ||
Loaded! | ||
</div> | ||
</KTransition> | ||
</div> | ||
<div> | ||
<code>isFetching: {{ isFetching }}</code> | ||
<code>minVisibleTime: {{ minVisibleTime }}</code> | ||
</div> | ||
</div> | ||
</DocsShow> | ||
</div> | ||
<div :style="{ marginTop: '28px', marginLeft: '24px' }"> | ||
<span> | ||
<label :style="{ display: 'block' }">Fetch request length (ms)</label> | ||
<input | ||
v-model="fetchingTimeInput" | ||
type="number" | ||
:style="{ display: 'block' }" | ||
> | ||
</span> | ||
<span> | ||
<label :style="{ display: 'block', marginTop: '12px' }"> | ||
Minimum visible time (ms) | ||
</label> | ||
<input | ||
v-model="minVisibleTimeInput" | ||
type="number" | ||
:style="{ display: 'block' }" | ||
> | ||
</span> | ||
<KButton :style="{ marginTop: '24px' }" @click="fetchData"> | ||
Fetch data | ||
</KButton> | ||
</div> | ||
</div> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Related" anchor="#related"> | ||
<ul> | ||
<li> | ||
Some components offer a simpler interfance to achieve the same effect when there is no need to be switching between more components. For example, see <DocsInternalLink href="/kcircularloader#prop:minVisibleTime"> | ||
KCircularLoader's <code>minVisibleTime</code> | ||
</DocsInternalLink>. | ||
</li> | ||
</ul> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Parameters" anchor="#parameters"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Parameters" and "Returns" would ideally get automatically generated from JSDoc comments of the composable function, similarly how "Props" are generated from components. I believe this would be helpful for the other two composables we have in KDS already. Will open an issue for this as soon as review of this PR is done. |
||
<PropsTable :api="params" /> | ||
</DocsPageSection> | ||
|
||
<DocsPageSection title="Returns" anchor="#returns"> | ||
<p><span style="font-weight: bold">Type:</span> <code>boolean</code></p> | ||
<p><span style="font-weight: bold">Description:</span> Returns <code>true</code> after <code>shouldShow</code> becomes truthy and keeps returning <code>true</code> for the duration of <code>minVisibleTime</code> (even when <code>shouldShow</code> changes back to falsy meanwhile). After <code>minVisibleTime</code> elapses and when <code>shouldShow</code> is falsy already, it returns <code>false</code>.</p> | ||
</DocsPageSection> | ||
</DocsPageTemplate> | ||
|
||
</template> | ||
|
||
|
||
<script> | ||
|
||
import { ref } from '@vue/composition-api'; | ||
import useKShow from '../../lib/composables/useKShow'; | ||
import PropsTable from '../common/DocsPageTemplate/jsdocs/PropsTable'; | ||
|
||
export default { | ||
components: { | ||
PropsTable, | ||
}, | ||
setup() { | ||
const { show } = useKShow(); | ||
|
||
let timeoutId; | ||
const isFetching = ref(false); | ||
|
||
const minVisibleTime = ref(5000); | ||
const minVisibleTimeInput = ref(5000); | ||
|
||
const fetchingTime = ref(1000); | ||
const fetchingTimeInput = ref(1000); | ||
|
||
function fetchData() { | ||
clearTimeout(timeoutId); | ||
|
||
fetchingTime.value = fetchingTimeInput.value; | ||
minVisibleTime.value = minVisibleTimeInput.value; | ||
isFetching.value = true; | ||
|
||
timeoutId = setTimeout(function() { | ||
isFetching.value = false; | ||
}, fetchingTime.value); | ||
} | ||
|
||
return { | ||
show, | ||
isFetching, | ||
fetchingTime, | ||
minVisibleTime, | ||
fetchingTimeInput, | ||
minVisibleTimeInput, | ||
fetchData, | ||
}; | ||
}, | ||
data() { | ||
return { | ||
params: [ | ||
{ | ||
name: 'key', | ||
required: true, | ||
type: { name: 'number|string' }, | ||
description: | ||
'Each `show` function instance has to pass a key unique in the context of a whole page to this attribute', | ||
}, | ||
{ | ||
name: 'shouldShow', | ||
required: false, | ||
default: false, | ||
type: { name: 'boolean' }, | ||
description: | ||
'Accurate, real-time information on whether something should be shown. For example, it should be set to `false` for a loader immediately after related data have finished loading.', | ||
}, | ||
{ | ||
name: 'minVisibleTime', | ||
required: false, | ||
default: 0, | ||
type: { name: 'number' }, | ||
description: 'For how long should `show` return `true` after an initial trigger', | ||
}, | ||
], | ||
}; | ||
}, | ||
}; | ||
|
||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,7 @@ const textRelatedKeywords = ['text', 'area', 'field', 'box']; | |
const layoutRelatedKeywords = ['grid', 'layout', 'container', 'page']; | ||
const responsiveComponentsRelatedKeywords = ['responsive', 'mixin', 'breakpoint']; | ||
const tabsRelatedKeywords = ['tab', 'tabs', 'panel', 'tablist', 'tabpanel']; | ||
const compositionRelatedKeywords = ['composable', 'composition']; | ||
|
||
export default [ | ||
new Section({ | ||
|
@@ -170,6 +171,27 @@ export default [ | |
}), | ||
], | ||
}), | ||
new Section({ | ||
title: 'Composables', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine that we'd ideally move already existing composables (responsiveWindow and responsiveElement) to this section, rather than having them hidden in the components docs, and also move their code files to the same folder. In that way, we would have consistent imports in products. I hope having this section above components will help with discoverability of KDS Composition API utilities (see learningequality/kolibri#11132 (comment)) cc @akolson Can open follow-up. |
||
autoSort: true, | ||
pages: [ | ||
new Page({ | ||
path: '/usekshow', | ||
title: 'useKShow', | ||
isCode: true, | ||
keywords: [ | ||
...compositionRelatedKeywords, | ||
'if', | ||
'show', | ||
'time', | ||
'minimum', | ||
'visible', | ||
'loader', | ||
'loading', | ||
], | ||
}), | ||
], | ||
}), | ||
new Section({ | ||
title: 'Code library components', | ||
autoSort: true, | ||
|
@@ -359,6 +381,12 @@ export default [ | |
isCode: true, | ||
keywords: tabsRelatedKeywords, | ||
}), | ||
new Page({ | ||
path: '/ktransition', | ||
title: 'KTransition', | ||
isCode: true, | ||
keywords: ['transition'], | ||
}), | ||
], | ||
}), | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example is excellent <3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, playing around this was fun, glad that it feels useful