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