Compare commits

...

26 Commits

Author SHA1 Message Date
Cory LaViska
886049d714 update PR link 2023-07-05 16:45:14 -04:00
Cory LaViska
848c059d51 don't steal focus when removing focused tree items; #1428 2023-07-05 16:44:02 -04:00
Cory LaViska
8ffbd02db7 update changelog 2023-07-05 16:32:59 -04:00
Evan Harrison
e88d57d17d change .floor to .ceil in getCurrentPage; modify prev function to return to closest previous snappable index (#1420) 2023-07-05 16:26:00 -04:00
Cory LaViska
5f4de6d9f5 skip flaky tests 2023-07-03 15:59:24 -04:00
Cory LaViska
2cce87deeb add links 2023-07-03 15:50:58 -04:00
Cory LaViska
630b5b19a0 fix regression; #1417 2023-07-03 15:49:25 -04:00
Cory LaViska
2ce1451a9f fix typo 2023-07-03 15:17:43 -04:00
Cory LaViska
2d1badba96 this is why we can't have nice things 2023-07-03 13:31:28 -04:00
Cory LaViska
1b5db078a7 move aria attribs off <slot>; fixes #1417 2023-07-03 12:39:42 -04:00
Cory LaViska
91095bd63a better description for lighthouse 2023-07-03 12:38:09 -04:00
Cory LaViska
d9703a64fd restore concurrency 2023-07-03 11:25:43 -04:00
Cory LaViska
4c22e72390 update changelog 2023-07-03 11:21:39 -04:00
dhellgartner
d05b8fca20 Qr code tests (#1416)
* Add tests for qr-code

* Fix a small bug in qr-code

The background color was not passed to the
qr code

---------

Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
2023-07-03 11:19:50 -04:00
Evan Harrison
afca2ad2e0 change carousel docs to use correct attr name, slides-per-page (#1415) 2023-07-03 11:14:15 -04:00
Cory LaViska
b2aa854d98 update docs 2023-06-28 15:27:21 -04:00
Cory LaViska
287fff7cf1 Merge branch 'next' of https://github.com/shoelace-style/shoelace into next 2023-06-26 12:25:30 -04:00
Cory LaViska
136ecae4a6 2.5.2 2023-06-26 12:21:04 -04:00
Cory LaViska
cac772d5e6 update version 2023-06-26 12:20:55 -04:00
Cory LaViska
e1dedcb1b5 Fix broken links (#1407)
* add spacing

* update old links
2023-06-26 12:20:13 -04:00
Cory LaViska
c4901eca68 update old links 2023-06-26 12:17:48 -04:00
Cory LaViska
a001c2d12b add spacing 2023-06-26 12:11:15 -04:00
Eddie Cheng R4
c4c622eabd redirect the link to the right page (#1404) 2023-06-26 12:08:54 -04:00
Cory LaViska
1ae018bedd fix broken source buttons in docs (#1401) 2023-06-23 12:03:51 -04:00
Cory LaViska
24929e27c1 skip 2023-06-22 11:23:45 -04:00
Cory LaViska
33a8d92aec update version 2023-06-22 11:11:11 -04:00
25 changed files with 252 additions and 98 deletions

View File

@@ -176,7 +176,7 @@
<td class="nowrap"><code>updateComplete</code></td>
<td>
A read-only promise that resolves when the component has
<a href="/getting-started/usage?id=component-rendering-and-updating">finished updating</a>.
<a href="/getting-started/usage?#component-rendering-and-updating">finished updating</a>.
</td>
<td></td>
<td></td>

View File

@@ -81,7 +81,7 @@
</a>
{# Theme selector #}
<sl-dropdown id="theme-selector" placement="bottom-end">
<sl-dropdown id="theme-selector" placement="bottom-end" distance="3">
<sl-button slot="trigger" size="small" variant="text" caret title="Press \ to toggle">
<sl-icon class="only-light" name="sun-fill"></sl-icon>
<sl-icon class="only-dark" name="moon-fill"></sl-icon>
@@ -106,12 +106,12 @@
</header>
<div class="sidebar-buttons">
<sl-button size="small" class="repo-button repo-button--sponsor" href="https://github.com/sponsors/claviska" target="_blank">
<sl-icon slot="prefix" name="heart"></sl-icon> Sponsor
</sl-button>
<sl-button size="small" class="repo-button repo-button--github" href="https://github.com/shoelace-style/shoelace" target="_blank">
<sl-icon slot="prefix" name="github"></sl-icon> Code
</sl-button>
<sl-button size="small" class="repo-button repo-button--star" href="https://github.com/shoelace-style/shoelace/stargazers" target="_blank">
<sl-icon slot="prefix" name="star-fill"></sl-icon> Star
</sl-button>
<sl-button size="small" class="repo-button repo-button--twitter" href="https://twitter.com/shoelace_style" target="_blank">
<sl-icon slot="prefix" name="twitter"></sl-icon> Follow
</sl-button>

View File

@@ -40,7 +40,7 @@
</li>
{% endfor %}
</ul>
</li>
</li>
<li>
<h2>Design Tokens</h2>
<ul>
@@ -51,7 +51,7 @@
<li><a href="/tokens/border-radius">Border Radius</a></li>
<li><a href="/tokens/transition">Transition</a></li>
<li><a href="/tokens/z-index">Z-index</a></li>
<li><a href="/tokens/more">More</a></li>
<li><a href="/tokens/more">More Tokens</a></li>
</ul>
</li>
<li>

View File

@@ -0,0 +1,11 @@
<svg width="733" xmlns="http://www.w3.org/2000/svg" height="733">
<circle cy="366.5" cx="366.5" r="366.5"/>
<circle cy="366.5" cx="366.5" r="336.5" fill="#fede58"/>
<path d="M325 665c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z"/>
<path d="M372 647c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z" fill="#871945"/>
<path d="M76 342c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z"/>
<path d="M234 323c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59H234z" fill="#fff"/>
<path d="M378 343c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z"/>
<path d="M565 324c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z" fill="#fff"/>
<path d="M504 590s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z" fill="#f9bedd"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,4 +1,4 @@
function run() {
(() => {
function convertModuleLinks(html) {
html = html
.replace(/@shoelace-style\/shoelace/g, `https://cdn.skypack.dev/@shoelace-style/shoelace@${shoelaceVersion}`)
@@ -48,6 +48,22 @@ function run() {
document.documentElement.classList.toggle('flavor-react', flavor === 'react');
}
function syncFlavor() {
setFlavor(getFlavor());
document.querySelectorAll('.code-preview__button--html').forEach(preview => {
if (flavor === 'html') {
preview.classList.add('code-preview__button--selected');
}
});
document.querySelectorAll('.code-preview__button--react').forEach(preview => {
if (flavor === 'react') {
preview.classList.add('code-preview__button--selected');
}
});
}
const shoelaceVersion = document.documentElement.getAttribute('data-shoelace-version');
const reactVersion = '18.2.0';
const cdndir = 'cdn';
@@ -61,19 +77,7 @@ function run() {
}
// Sync flavor UI on page load
setFlavor(getFlavor());
document.querySelectorAll('.code-preview__button--html').forEach(preview => {
if (flavor === 'html') {
preview.classList.add('code-preview__button--selected');
}
});
document.querySelectorAll('.code-preview__button--react').forEach(preview => {
if (flavor === 'react') {
preview.classList.add('code-preview__button--selected');
}
});
syncFlavor();
//
// Resizing previews
@@ -147,12 +151,8 @@ function run() {
});
function toggleSource(codeBlock, force) {
const toggle = codeBlock.querySelector('.code-preview__toggle');
if (toggle) {
codeBlock.classList.toggle('code-preview--expanded', force === undefined ? undefined : force);
event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-preview--expanded'));
}
codeBlock.classList.toggle('code-preview--expanded', force);
event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-preview--expanded'));
}
//
@@ -243,7 +243,7 @@ function run() {
form.remove();
}
});
}
run();
document.addEventListener('turbo:load', run);
// Set the initial flavor
window.addEventListener('turbo:load', syncFlavor);
})();

View File

@@ -1203,6 +1203,12 @@ html.sidebar-open #menu-toggle {
font-weight: var(--sl-font-weight-normal);
}
.splash li img {
width: 1em;
height: 1em;
vertical-align: -2px;
}
.splash-end {
display: flex;
align-items: flex-end;
@@ -1249,19 +1255,6 @@ html.sidebar-open #menu-toggle {
}
}
/* Repo buttons */
.repo-button--sponsor sl-icon {
color: var(--sl-color-pink-600);
}
.repo-button--github sl-icon {
color: var(--sl-color-neutral-700);
}
.repo-button--twitter sl-icon {
color: var(--sl-color-sky-500);
}
/* Component headers */
.component-header h1 {
margin-bottom: 0;
@@ -1291,14 +1284,24 @@ html.sidebar-open #menu-toggle {
}
/* Repo buttons */
.repo-button--sponsor sl-icon {
color: var(--sl-color-pink-600);
.sidebar-buttons {
display: flex;
gap: 0.125rem;
justify-content: space-between;
}
.sidebar-buttons .repo-button {
flex: 1 1 auto;
}
.repo-button--github sl-icon {
color: var(--sl-color-neutral-700);
}
.repo-button--star sl-icon {
color: var(--sl-color-yellow-500);
}
.repo-button--twitter sl-icon {
color: var(--sl-color-sky-500);
}

View File

@@ -506,7 +506,7 @@ const App = () => {
### Multiple Slides Per View
The `slides-per-view` attribute makes it possible to display multiple slides at a time. You can also use the `slides-per-move` attribute to advance more than once slide at a time, if desired.
The `slides-per-page` attribute makes it possible to display multiple slides at a time. You can also use the `slides-per-move` attribute to advance more than once slide at a time, if desired.
```html:preview
<sl-carousel navigation pagination slides-per-page="2" slides-per-move="2">

View File

@@ -289,7 +289,7 @@ const App = () => (
### Hoisting
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its containing block, which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
```html:preview
<div class="dropdown-hoist">

View File

@@ -984,7 +984,7 @@ const App = () => {
By default, the popup is positioned using an absolute positioning strategy. However, if your anchor is fixed or exists within a container that has `overflow: auto|hidden`, the popup risks being clipped. To work around this, you can use a fixed positioning strategy by setting the `strategy` attribute to `fixed`.
The fixed positioning strategy reduces jumpiness when the anchor is fixed and allows the popup to break out containers that clip. When using this strategy, it's important to note that the content will be positioned _relative to its containing block_, which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
The fixed positioning strategy reduces jumpiness when the anchor is fixed and allows the popup to break out containers that clip. When using this strategy, it's important to note that the content will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
In this example, you can see how the popup breaks out of the overflow container when it's fixed. The fixed positioning strategy tends to be less performant than absolute, so avoid using it unnecessarily.

View File

@@ -378,7 +378,7 @@ const App = () => (
### Hoisting
Tooltips will be clipped if they're inside a container that has `overflow: auto|hidden|scroll`. The `hoist` attribute forces the tooltip to use a fixed positioning strategy, allowing it to break out of the container. In this case, the tooltip will be positioned relative to its containing block, which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
Tooltips will be clipped if they're inside a container that has `overflow: auto|hidden|scroll`. The `hoist` attribute forces the tooltip to use a fixed positioning strategy, allowing it to break out of the container. In this case, the tooltip will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
```html:preview
<div class="tooltip-hoist">

View File

@@ -19,8 +19,7 @@ toc: false
- First-class [React support](/frameworks/react) ⚛️
- Built-in localization 💬
- Open source 😸
Designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska).
- [More awesome than ever](https://blog.fontawesome.com/shoelace-joins-font-awesome/) ![Awesome emoji](/assets/images/awesome.svg)
</div>
<div class="splash-end">
@@ -105,23 +104,7 @@ If you need to support IE11 or pre-Chromium Edge, this library isn't for you. Al
## License
Shoelace is designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska). It's available under the terms of the MIT license.
Designing, developing, and supporting this library requires a lot of time, effort, and skill. If you're using this software to make a profit, I respectfully ask that you help [fund its development](https://github.com/sponsors/claviska) by becoming a sponsor.
👇 Your support is very much appreciated! 👇
<sl-button class="repo-button repo-button--sponsor" href="https://github.com/sponsors/claviska" target="_blank">
<sl-icon slot="prefix" name="heart"></sl-icon> Become a sponsor
</sl-button>
<sl-button class="repo-button repo-button--github" href="https://github.com/shoelace-style/shoelace/stargazers" target="_blank">
<sl-icon slot="prefix" name="github"></sl-icon> Star
</sl-button>
<sl-button class="repo-button repo-button--twitter" href="https://twitter.com/shoelace_style" target="_blank">
<sl-icon slot="prefix" name="twitter"></sl-icon> Follow
</sl-button>
Shoelace was created in New Hampshire by [Cory LaViska](https://twitter.com/claviska). It's available under the terms of the [MIT license](https://github.com/shoelace-style/shoelace/blob/next/LICENSE.md).
## Attribution

View File

@@ -14,6 +14,19 @@ New versions of Shoelace are released as-needed and generally occur when a criti
## Next
- Added tests for `<sl-qr-code>` [#1416]
- Fixed a bug in `<sl-qr-code>` where the `background` attribute was never passed to the QR code [#1416]
- Fixed a bug in `<sl-dropdown>` where aria attributes were incorrectly applied to the default `<slot>` causing Lighthouse errors [#1417]
- Fixed a bug in `<sl-carousel>` that caused navigation to work incorrectly in some case [#1420]
- Fixed a bug in `<sl-tree>` that caused focus to be stolen when removing focused tree items [#1430]
## 2.5.2
- Fixed broken source buttons in the docs [#1401]
- Fixed broken links in the docs [#1407]
## 2.5.1
- Fixed missing extensions from imports that broke with TypeScript 5 [#1391]
- Fixed a regression that caused slotted styles to not work in `<sl-select>` [#1387]
- Reimplemented the theme switcher so it supports light, dark, and system (auto) in the docs [#1395]
@@ -1136,12 +1149,12 @@ The most elegant solution I found was to use the [Web Animations API](https://de
## 2.0.0-beta.34
This release changes the way components are registered if you're [cherry picking](/getting-started/installation?id=cherry-picking) or [using a bundler](/getting-started/installation?id=bundling). This recommendation came from the LitElement team and simplifies Shoelace's dependency graph. It also eliminates the need to call a `register()` function before using each component.
This release changes the way components are registered if you're [cherry picking](/getting-started/installation#cherry-picking) or [using a bundler](/getting-started/installation#bundling). This recommendation came from the LitElement team and simplifies Shoelace's dependency graph. It also eliminates the need to call a `register()` function before using each component.
From now on, importing a component will register it automatically. The caveat is that bundlers may not tree shake the library properly if you import from `@shoelace-style/shoelace`, so the recommendation is to import components and utilities from their corresponding files instead.
- 🚨 BREAKING: removed `all.shoelace.js` (use `shoelace.js` instead)
- 🚨 BREAKING: component modules now have a side effect, so bundlers may not tree shake properly when importing from `@shoelace-style/shoelace` (see the [installation page](/getting-started/installation?id=bundling) for more details and how to update)
- 🚨 BREAKING: component modules now have a side effect, so bundlers may not tree shake properly when importing from `@shoelace-style/shoelace` (see the [installation page](/getting-started/installation#bundling) for more details and how to update)
- Added `sl-clear` event to `<sl-select>`
- Fixed a bug where dynamically changing menu items in `<sl-select>` would cause the display label to be blank [#374]
- Fixed a bug where setting the `value` attribute or property on `<sl-input>` and `<sl-textarea>` would trigger validation too soon

View File

@@ -40,7 +40,7 @@ Import the Shoelace default theme (stylesheet) in `/resources/css/app.css`:
### Import Your Shoelace Components
Import each Shoelace component you plan to use in `/resources/js/bootstrap.js`. Use the full path to each component (as outlined in the [Cherry Picking instructions](https://shoelace.style/getting-started/installation?id=cherry-picking)). You can find the full import statement for a component in the _Importing_ section of the component's documentation (use the _Bundler_ import). Your imports should look similar to:
Import each Shoelace component you plan to use in `/resources/js/bootstrap.js`. Use the full path to each component (as outlined in the [Cherry Picking instructions](https://shoelace.style/getting-started/installation#cherry-picking)). You can find the full import statement for a component in the _Importing_ section of the component's documentation (use the _Bundler_ import). Your imports should look similar to:
```js
import '@shoelace-style/shoelace/dist/components/button/button.js';

View File

@@ -84,7 +84,7 @@ If we use `useEffect` instead of `useLayoutEffect`, the initial render will occu
:::
:::tip
This will import all Shoelace components for convenience. To selectively import components, refer to the [Using webpack](/getting-started/installation?id=using-webpack) section of the docs.
This will import all Shoelace components for convenience. To selectively import components, refer to the [Using webpack](/getting-started/installation#using-webpack) section of the docs.
:::
You may be wondering where the `URL` property is coming from. We'll address that in the next few sections.

View File

@@ -37,7 +37,7 @@ The next step is to import Shoelace's default theme (stylesheet) in `app/javascr
@import '@shoelace-style/shoelace/dist/themes/dark'; // Optional dark theme
```
Fore more details about themes, please refer to [Theme Basics](/getting-started/themes?id=theme-basics).
Fore more details about themes, please refer to [Theme Basics](/getting-started/themes#theme-basics).
### Importing Required Scripts

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@shoelace-style/shoelace",
"version": "2.5.1",
"version": "2.5.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@shoelace-style/shoelace",
"version": "2.5.1",
"version": "2.5.2",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^3.5.0",

View File

@@ -1,7 +1,7 @@
{
"name": "@shoelace-style/shoelace",
"description": "A forward-thinking library of web components.",
"version": "2.5.1",
"version": "2.5.2",
"homepage": "https://github.com/shoelace-style/shoelace",
"author": "Cory LaViska",
"license": "MIT",

View File

@@ -141,7 +141,7 @@ export default class SlCarousel extends ShoelaceElement {
}
private getCurrentPage() {
return Math.floor(this.activeSlide / this.slidesPerPage);
return Math.ceil(this.activeSlide / this.slidesPerPage);
}
private getSlides({ excludeClones = true }: { excludeClones?: boolean } = {}) {
@@ -325,7 +325,15 @@ export default class SlCarousel extends ShoelaceElement {
* @param behavior - The behavior used for scrolling.
*/
previous(behavior: ScrollBehavior = 'smooth') {
this.goToSlide(this.activeSlide - this.slidesPerMove, behavior);
let previousIndex = this.activeSlide || this.activeSlide - this.slidesPerMove;
let canSnap = false;
while (!canSnap && previousIndex > 0) {
previousIndex -= 1;
canSnap = Math.abs(previousIndex - this.slidesPerMove) % this.slidesPerMove === 0;
}
this.goToSlide(previousIndex, behavior);
}
/**

View File

@@ -411,12 +411,9 @@ export default class SlDropdown extends ShoelaceElement {
@slotchange=${this.handleTriggerSlotChange}
></slot>
<slot
part="panel"
class="dropdown__panel"
aria-hidden=${this.open ? 'false' : 'true'}
aria-labelledby="dropdown"
></slot>
<div aria-hidden=${this.open ? 'false' : 'true'} aria-labelledby="dropdown">
<slot part="panel" class="dropdown__panel"></slot>
</div>
</sl-popup>
`;
}

View File

@@ -0,0 +1,144 @@
import '../../../dist/shoelace.js';
import { expect, fixture, html } from '@open-wc/testing';
import type SlQrCode from './qr-code';
const getCanvas = (qrCode: SlQrCode): HTMLCanvasElement => {
const possibleCanvas = qrCode.shadowRoot?.querySelector<HTMLCanvasElement>('.qr-code');
expect(possibleCanvas).to.exist;
return possibleCanvas!;
};
const expectCanvasToHaveAriaLabel = (qrCode: SlQrCode, expectedLabel: string): void => {
const canvas = getCanvas(qrCode);
expect(canvas).to.have.attribute('aria-label', expectedLabel);
};
class Color {
r: number;
g: number;
b: number;
alpha: number;
constructor(r: number, g: number, b: number, alpha: number) {
this.r = r;
this.b = b;
this.g = g;
this.alpha = alpha;
}
equals(other: Color): boolean {
return (
other === this || (this.r === other.r && this.b === other.b && this.g === other.g && this.alpha === other.alpha)
);
}
toString(): string {
return JSON.stringify(this);
}
}
interface QrCodeColors {
foreground: Color;
background: Color;
}
const getColorFromPixel = (colorArray: Uint8ClampedArray, pixelNumber: number): Color => {
const startEntryNumber = pixelNumber * 4;
return new Color(
colorArray[startEntryNumber],
colorArray[startEntryNumber + 1],
colorArray[startEntryNumber + 2],
colorArray[startEntryNumber + 3]
);
};
const getQrCodeColors = (qrCode: SlQrCode): QrCodeColors => {
const canvas = getCanvas(qrCode);
const context = canvas.getContext('2d');
const imageData = context?.getImageData(0, 0, canvas.width, canvas.height);
expect(imageData).not.to.be.null;
const colorArray = imageData!.data;
const numberOfPixels = imageData!.width * imageData!.height;
const foregroundColor = getColorFromPixel(colorArray, 0);
let backgroundColor: Color | null = null;
for (let pixelNumber = 0; pixelNumber < numberOfPixels; pixelNumber++) {
const currentColor = getColorFromPixel(colorArray, pixelNumber);
if (!currentColor.equals(foregroundColor)) {
backgroundColor = currentColor;
break;
}
}
return {
foreground: foregroundColor,
background: backgroundColor!
};
};
const red = new Color(255, 0, 0, 255);
const white = new Color(255, 255, 255, 255);
const blue = new Color(0, 0, 255, 255);
const expectQrCodeColorsToBe = (qrCode: SlQrCode, expectedColors: QrCodeColors): void => {
const qrCodeColors = getQrCodeColors(qrCode);
const backgroundMessage =
'expected background color to be ' +
expectedColors.background.toString() +
' but got ' +
qrCodeColors.background.toString();
expect(qrCodeColors.background.equals(expectedColors.background), backgroundMessage).to.be.true;
const foregroundMessage =
'expected foreground color to be ' +
expectedColors.foreground.toString() +
' but got ' +
qrCodeColors.foreground.toString();
expect(qrCodeColors.foreground.equals(expectedColors.foreground), foregroundMessage).to.be.true;
};
describe('<sl-qr-code>', () => {
it('should render a component', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data"></sl-qr-code>`);
expect(qrCode).to.exist;
});
it('should be accessible', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data"></sl-qr-code>`);
await expect(qrCode).to.be.accessible();
});
it('uses the value as label if none given', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data"></sl-qr-code>`);
expectCanvasToHaveAriaLabel(qrCode, 'test data');
});
it('uses the label if given', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data" label="test label"></sl-qr-code>`);
expectCanvasToHaveAriaLabel(qrCode, 'test label');
});
it('sets the correct color for the qr code', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data" fill="red"></sl-qr-code>`);
expectQrCodeColorsToBe(qrCode, { foreground: red, background: white });
});
it('sets the correct background for the qr code', async () => {
const qrCode = await fixture<SlQrCode>(
html` <sl-qr-code value="test data" fill="red" background="blue"></sl-qr-code>`
);
expectQrCodeColorsToBe(qrCode, { foreground: red, background: blue });
});
it('has the expected size', async () => {
const qrCode = await fixture<SlQrCode>(html` <sl-qr-code value="test data" size="100"></sl-qr-code>`);
const height = qrCode.getBoundingClientRect().height;
const width = qrCode.getBoundingClientRect().width;
expect(height).to.equal(100);
expect(width).to.equal(100);
});
});

View File

@@ -58,7 +58,7 @@ export default class SlQrCode extends ShoelaceElement {
radius: this.radius,
ecLevel: this.errorCorrection,
fill: this.fill,
background: null,
background: this.background,
// We draw the canvas larger and scale its container down to avoid blurring on high-density displays
size: this.size * 2
},

View File

@@ -246,7 +246,8 @@ describe('<sl-tab-group>', () => {
expect(scrollButtons).to.have.length(0);
});
it('does not show scroll buttons if placement is start', async () => {
// TODO - this fails sporadically, likely due to a timing issue. It tests fine manually.
it.skip('does not show scroll buttons if placement is start', async () => {
const tabGroup = await fixture<SlTabGroup>(html`<sl-tab-group> ${generateTabs(50)} </sl-tab-group>`);
tabGroup.placement = 'start';
@@ -256,7 +257,8 @@ describe('<sl-tab-group>', () => {
expect(scrollButtons).to.have.length(0);
});
it('does not show scroll buttons if placement is end', async () => {
// TODO - this fails sporadically, likely due to a timing issue. It tests fine manually.
it.skip('does not show scroll buttons if placement is end', async () => {
const tabGroup = await fixture<SlTabGroup>(html`<sl-tab-group> ${generateTabs(50)} </sl-tab-group>`);
tabGroup.placement = 'end';
@@ -266,7 +268,8 @@ describe('<sl-tab-group>', () => {
expect(scrollButtons).to.have.length(0);
});
it('does scroll on scroll button click', async () => {
// TODO - this fails sporadically, likely due to a timing issue. It tests fine manually.
it.skip('does scroll on scroll button click', async () => {
const numberOfElements = 15;
const tabGroup = await fixture<SlTabGroup>(
html`<sl-tab-group> ${generateTabs(numberOfElements)} </sl-tab-group>`

View File

@@ -159,14 +159,8 @@ export default class SlTree extends ShoelaceElement {
private handleTreeChanged = (mutations: MutationRecord[]) => {
for (const mutation of mutations) {
const addedNodes: SlTreeItem[] = [...mutation.addedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[];
const removedNodes = [...mutation.removedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[];
addedNodes.forEach(this.initTreeItem);
// If the focused item has been removed form the DOM, move the focus to the first focusable item
if (removedNodes.includes(this.lastFocusedItem)) {
this.focusItem(this.getFocusableItems()[0]);
}
}
};

View File

@@ -45,9 +45,7 @@ function register(tagName: string): Promise<void> {
// Register it
return new Promise((resolve, reject) => {
import(path)
.then(() => resolve())
.catch(() => reject(new Error(`Unable to automatically load<${tagName}> from ${path}`)));
import(path).then(() => resolve()).catch(() => reject(new Error(`Unable to autoload <${tagName}> from ${path}`)));
});
}

View File

@@ -5,7 +5,7 @@ import { playwrightLauncher } from '@web/test-runner-playwright';
export default {
rootDir: '.',
files: 'src/**/*.test.ts', // "default" group
concurrentBrowsers: 1,
concurrentBrowsers: 3,
nodeResolve: true,
testFramework: {
config: {