feat(helpers): new package with several helpers
This commit is contained in:
parent
614be5fb89
commit
d13672a226
13 changed files with 657 additions and 0 deletions
30
packages/helpers/README.md
Normal file
30
packages/helpers/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Helpers
|
||||
|
||||
[//]: # 'AUTO INSERT HEADER PREPUBLISH'
|
||||
|
||||
A helpers package that contains several helpers that are used inside lion but can be used outside as well.
|
||||
|
||||
These helpers are considered developer tools, not actual things to use in production.
|
||||
Therefore, they may not have the same quality standards as our other packages.
|
||||
|
||||
## Live Demo/Documentation
|
||||
|
||||
> See our [storybook](http://lion-web-components.netlify.com/?path=/docs/helpers) for a live demo and API documentation
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm i @lion/helpers
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Example using the sb-action-logger helper component.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import '@lion/helpers/sb-action-logger.js';
|
||||
</script>
|
||||
|
||||
<sb-action-logger></sb-action-logger>
|
||||
```
|
||||
6
packages/helpers/index.js
Normal file
6
packages/helpers/index.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Utilities
|
||||
export { renderLitAsNode } from './renderLitAsNode/src/renderLitAsNode.js';
|
||||
|
||||
// Components
|
||||
export { SbActionLogger } from './sb-action-logger/src/SbActionLogger.js';
|
||||
export { SbLocaleSwitcher } from './sb-locale-switcher/src/SbLocaleSwitcher.js';
|
||||
38
packages/helpers/package.json
Normal file
38
packages/helpers/package.json
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "@lion/helpers",
|
||||
"version": "0.1.0",
|
||||
"description": "Helpers that are used throughout lion and can be used outside",
|
||||
"author": "ing-bank",
|
||||
"homepage": "https://github.com/ing-bank/lion/",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ing-bank/lion.git",
|
||||
"directory": "packages/helpers"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "../../scripts/npm-prepublish.js"
|
||||
},
|
||||
"keywords": [
|
||||
"lion",
|
||||
"web-components",
|
||||
"helpers",
|
||||
"action logger"
|
||||
],
|
||||
"main": "index.js",
|
||||
"module": "index.js",
|
||||
"files": [
|
||||
"sb-action-logger",
|
||||
"*.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@lion/core": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@open-wc/demoing-storybook": "^1.6.1",
|
||||
"@open-wc/testing": "^2.3.4"
|
||||
}
|
||||
}
|
||||
7
packages/helpers/renderLitAsNode/src/renderLitAsNode.js
Normal file
7
packages/helpers/renderLitAsNode/src/renderLitAsNode.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { render } from '@lion/core';
|
||||
|
||||
export const renderLitAsNode = litHtmlTemplate => {
|
||||
const offlineRenderContainer = document.createElement('div');
|
||||
render(litHtmlTemplate, offlineRenderContainer);
|
||||
return offlineRenderContainer.firstElementChild;
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { expect } from '@open-wc/testing';
|
||||
import { html } from '@lion/core';
|
||||
import { renderLitAsNode } from '../src/renderLitAsNode.js';
|
||||
|
||||
describe('renderLitAsNode', () => {
|
||||
it('should return a matching HTMLElement (Node)', () => {
|
||||
const el = renderLitAsNode(html`
|
||||
<div>
|
||||
<a href="#" target="_blank">Link</a>
|
||||
Some text: <span>Hello, World</span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
expect(el).to.be.instanceOf(HTMLElement);
|
||||
expect(el).dom.to.equal(`
|
||||
<div>
|
||||
<a href="#" target="_blank">Link</a>
|
||||
Some text: <span>Hello, World</span>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should only render and return the first (root) node in the template', () => {
|
||||
const el = renderLitAsNode(html`
|
||||
<div>
|
||||
<a href="#" target="_blank">Link</a>
|
||||
Some text: <span>Hello, World</span>
|
||||
</div>
|
||||
<div>Sibling div</div>
|
||||
`);
|
||||
|
||||
expect(el).dom.to.equal(`
|
||||
<div>
|
||||
<a href="#" target="_blank">Link</a>
|
||||
Some text: <span>Hello, World</span>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
});
|
||||
3
packages/helpers/sb-action-logger.js
Normal file
3
packages/helpers/sb-action-logger.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { SbActionLogger } from './sb-action-logger/src/SbActionLogger.js';
|
||||
|
||||
window.customElements.define('sb-action-logger', SbActionLogger);
|
||||
35
packages/helpers/sb-action-logger/README.md
Normal file
35
packages/helpers/sb-action-logger/README.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Storybook Action Logger
|
||||
|
||||
[//]: # 'AUTO INSERT HEADER PREPUBLISH'
|
||||
|
||||
A visual element to show action logs in Storybook demos `sb-action-logger`.
|
||||
|
||||
**This is a demonstrative tool**, not a debugging tool (although it may help initially).
|
||||
If you try logging complex values such as arrays, objects or promises,
|
||||
you should expect to get only the string interpretation as the output in this logger.
|
||||
|
||||
## Live Demo/Documentation
|
||||
|
||||
> See our [storybook](http://lion-web-components.netlify.com/?path=/docs/helpers-storybook-action-logger) for a live demo and API documentation
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm i @lion/helpers
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import '@lion/helpers/sb-action-logger/sb-action-logger.js';
|
||||
</script>
|
||||
|
||||
<sb-action-logger></sb-action-logger>
|
||||
```
|
||||
|
||||
Then, with the sb-action-logger instance selected, call the `log` method on it.
|
||||
|
||||
```js
|
||||
myActionLoggerInstance.log('Hello, World!');
|
||||
```
|
||||
46
packages/helpers/sb-action-logger/custom-elements.json
Normal file
46
packages/helpers/sb-action-logger/custom-elements.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"version": 0,
|
||||
"tags": [
|
||||
{
|
||||
"name": "sb-action-logger",
|
||||
"description": "A visual element to show action logs in Storybook demos",
|
||||
"properties": [
|
||||
{
|
||||
"name": "title",
|
||||
"type": "String",
|
||||
"description": "The title of action logger",
|
||||
"default": "Action Logger"
|
||||
}
|
||||
],
|
||||
"events": [],
|
||||
"slots": [],
|
||||
"cssProperties": [
|
||||
{
|
||||
"name": "--sb-action-logger-title-color",
|
||||
"description": "Color of the title",
|
||||
"type": "Color"
|
||||
},
|
||||
{
|
||||
"name": "--sb-action-logger-text-color",
|
||||
"description": "Color of the logs' text",
|
||||
"type": "Color"
|
||||
},
|
||||
{
|
||||
"name": "--sb-action-logger-cue-color-primary",
|
||||
"description": "Primary color of the visual cue",
|
||||
"type": "Color"
|
||||
},
|
||||
{
|
||||
"name": "--sb-action-logger-cue-color-secondary",
|
||||
"description": "Secondary color of the visual cue",
|
||||
"type": "Color"
|
||||
},
|
||||
{
|
||||
"name": "--sb-action-logger-cue-duration",
|
||||
"description": "Duration of the visual cue",
|
||||
"type": "Number"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
178
packages/helpers/sb-action-logger/src/SbActionLogger.js
Normal file
178
packages/helpers/sb-action-logger/src/SbActionLogger.js
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import { css, html, LitElement, render } from '@lion/core';
|
||||
|
||||
/** @typedef {import('lit-html').TemplateResult} TemplateResult */
|
||||
|
||||
export class SbActionLogger extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
title: { type: String, reflect: true },
|
||||
__logCounter: { type: Number },
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
--sb-action-logger-title-color: black;
|
||||
--sb-action-logger-text-color: black;
|
||||
--sb-action-logger-cue-color-primary: #3f51b5;
|
||||
--sb-action-logger-cue-color-secondary: #c5cae9;
|
||||
--sb-action-logger-cue-duration: 1000ms;
|
||||
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header__info {
|
||||
color: var(--sb-action-logger-title-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.header__clear {
|
||||
margin-left: 16px;
|
||||
border-radius: 0px;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.header__clear:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header__title {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.header__log-cue {
|
||||
position: relative;
|
||||
height: 3px;
|
||||
background-color: var(--sb-action-logger-cue-color-secondary);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header__log-cue-overlay {
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: 50px;
|
||||
left: -50px;
|
||||
background-color: var(--sb-action-logger-cue-color-primary);
|
||||
}
|
||||
|
||||
.header__log-cue-overlay--slide {
|
||||
animation: slidethrough var(--sb-action-logger-cue-duration) ease-in;
|
||||
}
|
||||
|
||||
@keyframes slidethrough {
|
||||
from {
|
||||
left: -50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
to {
|
||||
left: 100%;
|
||||
width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.logger {
|
||||
overflow-y: auto;
|
||||
max-height: 110px;
|
||||
}
|
||||
|
||||
.logger__log {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.logger__log:not(:last-child) {
|
||||
border-bottom: 1px solid lightgrey;
|
||||
}
|
||||
|
||||
.logger__log code {
|
||||
color: var(--sb-action-logger-text-color);
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.title = 'Action Logger';
|
||||
this.__logCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the passed content as a node, and appends it to the logger
|
||||
* Only supports simple values, will be interpreted to a String
|
||||
* E.g. an Object will become '[object Object]'
|
||||
*
|
||||
* @param {} content Content to be logged to the action logger
|
||||
*/
|
||||
log(content) {
|
||||
const loggerEl = this.shadowRoot.querySelector('.logger');
|
||||
const offlineRenderContainer = document.createElement('div');
|
||||
render(this._logTemplate(content), offlineRenderContainer);
|
||||
// TODO: Feature, combine duplicate consecutive logs as 1 dom element and add a counter for dupes
|
||||
loggerEl.appendChild(offlineRenderContainer.firstElementChild);
|
||||
this.__logCounter += 1;
|
||||
this.__animateCue();
|
||||
loggerEl.scrollTo({ top: loggerEl.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected getter that returns the template of a single log
|
||||
*
|
||||
* @return {TemplateResult} TemplateResult that uses the content passed to create a log
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_logTemplate(content) {
|
||||
return html`
|
||||
<div class="logger__log">
|
||||
<code>${content}</code>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
__animateCue() {
|
||||
const cueEl = this.shadowRoot.querySelector('.header__log-cue-overlay');
|
||||
cueEl.classList.remove('header__log-cue-overlay--slide');
|
||||
// This triggers browser to stop batching changes because it has to evaluate something.
|
||||
// eslint-disable-next-line no-void
|
||||
void this.offsetWidth;
|
||||
// So that when we arrive here, the browser sees this adding as an actual 'change'
|
||||
// and this means the animation gets refired.
|
||||
cueEl.classList.add('header__log-cue-overlay--slide');
|
||||
}
|
||||
|
||||
__clearLogs() {
|
||||
const loggerEl = this.shadowRoot.querySelector('.logger');
|
||||
loggerEl.innerHTML = '';
|
||||
this.__logCounter = 0;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="header">
|
||||
<div class="header__info">
|
||||
<p class="header__title">${this.title}</p>
|
||||
<div class="header__counter">${this.__logCounter}</div>
|
||||
<button class="header__clear" @click=${this.__clearLogs}>Clear</button>
|
||||
</div>
|
||||
<div class="header__log-cue">
|
||||
<div class="header__log-cue-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="logger"></div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
116
packages/helpers/sb-action-logger/stories/index.stories.mdx
Normal file
116
packages/helpers/sb-action-logger/stories/index.stories.mdx
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import {
|
||||
Story,
|
||||
Preview,
|
||||
Meta,
|
||||
Props,
|
||||
html,
|
||||
} from '@open-wc/demoing-storybook';
|
||||
|
||||
import '../../sb-action-logger.js';
|
||||
|
||||
<Meta
|
||||
title="Helpers/Storybook Action Logger"
|
||||
parameters={{
|
||||
component: "sb-action-logger",
|
||||
options: { selectedPanel: "storybookjs/knobs/panel" }
|
||||
}}
|
||||
/>
|
||||
|
||||
# Storybook Action Logger
|
||||
|
||||
A visual element to show action logs in Storybook demos `sb-action-logger`
|
||||
|
||||
<Story name="Default">
|
||||
{html`
|
||||
<style>
|
||||
sb-action-logger {
|
||||
font-family: 'Nunito Sans', -apple-system, '.SFNSText-Regular', 'San Francisco',
|
||||
BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
<div>To log: <code>Hello, World!</code></div>
|
||||
<button
|
||||
@click=${() => document.getElementById('logger-a53209ghj').log('Hello, World!')}
|
||||
>Click this button</button>
|
||||
<sb-action-logger id="logger-a53209ghj"></sb-action-logger>
|
||||
`}
|
||||
</Story>
|
||||
|
||||
```html
|
||||
<div>To log: <code>Hello, World!</code></div>
|
||||
<button
|
||||
@click=${() => document.getElementById('logger-a53209ghj').log('Hello, World!')}
|
||||
>Click this button</button>
|
||||
<sb-action-logger id="logger-a53209ghj"></sb-action-logger>
|
||||
```
|
||||
|
||||
Note that you need some reference to your logger. Above example shows this by using a unique ID.
|
||||
|
||||
## Features:
|
||||
|
||||
- A public method `log` to log things to the action logger.
|
||||
- Overridable `title` property.
|
||||
- Clear button to clear logs
|
||||
- A counter to count the total amount of logs
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm i sb-action-logger
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
<Props of="sb-action-logger" />
|
||||
|
||||
## Variations
|
||||
|
||||
### Custom Title
|
||||
|
||||
<Story name="Custom Title">
|
||||
{html`
|
||||
<button
|
||||
@click=${() => document.getElementById('logger-vnfoiu3478').log('Hello, World!')}
|
||||
>Log</button>
|
||||
<sb-action-logger id="logger-vnfoiu3478" .title=${'Hello World'}></sb-action-logger>
|
||||
`}
|
||||
</Story>
|
||||
|
||||
|
||||
## Rationale
|
||||
|
||||
This component was created due to a need for a nice visual action logger in Storybook Docs mode.
|
||||
|
||||
In docs mode, you do not have access to the action logger addon component, and it is nice to be able to show actions inline in your demos and documentation.
|
||||
|
||||
### Opinionated
|
||||
|
||||
I added quite a bit of styling on this component to make it look decent.
|
||||
There are a bunch of styles that you can easily override to make it fit your design system which I believe should be enough in most cases.
|
||||
If you need more control you can always:
|
||||
|
||||
- Override the host styles, there's a few custom CSS props that you can override as well.
|
||||
- Extend the component and apply your overrides
|
||||
- Open an issue if you believe it would be good to make something more flexible / configurable
|
||||
|
||||
Maybe in the future I will abstract this component to a more generic (ugly) one with no styles, so it's more friendly as a shared component.
|
||||
|
||||
### Plugin
|
||||
|
||||
If you use an action logger inside your Story in Storybook, you will also see it in your canvas, and this may not be your intention.
|
||||
|
||||
One idea I have is that we can simplify the usage further by making this a Storybook (docs-)plugin or decorator or whatever.
|
||||
I am not too familiar with them at the moment, but it would be cool if someone can simply enable an action logger option on a particular Story inside their .mdx,
|
||||
and then actions are automatically logged to the visual logger below it. Would need to figure out how to catch the action and pass it to the visual logger element.
|
||||
|
||||
I have not investigated yet on the how, but that is the rough idea. Feel free to help out here :)
|
||||
|
||||
## Future
|
||||
|
||||
I plan on adding more features.
|
||||
They can always be found in the test folder where I specify new features as tests first, and then I skip them until I implement them. Easy to find them that way.
|
||||
If the feature you'd like is not in the tests, I probably did not think about it yet or did not plan to do it yet, so in that case feel free to make an issue so we can add it.
|
||||
|
||||
I'm happy to accept pull requests for skipped tests (features to be added), see the CONTRIBUTING.md on GitHub for more details on how to contribute to this codebase.
|
||||
125
packages/helpers/sb-action-logger/test/sb-action-logger.test.js
Normal file
125
packages/helpers/sb-action-logger/test/sb-action-logger.test.js
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
import '../../sb-action-logger.js';
|
||||
|
||||
// Note: skips are left out of first iteration
|
||||
|
||||
describe('sb-action-logger', () => {
|
||||
it('has a default title "Action Logger"', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
expect(el.shadowRoot.querySelector('.header__title').innerText).to.equal('Action Logger');
|
||||
});
|
||||
|
||||
it('has a title property / attribute that can be overridden', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger title="Logging your favorite fruit"></sb-action-logger>
|
||||
`);
|
||||
|
||||
const titleEl = el.shadowRoot.querySelector('.header__title');
|
||||
|
||||
expect(titleEl.innerText).to.equal('Logging your favorite fruit');
|
||||
});
|
||||
|
||||
describe('Logger behavior', () => {
|
||||
it('is possible to send something to the logger using the log method', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
el.log('Hello, World!');
|
||||
|
||||
const loggerEl = el.shadowRoot.querySelector('.logger');
|
||||
|
||||
expect(loggerEl.children.length).to.equal(1);
|
||||
expect(loggerEl.firstElementChild.innerText).to.equal('Hello, World!');
|
||||
});
|
||||
|
||||
it('appends new logs to the logger', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
el.log('Hello, World!');
|
||||
el.log('Hello, Planet!');
|
||||
el.log('Hello, Earth!');
|
||||
el.log('Hello, World!');
|
||||
el.log('Hello, Planet!');
|
||||
|
||||
const loggerEl = el.shadowRoot.querySelector('.logger');
|
||||
|
||||
expect(loggerEl.children.length).to.equal(5);
|
||||
});
|
||||
|
||||
it('shows a visual cue whenever something is logged to the logger', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
const cueEl = el.shadowRoot.querySelector('.header__log-cue-overlay');
|
||||
expect(cueEl.classList.contains('header__log-cue-overlay--slide')).to.be.false;
|
||||
|
||||
el.log('Hello, World!');
|
||||
expect(cueEl.classList.contains('header__log-cue-overlay--slide')).to.be.true;
|
||||
});
|
||||
|
||||
it('has a visual counter that counts the amount of total logs', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
const cueEl = el.shadowRoot.querySelector('.header__log-cue-overlay');
|
||||
|
||||
expect(cueEl.classList.contains('.header__log-cue-overlay--slide')).to.be.false;
|
||||
|
||||
el.log('Hello, World!');
|
||||
expect(cueEl.classList.contains('header__log-cue-overlay--slide')).to.be.true;
|
||||
});
|
||||
|
||||
it('has a clear button that clears the logs and resets the counter', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
|
||||
el.log('Hello, World!');
|
||||
el.log('Hello, Planet!');
|
||||
|
||||
const clearBtn = el.shadowRoot.querySelector('.header__clear');
|
||||
clearBtn.click();
|
||||
|
||||
expect(el.shadowRoot.querySelector('.logger').children.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('duplicate consecutive logs are kept as one', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
expect(el).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Potential Additional Features', () => {
|
||||
it.skip('duplicate consecutive adds a visual counter to count per duplicate', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
expect(el).to.be.true;
|
||||
});
|
||||
|
||||
// This is handy if you don't want to keep track of updates
|
||||
it.skip('can be set to mode=simple for only showing a single log statement', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger simple></sb-action-logger>
|
||||
`);
|
||||
expect(el).to.be.true;
|
||||
});
|
||||
|
||||
it.skip('fires a sb-action-logged event when something is logged to the logger', async () => {
|
||||
const el = await fixture(html`
|
||||
<sb-action-logger></sb-action-logger>
|
||||
`);
|
||||
expect(el).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
3
packages/helpers/sb-locale-switcher.js
Normal file
3
packages/helpers/sb-locale-switcher.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { SbLocaleSwitcher } from './sb-locale-switcher/src/SbLocaleSwitcher.js';
|
||||
|
||||
window.customElements.define('sb-locale-switcher', SbLocaleSwitcher);
|
||||
31
packages/helpers/sb-locale-switcher/src/SbLocaleSwitcher.js
Normal file
31
packages/helpers/sb-locale-switcher/src/SbLocaleSwitcher.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { LitElement, html } from '@lion/core';
|
||||
|
||||
export class SbLocaleSwitcher extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
showLocales: { type: Array, attribute: 'show-locales' },
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showLocales = ['en-GB', 'en-US', 'en-AU', 'nl-NL', 'nl-BE'];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
callback(locale) {
|
||||
document.documentElement.lang = locale;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this.showLocales.map(
|
||||
showLocale => html`
|
||||
<button @click=${() => this.callback(showLocale)}>
|
||||
${showLocale}
|
||||
</button>
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue