mirror of
https://github.com/shoelace-style/shoelace.git
synced 2026-01-12 02:59:13 +00:00
Merge branch 'next' into konnorrogers/fix-select-regression
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"autoloading",
|
||||
"autoplay",
|
||||
"bezier",
|
||||
"Bokmål",
|
||||
"boxicons",
|
||||
"CACHEABLE",
|
||||
"callout",
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#custom-properties') }}">customizing CSS custom properties</a>.</em></p>
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/customizing#custom-properties') }}">customizing CSS custom properties</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# CSS Parts #}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@7.3.0/+esm';
|
||||
import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm';
|
||||
|
||||
(() => {
|
||||
if (!window.scrollPositions) {
|
||||
@@ -6,13 +6,13 @@ import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@7.3.0/+esm'
|
||||
}
|
||||
|
||||
function preserveScroll() {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
document.querySelectorAll('[data-preserve-scroll]').forEach(element => {
|
||||
scrollPositions[element.id] = element.scrollTop;
|
||||
});
|
||||
}
|
||||
|
||||
function restoreScroll(event) {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
document.querySelectorAll('[data-preserve-scroll]').forEach(element => {
|
||||
element.scrollTop = scrollPositions[element.id];
|
||||
});
|
||||
|
||||
|
||||
@@ -504,17 +504,17 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
|
||||
|
||||
### Lazy loading options
|
||||
|
||||
Lazy loading options is very hard to get right. `<wa-select>` largely follows how a native `<select>` works.
|
||||
Lazy loading options is very hard to get right. `<sl-select>` largely follows how a native `<select>` works.
|
||||
|
||||
Here are the following conditions:
|
||||
|
||||
- If a `<wa-select>` is created without any options, but is given a `value` attribute, its `value` will be `""`, and then when options are added, if any of the options have a value equal to the `<wa-select>` value, the value of the `<wa-select>` will equal that of the option.
|
||||
- If a `<sl-select>` is created without any options, but is given a `value` attribute, its `value` will be `""`, and then when options are added, if any of the options have a value equal to the `<sl-select>` value, the value of the `<sl-select>` will equal that of the option.
|
||||
|
||||
EX: `<wa-select value="foo">` will have a value of `""` until `<wa-option value="foo">Foo</wa-option>` connects, at which point its value will become `"foo"` when submitting.
|
||||
EX: `<sl-select value="foo">` will have a value of `""` until `<sl-option value="foo">Foo</sl-option>` connects, at which point its value will become `"foo"` when submitting.
|
||||
|
||||
- If a `<wa-select multiple>` with an initial value has multiple values, but only some of the options are present, it will only respect the options that are present, and if a selected option is loaded in later, _AND_ the value of the select has not changed via user interaction or direct property assignment, it will add the selected option to the form value and to the `.value` of the select.
|
||||
- If a `<sl-select multiple>` with an initial value has multiple values, but only some of the options are present, it will only respect the options that are present, and if a selected option is loaded in later, _AND_ the value of the select has not changed via user interaction or direct property assignment, it will add the selected option to the form value and to the `.value` of the select.
|
||||
|
||||
This can be hard to conceptualize, so heres a fairly large example showing how lazy loaded options work with `<wa-select>` and `<wa-select multiple>` when given initial value attributes. Feel free to play around with it in a codepen.
|
||||
This can be hard to conceptualize, so heres a fairly large example showing how lazy loaded options work with `<sl-select>` and `<sl-select multiple>` when given initial value attributes. Feel free to play around with it in a codepen.
|
||||
|
||||
```html:preview
|
||||
<form id="lazy-options-example">
|
||||
|
||||
@@ -31,7 +31,7 @@ const App = () => (
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` attribute to change a tab's size.
|
||||
Use the `size` attribute to change a tag's size.
|
||||
|
||||
```html:preview
|
||||
<sl-tag size="small">Small</sl-tag>
|
||||
@@ -53,7 +53,7 @@ const App = () => (
|
||||
|
||||
### Pill
|
||||
|
||||
Use the `pill` attribute to give tabs rounded edges.
|
||||
Use the `pill` attribute to give tags rounded edges.
|
||||
|
||||
```html:preview
|
||||
<sl-tag size="small" pill>Small</sl-tag>
|
||||
|
||||
@@ -14,11 +14,17 @@ New versions of Shoelace are released as-needed and generally occur when a criti
|
||||
|
||||
## Next
|
||||
|
||||
- Added Norwegian translations for Bokmål and Nynorsk [#2268]
|
||||
- Added Ukrainian translation [#2270]
|
||||
- Added support for <kbd>Enter</kbd> to `<sl-split-panel>` to align with ARIA APG's [window splitter pattern](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/) [#2234]
|
||||
- Fixed a bug in `<sl-select>` when setting the value property before the element connected. [#2255]
|
||||
- Fixed a bug in `<sl-select>` where it was using the wrong tag name. [#2287]
|
||||
- Fixed a bug in `<sl-carousel>` that caused the navigation icons to be reversed
|
||||
- Fixed a bug in `<sl-select>` that prevented label changes in `<sl-option>` from updating the controller [#1971]
|
||||
- Fixed a bug in `<sl-textarea>` that caused a console warning in Firefox when typing [#2107]
|
||||
- Fixed a bug in `<sl-carousel>` that caused interactive elements to be activated when dragging [#2196]
|
||||
- Fixed a bug in `<sl-carousel>` that caused out of order slides when used inside a resize observer [#2260]
|
||||
- Fixed a bug in `<sl-rating>` that allowed tabbing into the rating when readonly [#2271]
|
||||
- Improved performance of `<sl-range>` by skipping positioning logic when tooltip isn't shown [#2064]
|
||||
|
||||
## 2.18.0
|
||||
|
||||
@@ -92,6 +92,7 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
@state() dragging = false;
|
||||
|
||||
private autoplayController = new AutoplayController(this, () => this.next());
|
||||
private dragStartPosition: [number, number] = [-1, -1];
|
||||
private readonly localize = new LocalizeController(this);
|
||||
private mutationObserver: MutationObserver;
|
||||
private pendingSlideChange = false;
|
||||
@@ -151,6 +152,20 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
) as SlCarouselItem[];
|
||||
}
|
||||
|
||||
private handleClick(event: MouseEvent) {
|
||||
if (this.dragging && this.dragStartPosition[0] > 0 && this.dragStartPosition[1] > 0) {
|
||||
const deltaX = Math.abs(this.dragStartPosition[0] - event.clientX);
|
||||
const deltaY = Math.abs(this.dragStartPosition[1] - event.clientY);
|
||||
const delta = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
|
||||
// Prevents clicks on interactive elements while dragging if the click is within a small range. This prevents
|
||||
// accidental drags from interfering with intentional clicks.
|
||||
if (delta >= 10) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleKeyDown(event: KeyboardEvent) {
|
||||
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) {
|
||||
const target = event.target as HTMLElement;
|
||||
@@ -208,6 +223,7 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
// Start dragging if it hasn't yet
|
||||
this.scrollContainer.style.setProperty('scroll-snap-type', 'none');
|
||||
this.dragging = true;
|
||||
this.dragStartPosition = [event.clientX, event.clientY];
|
||||
}
|
||||
|
||||
this.scrollContainer.scrollBy({
|
||||
@@ -255,6 +271,7 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
scrollContainer.style.removeProperty('scroll-snap-type');
|
||||
|
||||
this.dragging = false;
|
||||
this.dragStartPosition = [-1, -1];
|
||||
this.handleScrollEnd();
|
||||
});
|
||||
};
|
||||
@@ -364,10 +381,10 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
this.createClones();
|
||||
}
|
||||
|
||||
this.synchronizeSlides();
|
||||
|
||||
// Because the DOM may be changed, restore the scroll position to the active slide
|
||||
this.goToSlide(this.activeSlide, 'auto');
|
||||
|
||||
this.synchronizeSlides();
|
||||
}
|
||||
|
||||
private createClones() {
|
||||
@@ -533,6 +550,7 @@ export default class SlCarousel extends ShoelaceElement {
|
||||
@mousedown="${this.handleMouseDragStart}"
|
||||
@scroll="${this.handleScroll}"
|
||||
@scrollend=${this.handleScrollEnd}
|
||||
@click=${this.handleClick}
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
@@ -114,7 +114,7 @@ export default class SlDialog extends ShoelaceElement {
|
||||
super.disconnectedCallback();
|
||||
this.modal.deactivate();
|
||||
unlockBodyScrolling(this);
|
||||
this.closeWatcher?.destroy();
|
||||
this.removeOpenListeners();
|
||||
}
|
||||
|
||||
private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {
|
||||
|
||||
@@ -131,7 +131,7 @@ export default class SlDrawer extends ShoelaceElement {
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
unlockBodyScrolling(this);
|
||||
this.closeWatcher?.destroy();
|
||||
this.removeOpenListeners();
|
||||
}
|
||||
|
||||
private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {
|
||||
|
||||
@@ -240,7 +240,7 @@ export default class SlRating extends ShoelaceElement {
|
||||
aria-valuenow=${this.value}
|
||||
aria-valuemin=${0}
|
||||
aria-valuemax=${this.max}
|
||||
tabindex=${this.disabled ? '-1' : '0'}
|
||||
tabindex=${this.disabled || this.readonly ? '-1' : '0'}
|
||||
@click=${this.handleClick}
|
||||
@keydown=${this.handleKeyDown}
|
||||
@mouseenter=${this.handleMouseEnter}
|
||||
|
||||
@@ -518,8 +518,8 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
|
||||
|
||||
/* @internal - used by options to update labels */
|
||||
public handleDefaultSlotChange() {
|
||||
if (!customElements.get('wa-option')) {
|
||||
customElements.whenDefined('wa-option').then(() => this.handleDefaultSlotChange());
|
||||
if (!customElements.get('sl-option')) {
|
||||
customElements.whenDefined('sl-option').then(() => this.handleDefaultSlotChange());
|
||||
}
|
||||
|
||||
const allOptions = this.getAllOptions();
|
||||
|
||||
39
src/translations/nb.ts
Normal file
39
src/translations/nb.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { registerTranslation } from '../utilities/localize.js';
|
||||
import type { Translation } from '../utilities/localize.js';
|
||||
|
||||
const translation: Translation = {
|
||||
$code: 'nb',
|
||||
$name: 'Norwegian Bokmål',
|
||||
$dir: 'ltr',
|
||||
|
||||
carousel: 'Karusell',
|
||||
clearEntry: 'Tøm felt',
|
||||
close: 'Lukk',
|
||||
copied: 'Kopiert',
|
||||
copy: 'Kopier',
|
||||
currentValue: 'Nåværende verdi',
|
||||
error: 'Feil',
|
||||
goToSlide: (slide, count) => `Gå til visning ${slide} av ${count}`,
|
||||
hidePassword: 'Skjul passord',
|
||||
loading: 'Laster',
|
||||
nextSlide: 'Neste visning',
|
||||
numOptionsSelected: num => {
|
||||
if (num === 0) return 'Ingen alternativer valgt';
|
||||
if (num === 1) return 'Ett alternativ valgt';
|
||||
return `${num} alternativer valgt`;
|
||||
},
|
||||
previousSlide: 'Forrige visning',
|
||||
progress: 'Fremdrift',
|
||||
remove: 'Fjern',
|
||||
resize: 'Endre størrelse',
|
||||
scrollToEnd: 'Rull til slutten',
|
||||
scrollToStart: 'Rull til starten',
|
||||
selectAColorFromTheScreen: 'Velg en farge fra skjermen',
|
||||
showPassword: 'Vis passord',
|
||||
slideNum: slide => `Visning ${slide}`,
|
||||
toggleColorFormat: 'Bytt fargeformat'
|
||||
};
|
||||
|
||||
registerTranslation(translation);
|
||||
|
||||
export default translation;
|
||||
39
src/translations/nn.ts
Normal file
39
src/translations/nn.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { registerTranslation } from '../utilities/localize.js';
|
||||
import type { Translation } from '../utilities/localize.js';
|
||||
|
||||
const translation: Translation = {
|
||||
$code: 'nn',
|
||||
$name: 'Norwegian Nynorsk',
|
||||
$dir: 'ltr',
|
||||
|
||||
carousel: 'Karusell',
|
||||
clearEntry: 'Tøm felt',
|
||||
close: 'Lukk',
|
||||
copied: 'Kopiert',
|
||||
copy: 'Kopier',
|
||||
currentValue: 'Nåverande verdi',
|
||||
error: 'Feil',
|
||||
goToSlide: (slide, count) => `Gå til visning ${slide} av ${count}`,
|
||||
hidePassword: 'Gøym passord',
|
||||
loading: 'Lastar',
|
||||
nextSlide: 'Neste visning',
|
||||
numOptionsSelected: num => {
|
||||
if (num === 0) return 'Ingen alternativ valt';
|
||||
if (num === 1) return 'Eitt alternativ valt';
|
||||
return `${num} alternativ valt`;
|
||||
},
|
||||
previousSlide: 'Førre visning',
|
||||
progress: 'Framdrift',
|
||||
remove: 'Fjern',
|
||||
resize: 'Endre storleik',
|
||||
scrollToEnd: 'Rull til slutten',
|
||||
scrollToStart: 'Rull til starten',
|
||||
selectAColorFromTheScreen: 'Vel ein farge frå skjermen',
|
||||
showPassword: 'Vis passord',
|
||||
slideNum: slide => `Visning ${slide}`,
|
||||
toggleColorFormat: 'Byt fargeformat'
|
||||
};
|
||||
|
||||
registerTranslation(translation);
|
||||
|
||||
export default translation;
|
||||
41
src/translations/uk.ts
Normal file
41
src/translations/uk.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { registerTranslation } from '../utilities/localize.js';
|
||||
import type { Translation } from '../utilities/localize.js';
|
||||
|
||||
const translation: Translation = {
|
||||
$code: 'uk',
|
||||
$name: 'Українська',
|
||||
$dir: 'ltr',
|
||||
|
||||
carousel: 'Карусель',
|
||||
clearEntry: 'Очистити поле',
|
||||
close: 'Закрити',
|
||||
copied: 'Скопійовано',
|
||||
copy: 'Скопіювати',
|
||||
currentValue: 'Поточне значення',
|
||||
error: 'Збій',
|
||||
goToSlide: (slide, count) => `Перейти до слайда №${slide} з ${count}`,
|
||||
hidePassword: 'Приховати пароль',
|
||||
loading: 'Завантаження',
|
||||
nextSlide: 'Наступний слайд',
|
||||
numOptionsSelected: num => {
|
||||
const n = num % 10;
|
||||
if (n === 0) return 'не вибрано варіантів';
|
||||
if (n === 1) return 'вибрано 1 варіант';
|
||||
if (n === 2 || n === 3 || n === 4) return `вибрано ${num} варіанти`;
|
||||
return `вибрано ${num} варіантів`;
|
||||
},
|
||||
previousSlide: 'Попередній слайд',
|
||||
progress: 'Поступ',
|
||||
remove: 'Видалити',
|
||||
resize: 'Змінити розмір',
|
||||
scrollToEnd: 'Прокрутити в кінець',
|
||||
scrollToStart: 'Прокрутити на початок',
|
||||
selectAColorFromTheScreen: 'Виберіть колір на екрані',
|
||||
showPassword: 'Показати пароль',
|
||||
slideNum: slide => `Слайд ${slide}`,
|
||||
toggleColorFormat: 'Переключити кольорову модель'
|
||||
};
|
||||
|
||||
registerTranslation(translation);
|
||||
|
||||
export default translation;
|
||||
Reference in New Issue
Block a user