chore: removed accidentally committed directory
This commit is contained in:
parent
a1f1270671
commit
886151ba85
8 changed files with 0 additions and 455 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
# Lion Drawer Overview
|
|
||||||
|
|
||||||
[=> See Source <=](../../../docs/components/drawer/overview.md)
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
# Lion Drawer Use Cases
|
|
||||||
|
|
||||||
[=> See Source <=](../../../docs/components/drawer/use-cases.md)
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { LionDrawer } from './src/LionDrawer.js';
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import { LionDrawer } from './src/LionDrawer.js';
|
|
||||||
|
|
||||||
customElements.define('lion-drawer', LionDrawer);
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@lion/drawer",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"description": "Drawer that can be expanded to reveal it contents",
|
|
||||||
"license": "MIT",
|
|
||||||
"author": "ing-bank",
|
|
||||||
"homepage": "https://github.com/ing-bank/lion/",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/ing-bank/lion.git",
|
|
||||||
"directory": "packages/drawer"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"exports": {
|
|
||||||
".": "./index.js",
|
|
||||||
"./define": "./lion-drawer.js",
|
|
||||||
"./docs/*": "./docs/*"
|
|
||||||
},
|
|
||||||
"main": "index.js",
|
|
||||||
"module": "index.js",
|
|
||||||
"files": [
|
|
||||||
"*.d.ts",
|
|
||||||
"*.js",
|
|
||||||
"custom-elements.json",
|
|
||||||
"docs",
|
|
||||||
"src",
|
|
||||||
"test",
|
|
||||||
"test-helpers",
|
|
||||||
"translations",
|
|
||||||
"types"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"custom-elements-manifest": "custom-elements-manifest analyze --litelement --exclude \"docs/**/*\" \"test-helpers/**/*\"",
|
|
||||||
"debug": "cd ../../ && npm run debug -- --group drawer",
|
|
||||||
"debug:firefox": "cd ../../ && npm run debug:firefox -- --group drawer",
|
|
||||||
"debug:webkit": "cd ../../ && npm run debug:webkit -- --group drawer",
|
|
||||||
"publish-docs": "node ../../packages-node/publish-docs/src/cli.js --github-url https://github.com/ing-bank/lion/ --git-root-dir ../../",
|
|
||||||
"prepublishOnly": "npm run publish-docs && npm run custom-elements-manifest",
|
|
||||||
"test": "cd ../../ && npm run test:browser -- --group drawer"
|
|
||||||
},
|
|
||||||
"sideEffects": [
|
|
||||||
"lion-drawer.js",
|
|
||||||
"./docs/styled-drawer-content.js"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@lion/collapsible": "^0.9.1",
|
|
||||||
"@lion/core": "^0.24.0"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"drawer",
|
|
||||||
"lion",
|
|
||||||
"web-components"
|
|
||||||
],
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"customElements": "custom-elements.json"
|
|
||||||
}
|
|
||||||
|
|
@ -1,217 +0,0 @@
|
||||||
import { html } from '@lion/core';
|
|
||||||
import { LionCollapsible } from '@lion/collapsible';
|
|
||||||
import { drawerStyle } from './drawerStyle.js';
|
|
||||||
|
|
||||||
const EVENT = {
|
|
||||||
TRANSITION_END: 'transitionend',
|
|
||||||
TRANSITION_START: 'transitionstart',
|
|
||||||
};
|
|
||||||
|
|
||||||
export class LionDrawer extends LionCollapsible {
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
transitioning: {
|
|
||||||
type: Boolean,
|
|
||||||
reflect: true,
|
|
||||||
},
|
|
||||||
opened: {
|
|
||||||
type: Boolean,
|
|
||||||
reflect: true,
|
|
||||||
},
|
|
||||||
position: {
|
|
||||||
type: String,
|
|
||||||
reflect: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this.__toggle = () => {
|
|
||||||
this.opened = !this.opened;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
|
|
||||||
if (!this.hasAttribute('position')) {
|
|
||||||
this.position = 'left';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._contentNode) {
|
|
||||||
this._contentNode.style.setProperty('display', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__setBoundaries();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update aria labels on state change.
|
|
||||||
* @param {import('@lion/core').PropertyValues } changedProperties
|
|
||||||
*/
|
|
||||||
updated(changedProperties) {
|
|
||||||
if (changedProperties.has('opened')) {
|
|
||||||
this._openedChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return [drawerStyle];
|
|
||||||
}
|
|
||||||
|
|
||||||
__setBoundaries() {
|
|
||||||
const host = this.shadowRoot?.host;
|
|
||||||
|
|
||||||
if (this.position === 'top') {
|
|
||||||
this.minHeight = host ? getComputedStyle(host).getPropertyValue('--min-height') : '0px';
|
|
||||||
this.maxHeight = host ? getComputedStyle(host).getPropertyValue('--max-height') : '0px';
|
|
||||||
this.minWidth = '0px';
|
|
||||||
this.maxWidth = 'none';
|
|
||||||
} else {
|
|
||||||
this.minWidth = host ? getComputedStyle(host).getPropertyValue('--min-width') : '0px';
|
|
||||||
this.maxWidth = host ? getComputedStyle(host).getPropertyValue('--max-width') : '0px';
|
|
||||||
this.minHeight = 'auto';
|
|
||||||
this.maxHeight = 'fit-content';
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const prop = this.position === 'top' ? 'width' : 'height';
|
|
||||||
|
|
||||||
if (this.__contentNode) {
|
|
||||||
this.__contentNode.style.setProperty(prop, '');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter for position property, available values are 'top', 'left' and 'right'
|
|
||||||
* @param {String} position
|
|
||||||
*/
|
|
||||||
set position(position) {
|
|
||||||
const stale = this.position;
|
|
||||||
this._position = position;
|
|
||||||
this.setAttribute('position', position);
|
|
||||||
|
|
||||||
this.__setBoundaries();
|
|
||||||
this.requestUpdate('position', stale);
|
|
||||||
}
|
|
||||||
|
|
||||||
get position() {
|
|
||||||
return this._position ?? 'left';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger show animation and wait for transition to be finished.
|
|
||||||
* @param {Object} options - element node and its options
|
|
||||||
* @param {HTMLElement} options.contentNode
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
async _showAnimation({ contentNode }) {
|
|
||||||
const min = this.position === 'top' ? this.minHeight : this.minWidth;
|
|
||||||
const max = this.position === 'top' ? this.maxHeight : this.maxWidth;
|
|
||||||
const prop = this.position === 'top' ? 'height' : 'width';
|
|
||||||
|
|
||||||
contentNode.style.setProperty(prop, /** @type {string} */ (min));
|
|
||||||
await new Promise(resolve => requestAnimationFrame(() => resolve(true)));
|
|
||||||
contentNode.style.setProperty(prop, /** @type {string} */ (max));
|
|
||||||
await this._waitForTransition({ contentNode });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger hide animation and wait for transition to be finished.
|
|
||||||
* @param {Object} options - element node and its options
|
|
||||||
* @param {HTMLElement} options.contentNode
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
async _hideAnimation({ contentNode }) {
|
|
||||||
if (
|
|
||||||
((this.position === 'left' || this.position === 'right') &&
|
|
||||||
this._contentWidth === this.minWidth) ||
|
|
||||||
(this.position === 'top' && this._contentHeight === this.minHeight)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const min = this.position === 'top' ? this.minHeight : this.minWidth;
|
|
||||||
const prop = this.position === 'top' ? 'height' : 'width';
|
|
||||||
|
|
||||||
contentNode.style.setProperty(prop, /** @type {string} */ (min));
|
|
||||||
await this._waitForTransition({ contentNode });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait until the transition event is finished.
|
|
||||||
* @param {Object} options - element node and its options
|
|
||||||
* @param {HTMLElement} options.contentNode
|
|
||||||
* @returns {Promise<void>} transition event
|
|
||||||
*/
|
|
||||||
_waitForTransition({ contentNode }) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const transitionStarted = () => {
|
|
||||||
contentNode.removeEventListener(EVENT.TRANSITION_START, transitionStarted);
|
|
||||||
this.transitioning = true;
|
|
||||||
};
|
|
||||||
contentNode.addEventListener(EVENT.TRANSITION_START, transitionStarted);
|
|
||||||
|
|
||||||
const transitionEnded = () => {
|
|
||||||
contentNode.removeEventListener(EVENT.TRANSITION_END, transitionEnded);
|
|
||||||
this.transitioning = false;
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
contentNode.addEventListener(EVENT.TRANSITION_END, transitionEnded);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
get __contentNode() {
|
|
||||||
return /** @type {HTMLElement} */ (this.shadowRoot?.querySelector('.container'));
|
|
||||||
}
|
|
||||||
|
|
||||||
get _contentWidth() {
|
|
||||||
const size = this.__contentNode?.getBoundingClientRect().width || 0;
|
|
||||||
return `${size}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get _contentHeight() {
|
|
||||||
const size = this.__contentNode?.getBoundingClientRect().height || 0;
|
|
||||||
return `${size}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
_openedChanged() {
|
|
||||||
this._updateContentSize();
|
|
||||||
if (this._invokerNode) {
|
|
||||||
this._invokerNode.setAttribute('aria-expanded', `${this.opened}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent('opened-changed'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _updateContentSize() {
|
|
||||||
if (this.__contentNode) {
|
|
||||||
if (this.opened) {
|
|
||||||
await this._showAnimation({ contentNode: this.__contentNode });
|
|
||||||
} else {
|
|
||||||
await this._hideAnimation({ contentNode: this.__contentNode });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<div class="container">
|
|
||||||
<div class="headline-container">
|
|
||||||
<slot name="invoker"></slot>
|
|
||||||
<slot name="headline"></slot>
|
|
||||||
</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<slot name="content"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
import { css } from '@lion/core';
|
|
||||||
|
|
||||||
export const drawerStyle = css`
|
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
--min-width: 72px;
|
|
||||||
--max-width: 320px;
|
|
||||||
--min-height: auto;
|
|
||||||
--max-height: fit-content;
|
|
||||||
--start-width: var(--min-width);
|
|
||||||
--start-height: 100%;
|
|
||||||
--transition-property: width;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([position='top']) {
|
|
||||||
width: 100%;
|
|
||||||
--min-width: 0px;
|
|
||||||
--max-width: none;
|
|
||||||
--min-height: 50px;
|
|
||||||
--max-height: 200px;
|
|
||||||
--start-width: 100%;
|
|
||||||
--start-height: var(--min-height);
|
|
||||||
--transition-property: height;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: var(--start-width);
|
|
||||||
height: var(--start-height);
|
|
||||||
min-width: var(--min-width);
|
|
||||||
max-width: var(--max-width);
|
|
||||||
min-height: var(--min-height);
|
|
||||||
max-height: var(--max-height);
|
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: var(--transition-property) 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.headline-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([position='right']) .headline-container {
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-container {
|
|
||||||
overflow: hidden;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::slotted([slot='content']) {
|
|
||||||
width: var(--max-width);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
import { expect, fixture as _fixture } from '@open-wc/testing';
|
|
||||||
import { html } from 'lit/static-html.js';
|
|
||||||
|
|
||||||
import '@lion/drawer/define';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../src/LionDrawer').LionDrawer} LionDrawer
|
|
||||||
* @typedef {import('@lion/core').TemplateResult} TemplateResult
|
|
||||||
*/
|
|
||||||
const fixture = /** @type {(arg: TemplateResult) => Promise<LionDrawer>} */ (_fixture);
|
|
||||||
|
|
||||||
const template = html`
|
|
||||||
<lion-drawer>
|
|
||||||
<button slot="invoker">Open</button>
|
|
||||||
<p slot="headline">Headline</p>
|
|
||||||
<div slot="content" class="drawer">This is the content of the drawer</div>
|
|
||||||
</lion-drawer>
|
|
||||||
`;
|
|
||||||
|
|
||||||
describe('<lion-drawer>', () => {
|
|
||||||
describe('Drawer', () => {
|
|
||||||
it('sets position to "left" by default', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
expect(drawer.position).to.equal('left');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has [position] attribute which serves as styling hook', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
expect(drawer).to.have.attribute('position').equal('left');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the minimum and maximum width when position=left', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
const minWidth = getComputedStyle(drawer).getPropertyValue('--min-width');
|
|
||||||
const maxWidth = getComputedStyle(drawer).getPropertyValue('--max-width');
|
|
||||||
|
|
||||||
expect(drawer.minWidth).to.equal(minWidth);
|
|
||||||
expect(drawer.maxWidth).to.equal(maxWidth);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the minimum and maximum width when position=right', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
drawer.position = 'right';
|
|
||||||
await drawer.updateComplete;
|
|
||||||
|
|
||||||
const minWidth = getComputedStyle(drawer).getPropertyValue('--min-width');
|
|
||||||
const maxWidth = getComputedStyle(drawer).getPropertyValue('--max-width');
|
|
||||||
|
|
||||||
expect(drawer.minWidth).to.equal(minWidth);
|
|
||||||
expect(drawer.maxWidth).to.equal(maxWidth);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the minimum and maximum height when position=top', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
drawer.position = 'top';
|
|
||||||
await drawer.updateComplete;
|
|
||||||
|
|
||||||
const minHeight = getComputedStyle(drawer).getPropertyValue('--min-height');
|
|
||||||
const maxHeight = getComputedStyle(drawer).getPropertyValue('--max-height');
|
|
||||||
|
|
||||||
expect(drawer.minHeight).to.equal(minHeight);
|
|
||||||
expect(drawer.maxHeight).to.equal(maxHeight);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
|
||||||
it('[collapsed] is a11y AXE accessible', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
await expect(drawer).to.be.accessible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('[opened] is a11y AXE accessible', async () => {
|
|
||||||
const drawer = await fixture(template);
|
|
||||||
drawer.opened = true;
|
|
||||||
await expect(drawer).to.be.accessible();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Invoker', () => {
|
|
||||||
it('links id of content items to invoker via [aria-controls]', async () => {
|
|
||||||
const drawerElement = await fixture(template);
|
|
||||||
const invoker = drawerElement.querySelector('[slot=invoker]');
|
|
||||||
const content = drawerElement.querySelector('[slot=content]');
|
|
||||||
expect(invoker?.getAttribute('aria-controls')).to.equal(content?.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds aria-expanded="false" to invoker when its content is not expanded', async () => {
|
|
||||||
const drawerElement = await fixture(template);
|
|
||||||
const invoker = drawerElement.querySelector('[slot=invoker]');
|
|
||||||
expect(invoker).to.have.attribute('aria-expanded', 'false');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds aria-expanded="true" to invoker when its content is expanded', async () => {
|
|
||||||
const drawerElement = await fixture(template);
|
|
||||||
const invoker = drawerElement.querySelector('[slot=invoker]');
|
|
||||||
drawerElement.opened = true;
|
|
||||||
await drawerElement.updateComplete;
|
|
||||||
expect(invoker).to.have.attribute('aria-expanded', 'true');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Contents', () => {
|
|
||||||
it('adds aria-labelledby referring to invoker id', async () => {
|
|
||||||
const drawerElement = await fixture(template);
|
|
||||||
const invoker = drawerElement.querySelector('[slot=invoker]');
|
|
||||||
const content = drawerElement.querySelector('[slot=content]');
|
|
||||||
expect(content).to.have.attribute('aria-labelledby', invoker?.id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
Reference in a new issue