Skip to content
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

Let's teleport + make 'sidebar' icon flip in RTL languages #722

Merged
merged 12 commits into from
Aug 30, 2024
3 changes: 2 additions & 1 deletion docs/pages/installation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
<li>Installs <code>$themeBrand</code>, <code>$themeTokens</code> <code>$themePalette</code>, and <code>$computedClass</code> helpers on all Vue instances (see <DocsInternalLink href="/colors/#usage" text="Colors" />).</li>
<li>Provides <code>$coreOutline</code>, <code>$inputModality</code>, <code>$mediaType</code>, and <code>$isPrint</code> computed properties as well as <code>$print</code> method to all Vue instances.</li>
<li>Globally registers all KDS Vue components.</li>
<li>Inserts assertive and polite ARIA live regions to your application's document body (see <DocsInternalLink href="/usekliveregion" text="useKLiveRegion" />).</li>
<li>Inserts assertive and polite ARIA live regions <code>#k-live-region</code> to an application's document body (see <DocsInternalLink href="/usekliveregion" text="useKLiveRegion" />).</li>
<li>Inserts the overlay container element <code>#k-overlay</code> to an application's document body (see <DocsLibraryLink component="KOverlay" /> or search for <code>appendToOverlay</code> prop on components).</li>
</ul>
</DocsPageSection>

Expand Down
29 changes: 29 additions & 0 deletions docs/pages/koverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>

<DocsPageTemplate apiDocs>
<DocsPageSection title="Overview" anchor="#overview">
<p>Use <code>KOverlay</code> to move an element from its original place in the DOM to the overlay container element <code>#k-overlay</code> that is inserted to an application's document body automatically <DocsInternalLink href="/installation#install-plugin" text="during the KDS installation process" />. This is often useful for modals, tooltips, dropdowns, or other elements that should appear on top of other content.</p>
</DocsPageSection>

<DocsPageSection title="Usage" anchor="#usage">
<p>First, check whether you need <code>KOverlay</code>. Some KDS components already utilize it internally and you only need to instruct them to activate it, typically via the <code>appendToOverlay</code> prop.</p>

<p>If you need to use <code>KOverlay</code>, simply wrap an element or a component in it:</p>

<DocsShowCode language="html">
<KOverlay>
<YourComponent />
</KOverlay>
</DocsShowCode>
</DocsPageSection>

<DocsPageSection title="Related" anchor="#related">
<ul>
<li>
<DocsInternalLink href="/installation#install-plugin" text="KDS installation step" /> that attaches the overlay container element <code>#k-overlay</code> to an application's document body
</li>
</ul>
</DocsPageSection>
</DocsPageTemplate>

</template>
8 changes: 2 additions & 6 deletions docs/pages/usekliveregion.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<DocsPageSection title="Related" anchor="#related">
<ul>
<li>
<DocsInternalLink href="/installation#install-plugin" text="KDS installation step" /> that attaches live regions to an application's DOM
<DocsInternalLink href="/installation#install-plugin" text="KDS installation step" /> that attaches live regions to an application's document body
</li>
</ul>
</DocsPageSection>
Expand All @@ -93,7 +93,7 @@

export default {
setup() {
const { _mountLiveRegion, sendPoliteMessage, sendAssertiveMessage } = useKLiveRegion();
const { sendPoliteMessage, sendAssertiveMessage } = useKLiveRegion();

const politeMessageInput = ref('Polite hello');
const updatePoliteMessage = message => {
Expand All @@ -106,7 +106,6 @@
};

return {
_mountLiveRegion,
updatePoliteMessage,
politeMessageInput,
updateAssertiveMessage,
Expand All @@ -115,9 +114,6 @@
sendAssertiveMessage,
};
},
mounted() {
this._mountLiveRegion(this.$root.$el);
},
};

</script>
5 changes: 5 additions & 0 deletions docs/tableOfContents.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ export default [
isCode: true,
keywords: tabsRelatedKeywords,
}),
new Page({
path: '/koverlay',
title: 'KOverlay',
isCode: true,
}),
new Page({
path: '/ktransition',
title: 'KTransition',
Expand Down
1 change: 1 addition & 0 deletions lib/KIcon/iconDefinitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ const KolibriIcons = {
email: { icon: require('./precompiled-icons/material-icons/mail_outline/baseline.vue').default },
sidebar: {
icon: require('./precompiled-icons/material-icons/vertical_split/baseline.vue').default,
rtlFlip: true,
},

bookmark: { icon: require('./precompiled-icons/mdi/bookmark.vue').default },
Expand Down
16 changes: 5 additions & 11 deletions lib/KModal.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>

<component :is="wrapper" v-bind="wrapperProps">
<component :is="wrapper">
<!-- Accessibility properties for the overlay -->
<transition name="modal-fade" appear>
<div
Expand Down Expand Up @@ -103,7 +103,6 @@

<script>

import Teleport from 'vue2-teleport';
import debounce from 'lodash/debounce';
import useKResponsiveWindow from './composables/useKResponsiveWindow';

Expand All @@ -120,9 +119,6 @@
*/
export default {
name: 'KModal',
components: {
Teleport,
},
setup() {
const { windowHeight, windowWidth } = useKResponsiveWindow();
return { windowHeight, windowWidth };
Expand Down Expand Up @@ -197,9 +193,10 @@
required: false,
},
/**
* Whether or not the modal should be teleported to the root of the document
* Whether or not the modal should be moved
* to the overlay container element `#k-overlay`
*/
appendToRoot: {
appendToOverlay: {
type: Boolean,
default: false,
},
Expand Down Expand Up @@ -236,10 +233,7 @@
};
},
wrapper() {
return this.appendToRoot ? 'Teleport' : 'div';
},
wrapperProps() {
return this.appendToRoot ? { to: 'body' } : {};
return this.appendToOverlay ? 'KOverlay' : 'div';
},
},
created() {
Expand Down
36 changes: 36 additions & 0 deletions lib/KOverlay/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>

<Teleport :to="overlayElSelector">
<!-- @slot Content to be moved to the overlay container element `#k-overlay` -->
<slot></slot>
</Teleport>

</template>


<script>

import Teleport from 'vue2-teleport';
import _useOverlay from '../composables/_useOverlay';

/**
* Moves an element from its original place in the DOM
* to the overlay container element #k-overlay that is inserted
* to an application's document body automatically during
* the KDS installation process (see KThemePlugin.js).
* This is often useful for modals, tooltips, dropdowns, or other
* elements that should appear on top of other content.
*/
export default {
name: 'KOverlay',
components: {
Teleport,
},
setup() {
const { overlayElSelector } = _useOverlay();
return { overlayElSelector };
},
};

</script>

9 changes: 5 additions & 4 deletions lib/KThemePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import KSwitch from './KSwitch';
import KTabs from './tabs/KTabs';
import KTabsList from './tabs/KTabsList';
import KTabsPanel from './tabs/KTabsPanel';
import KOverlay from './KOverlay';
import KTextbox from './KTextbox';
import KTooltip from './KTooltip';
import KTransition from './KTransition';
Expand All @@ -43,8 +44,10 @@ import { themeTokens, themeBrand, themePalette, themeOutlineStyle } from './styl
import globalThemeState from './styles/globalThemeState';

import useKLiveRegion from './composables/useKLiveRegion';
import _useOverlay from './composables/_useOverlay';

const { _mountLiveRegion } = useKLiveRegion();
const { mountOverlay } = _useOverlay();

require('./grids/globalStyles.js'); // global grid styles

Expand All @@ -53,13 +56,10 @@ require('./grids/globalStyles.js'); // global grid styles
* Also, set up global state, listeners, and styles.
*/
export default function KThemePlugin(Vue) {
// Note that if DOM live regions need to be demostrated
// on the KDS website, and therefore attached to the DOM,
// just call _mountLiveRegion() in the relevant documentation
// page's 'mounted' (see 'docs/pages/usekliveregio.vue' for an example)
if (!isNuxtServerSideRendering()) {
const onDomReady = () => {
_mountLiveRegion();
mountOverlay();
document.removeEventListener('DOMContentLoaded', onDomReady);
};

Expand Down Expand Up @@ -152,6 +152,7 @@ export default function KThemePlugin(Vue) {
Vue.component('KTabs', KTabs);
Vue.component('KTabsList', KTabsList);
Vue.component('KTabsPanel', KTabsPanel);
Vue.component('KOverlay', KOverlay);
Vue.component('KTextbox', KTextbox);
Vue.component('KTooltip', KTooltip);
Vue.component('KTransition', KTransition);
Expand Down
30 changes: 20 additions & 10 deletions lib/KTooltip/Popper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
Vendored from https://github.com/RobinCK/vue-popper/
pending
https://github.com/RobinCK/vue-popper/pull/73

LE customizations
- Allow for appending to a chosen element rather than to body,
typically to the overlay container element #k-overlay.
'appendToBody' prop changedto 'appendToEl' and related changes.
-->


Expand Down Expand Up @@ -89,9 +94,14 @@
default: false,
},
dataValue: { default: null }, // eslint-disable-line
appendToBody: {
type: Boolean,
default: false,
/* An HTML element the tooltip should be appended to */
// 'type: HTMLElement' breaks the documentation build (??)
// 'type: Object' causes 'Invalid prop: type check failed for prop
// "appendToEl". Expected Object, got HTMLDivElement' warning
// in consumers
appendToEl: {
type: null,
default: null,
},
visibleArrow: {
type: Boolean,
Expand Down Expand Up @@ -155,7 +165,7 @@

created() {
this.appendedArrow = false;
this.appendedToBody = false;
this.isAppendedToEl = false;
this.popperOptions = Object.assign(this.popperOptions, this.options);
},

Expand Down Expand Up @@ -210,9 +220,9 @@
this.popperJS = null;
}

if (this.appendedToBody) {
this.appendedToBody = false;
document.body.removeChild(this.popper.parentElement);
if (this.isAppendedToEl) {
this.isAppendedToEl = false;
this.appendToEl.removeChild(this.popper.parentElement);
}
},

Expand All @@ -222,9 +232,9 @@
this.appendArrow(this.popper);
}

if (this.appendToBody && !this.appendedToBody) {
this.appendedToBody = true;
document.body.appendChild(this.popper.parentElement);
if (this.appendToEl && !this.isAppendedToEl) {
this.isAppendedToEl = true;
this.appendToEl.appendChild(this.popper.parentElement);
}

if (this.popperJS && this.popperJS.destroy) {
Expand Down
17 changes: 17 additions & 0 deletions lib/KTooltip/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:disabled="disabled"
:visibleArrow="false"
:options="options"
:appendToEl="appendToEl"
trigger="hover"
>
<div
Expand All @@ -28,6 +29,7 @@
<script>

import isArray from 'lodash/isArray';
import _useOverlay from '../composables/_useOverlay';
import Popper from './Popper';

/**
Expand All @@ -38,6 +40,12 @@
components: {
Popper,
},

setup(props) {
const { getOverlayEl } = _useOverlay();
const appendToEl = props.appendToOverlay ? getOverlayEl() : null;
return { appendToEl };
},
props: {
/**
* Name of `ref` element within the parent's `$refs` object. Tooltip will be
Expand Down Expand Up @@ -86,6 +94,15 @@
type: String,
default: null,
},
/**
* Whether or not the tooltip should be moved
* to the overlay container element `#k-overlay`
*/
// eslint-disable-next-line kolibri/vue-no-unused-properties
appendToOverlay: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand Down
10 changes: 10 additions & 0 deletions lib/composables/_useOverlay/__tests__/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
describe('_useOverlay', () => {
// this is taken care of by KThemePlugin.js that is already registered
// in the global jest setup
it(`document body contains the overlay container element #k-overlay upon the KDS plugin initialization`, () => {
expect(`
<div id="k-overlay">
</div>
`).toBeInDom();
});
});
Loading