mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Merge branch 'next' of https://github.com/shoelace-style/shoelace into next
This commit is contained in:
@@ -32,9 +32,12 @@ New versions of Shoelace are released as-needed and generally occur when a criti
|
||||
- Added `--sl-input-required-content-color` custom property to all form controls [#948](https://github.com/shoelace-style/shoelace/pull/948)
|
||||
- Added the ability to cancel `sl-show` and `sl-hide` events in `<sl-details>` [#993](https://github.com/shoelace-style/shoelace/issues/993)
|
||||
- Added `focus()` and `blur()` methods to `<sl-radio-button>`
|
||||
- Added `stepUp()` and `stepDown()` methods to `<sl-input>` and `<sl-range>` [#1013](https://github.com/shoelace-style/shoelace/pull/1013)
|
||||
- Added `showPicker()` method to `<sl-input>` [#1013](https://github.com/shoelace-style/shoelace/pull/1013)
|
||||
- Added the `handle-icon` part to `<sl-image-comparer>`
|
||||
- Added `caret`, `check`, `grip-vertical`, `indeterminate`, and `radio` icons to the system library and removed `check-lg` [#985](https://github.com/shoelace-style/shoelace/issues/985)
|
||||
- Added the `loading` attribute to `<sl-avatar>` to allow lazy loading of image avatars [#1006](https://github.com/shoelace-style/shoelace/pull/1006)
|
||||
- Added `formenctype` attribute to `<sl-button>` [#1009](https://github.com/shoelace-style/shoelace/pull/1009)
|
||||
- Added `exports` to `package.json` and removed the `main` and `module` properties [#1007](https://github.com/shoelace-style/shoelace/pull/1007)
|
||||
- Fixed a bug in `<sl-card>` that prevented the border radius to apply correctly to the header [#934](https://github.com/shoelace-style/shoelace/pull/934)
|
||||
- Fixed a bug in `<sl-button-group>` where the inner border disappeared on focus [#980](https://github.com/shoelace-style/shoelace/pull/980)
|
||||
|
||||
@@ -116,6 +116,10 @@ export default class SlButton extends ShoelaceElement implements ShoelaceFormCon
|
||||
/** Used to override the form owner's `action` attribute. */
|
||||
@property({ attribute: 'formaction' }) formAction: string;
|
||||
|
||||
/** Used to override the form owner's `enctype` attribute. */
|
||||
@property({ attribute: 'formenctype' })
|
||||
formEnctype: 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain';
|
||||
|
||||
/** Used to override the form owner's `method` attribute. */
|
||||
@property({ attribute: 'formmethod' }) formMethod: 'post' | 'get';
|
||||
|
||||
|
||||
@@ -10,6 +10,43 @@ describe('<sl-input>', () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('default properties', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input></sl-input> `);
|
||||
|
||||
expect(el.type).to.equal('text');
|
||||
expect(el.size).to.equal('medium');
|
||||
expect(el.name).to.equal('');
|
||||
expect(el.value).to.equal('');
|
||||
expect(el.defaultValue).to.equal('');
|
||||
expect(el.filled).to.be.false;
|
||||
expect(el.pill).to.be.false;
|
||||
expect(el.label).to.equal('');
|
||||
expect(el.helpText).to.equal('');
|
||||
expect(el.clearable).to.be.false;
|
||||
expect(el.passwordToggle).to.be.false;
|
||||
expect(el.passwordVisible).to.be.false;
|
||||
expect(el.noSpinButtons).to.be.false;
|
||||
expect(el.placeholder).to.equal('');
|
||||
expect(el.disabled).to.be.false;
|
||||
expect(el.readonly).to.be.false;
|
||||
expect(el.minlength).to.be.undefined;
|
||||
expect(el.maxlength).to.be.undefined;
|
||||
expect(el.min).to.be.undefined;
|
||||
expect(el.max).to.be.undefined;
|
||||
expect(el.step).to.be.undefined;
|
||||
expect(el.pattern).to.be.undefined;
|
||||
expect(el.required).to.be.false;
|
||||
expect(el.autocapitalize).to.be.undefined;
|
||||
expect(el.autocorrect).to.be.undefined;
|
||||
expect(el.autocomplete).to.be.undefined;
|
||||
expect(el.autofocus).to.be.undefined;
|
||||
expect(el.enterkeyhint).to.be.undefined;
|
||||
expect(el.spellcheck).to.be.undefined;
|
||||
expect(el.inputmode).to.be.undefined;
|
||||
expect(el.valueAsDate).to.be.null;
|
||||
expect(isNaN(el.valueAsNumber)).to.be.true;
|
||||
});
|
||||
|
||||
it('should be disabled with the disabled attribute', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input disabled></sl-input> `);
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('[part~="input"]')!;
|
||||
@@ -208,5 +245,52 @@ describe('<sl-input>', () => {
|
||||
await el.updateComplete;
|
||||
expect(el.invalid).to.be.true;
|
||||
});
|
||||
|
||||
it('should increment by step if stepUp() is called', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input type="number" step="2" value="2"></sl-input> `);
|
||||
|
||||
el.stepUp();
|
||||
await el.updateComplete;
|
||||
expect(el.value).to.equal('4');
|
||||
});
|
||||
|
||||
it('should decrement by step if stepDown() is called', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input type="number" step="2" value="2"></sl-input> `);
|
||||
|
||||
el.stepDown();
|
||||
await el.updateComplete;
|
||||
expect(el.value).to.equal('0');
|
||||
});
|
||||
|
||||
it('should fire sl-input and sl-change if stepUp() is called', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input type="number" step="2" value="2"></sl-input> `);
|
||||
|
||||
const inputHandler = sinon.spy();
|
||||
const changeHandler = sinon.spy();
|
||||
el.addEventListener('sl-input', inputHandler);
|
||||
el.addEventListener('sl-change', changeHandler);
|
||||
|
||||
el.stepUp();
|
||||
|
||||
await waitUntil(() => inputHandler.calledOnce);
|
||||
await waitUntil(() => changeHandler.calledOnce);
|
||||
expect(inputHandler).to.have.been.calledOnce;
|
||||
expect(changeHandler).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should fire sl-input and sl-change if stepDown() is called', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input type="number" step="2" value="2"></sl-input> `);
|
||||
|
||||
const inputHandler = sinon.spy();
|
||||
const changeHandler = sinon.spy();
|
||||
el.addEventListener('sl-input', inputHandler);
|
||||
el.addEventListener('sl-change', changeHandler);
|
||||
|
||||
el.stepUp();
|
||||
|
||||
await waitUntil(() => inputHandler.calledOnce);
|
||||
await waitUntil(() => changeHandler.calledOnce);
|
||||
expect(changeHandler).to.have.been.calledOnce;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class SlInput extends ShoelaceElement implements ShoelaceFormCont
|
||||
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
|
||||
|
||||
/** The input's name attribute. */
|
||||
@property() name: string;
|
||||
@property() name = '';
|
||||
|
||||
/** The input's value attribute. */
|
||||
@property() value = '';
|
||||
@@ -121,7 +121,7 @@ export default class SlInput extends ShoelaceElement implements ShoelaceFormCont
|
||||
@property({ attribute: 'no-spin-buttons', type: Boolean }) noSpinButtons = false;
|
||||
|
||||
/** The input's placeholder text. */
|
||||
@property() placeholder: string;
|
||||
@property() placeholder = '';
|
||||
|
||||
/** Disables the input. */
|
||||
@property({ type: Boolean, reflect: true }) disabled = false;
|
||||
@@ -247,6 +247,33 @@ export default class SlInput extends ShoelaceElement implements ShoelaceFormCont
|
||||
}
|
||||
}
|
||||
|
||||
/** Displays the browser picker for an input element (only works if the browser supports it for the input type). */
|
||||
showPicker() {
|
||||
if ('showPicker' in HTMLInputElement.prototype) {
|
||||
this.input.showPicker();
|
||||
}
|
||||
}
|
||||
|
||||
/** Increments the value of a numeric input type by the value of the step attribute. */
|
||||
stepUp() {
|
||||
this.input.stepUp();
|
||||
if (this.value !== this.input.value) {
|
||||
this.value = this.input.value;
|
||||
this.emit('sl-input');
|
||||
this.emit('sl-change');
|
||||
}
|
||||
}
|
||||
|
||||
/** Decrements the value of a numeric input type by the value of the step attribute. */
|
||||
stepDown() {
|
||||
this.input.stepDown();
|
||||
if (this.value !== this.input.value) {
|
||||
this.value = this.input.value;
|
||||
this.emit('sl-input');
|
||||
this.emit('sl-change');
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks for validity but does not show the browser's validation message. */
|
||||
checkValidity() {
|
||||
return this.input.checkValidity();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
|
||||
import { expect, fixture, html, oneEvent, waitUntil } from '@open-wc/testing';
|
||||
import sinon from 'sinon';
|
||||
import { serialize } from '../../utilities/form';
|
||||
import type SlRange from './range';
|
||||
|
||||
@@ -8,6 +9,22 @@ describe('<sl-range>', () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('default properties', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range></sl-range> `);
|
||||
|
||||
expect(el.name).to.equal('');
|
||||
expect(el.value).to.equal(0);
|
||||
expect(el.label).to.equal('');
|
||||
expect(el.helpText).to.equal('');
|
||||
expect(el.disabled).to.be.false;
|
||||
expect(el.invalid).to.be.false;
|
||||
expect(el.min).to.equal(0);
|
||||
expect(el.max).to.equal(100);
|
||||
expect(el.step).to.equal(1);
|
||||
expect(el.tooltip).to.equal('top');
|
||||
expect(el.defaultValue).to.equal(0);
|
||||
});
|
||||
|
||||
it('should be disabled with the disabled attribute', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range disabled></sl-range> `);
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('[part~="input"]')!;
|
||||
@@ -15,6 +32,44 @@ describe('<sl-range>', () => {
|
||||
expect(input.disabled).to.be.true;
|
||||
});
|
||||
|
||||
describe('step', () => {
|
||||
it('should increment by step if stepUp() is called', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range step="2" value="2"></sl-range> `);
|
||||
|
||||
el.stepUp();
|
||||
await el.updateComplete;
|
||||
expect(el.value).to.equal(4);
|
||||
});
|
||||
|
||||
it('should decrement by step if stepDown() is called', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range step="2" value="2"></sl-range> `);
|
||||
|
||||
el.stepDown();
|
||||
await el.updateComplete;
|
||||
expect(el.value).to.equal(0);
|
||||
});
|
||||
|
||||
it('should fire sl-change if stepUp() is called', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range step="2" value="2"></sl-range> `);
|
||||
|
||||
const changeHandler = sinon.spy();
|
||||
el.addEventListener('sl-change', changeHandler);
|
||||
el.stepUp();
|
||||
await waitUntil(() => changeHandler.calledOnce);
|
||||
expect(changeHandler).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should fire sl-change if stepDown() is called', async () => {
|
||||
const el = await fixture<SlRange>(html` <sl-range step="2" value="2"></sl-range> `);
|
||||
|
||||
const changeHandler = sinon.spy();
|
||||
el.addEventListener('sl-change', changeHandler);
|
||||
el.stepUp();
|
||||
await waitUntil(() => changeHandler.calledOnce);
|
||||
expect(changeHandler).to.have.been.calledOnce;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when serializing', () => {
|
||||
it('should serialize its name and value with FormData', async () => {
|
||||
const form = await fixture<HTMLFormElement>(html` <form><sl-range name="a" value="1"></sl-range></form> `);
|
||||
|
||||
@@ -123,6 +123,24 @@ export default class SlRange extends ShoelaceElement implements ShoelaceFormCont
|
||||
this.input.blur();
|
||||
}
|
||||
|
||||
/** Increments the value of the input by the value of the step attribute. */
|
||||
stepUp() {
|
||||
this.input.stepUp();
|
||||
if (this.value !== Number(this.input.value)) {
|
||||
this.value = Number(this.input.value);
|
||||
this.emit('sl-change');
|
||||
}
|
||||
}
|
||||
|
||||
/** Decrements the value of the input by the value of the step attribute. */
|
||||
stepDown() {
|
||||
this.input.stepDown();
|
||||
if (this.value !== Number(this.input.value)) {
|
||||
this.value = Number(this.input.value);
|
||||
this.emit('sl-change');
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks for validity but does not show the browser's validation message. */
|
||||
checkValidity() {
|
||||
return this.input.checkValidity();
|
||||
|
||||
@@ -51,7 +51,7 @@ export default class SlTextarea extends ShoelaceElement implements ShoelaceFormC
|
||||
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
|
||||
|
||||
/** The textarea's name attribute. */
|
||||
@property() name: string;
|
||||
@property() name = '';
|
||||
|
||||
/** The textarea's value attribute. */
|
||||
@property() value = '';
|
||||
@@ -66,7 +66,7 @@ export default class SlTextarea extends ShoelaceElement implements ShoelaceFormC
|
||||
@property({ attribute: 'help-text' }) helpText = '';
|
||||
|
||||
/** The textarea's placeholder text. */
|
||||
@property() placeholder: string;
|
||||
@property() placeholder = '';
|
||||
|
||||
/** The number of rows to display by default. */
|
||||
@property({ type: Number }) rows = 4;
|
||||
|
||||
4
src/declaration.d.ts
vendored
4
src/declaration.d.ts
vendored
@@ -10,3 +10,7 @@ declare namespace Chai {
|
||||
accessible: (options?: Object) => PromiseLike<Assertion>;
|
||||
}
|
||||
}
|
||||
|
||||
interface HTMLInputElement {
|
||||
showPicker: () => void;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ export class FormSubmitController implements ReactiveController {
|
||||
|
||||
// Pass form attributes through to the temporary button
|
||||
if (invoker) {
|
||||
['formaction', 'formmethod', 'formnovalidate', 'formtarget'].forEach(attr => {
|
||||
['formaction', 'formenctype', 'formmethod', 'formnovalidate', 'formtarget'].forEach(attr => {
|
||||
if (invoker.hasAttribute(attr)) {
|
||||
button.setAttribute(attr, invoker.getAttribute(attr)!);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user