Skip to content

Commit

Permalink
fixes #985
Browse files Browse the repository at this point in the history
  • Loading branch information
claviska committed Nov 10, 2022
1 parent 197a0c3 commit f64f144
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 81 deletions.
8 changes: 8 additions & 0 deletions docs/components/checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,17 @@ Use the `setCustomValidity()` method to set a custom validation message. This wi
const form = document.querySelector('.custom-validity');
const checkbox = form.querySelector('sl-checkbox');
const errorMessage = `Don't forget to check me!`;
// Set initial validity as soon as the element is defined
customElements.whenDefined('sl-checkbox').then(() => {
checkbox.setCustomValidity(errorMessage);
});
// Update validity on change
checkbox.addEventListener('sl-change', () => {
checkbox.setCustomValidity(checkbox.checked ? '' : errorMessage);
});
// Handle submit
form.addEventListener('submit', event => {
event.preventDefault();
Expand All @@ -91,19 +94,24 @@ Use the `setCustomValidity()` method to set a custom validation message. This wi
```jsx react
import { useEffect, useRef } from 'react';
import { SlButton, SlCheckbox } from '@shoelace-style/shoelace/dist/react';

const App = () => {
const checkbox = useRef(null);
const errorMessage = `Don't forget to check me!`;

function handleChange() {
checkbox.current.setCustomValidity(checkbox.current.checked ? '' : errorMessage);
}

function handleSubmit(event) {
event.preventDefault();
alert('All fields are valid!');
}

useEffect(() => {
checkbox.current.setCustomValidity(errorMessage);
}, []);

return (
<form class="custom-validity" onSubmit={handleSubmit}>
<SlCheckbox ref={checkbox} onSlChange={handleChange}>
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
- Added `--indicator-transition-duration` custom property to `<sl-progress-ring>` [#986](https://github.com/shoelace-style/shoelace/issues/986)
- 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 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)
- 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)
- Fixed a bug that caused prefix/suffix animations in `<sl-input>` to wobble [#996](https://github.com/shoelace-style/shoelace/issues/996)
Expand Down
10 changes: 10 additions & 0 deletions docs/resources/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,13 @@ Form controls should support submission and validation through the following con
- All form controls must have an `invalid` property that reflects their validity
- All form controls should mirror their native validation attributes such as `required`, `pattern`, `minlength`, `maxlength`, etc. when possible
- All form controls must be tested to work with the standard `<form>` element

### System Icons

Avoid inlining SVG icons inside of templates. If a component requires an icon, make sure `<sl-icon>` is a dependency of the component and use the [system library](/components/icon#customizing-the-system-library):

```html
<sl-icon library="system" name="..."></sl-icon>
```

This will render the icons instantly whereas the default library will fetch them from a remote source. If an icon isn't available in the system library, you will need to add it to `library.system.ts`. Using the system library ensures that all icons load instantly and are customizable by users who wish to provide a custom resolver for the system library.
8 changes: 1 addition & 7 deletions src/components/button/button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,13 +408,7 @@ export default css`
}
.button--caret .button__caret {
display: flex;
align-items: center;
}
.button--caret .button__caret svg {
width: 1em;
height: 1em;
height: auto;
}
/*
Expand Down
21 changes: 4 additions & 17 deletions src/components/button/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FormSubmitController } from '../../internal/form';
import ShoelaceElement from '../../internal/shoelace-element';
import { HasSlotController } from '../../internal/slot';
import { LocalizeController } from '../../utilities/localize';
import '../icon/icon';
import '../spinner/spinner';
import styles from './button.styles';
import type { CSSResultGroup } from 'lit';
Expand All @@ -16,6 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @since 2.0
* @status stable
*
* @dependency sl-icon
* @dependency sl-spinner
*
* @event sl-blur - Emitted when the button loses focus.
Expand All @@ -29,7 +31,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart prefix - The prefix slot's container.
* @csspart label - The button's label.
* @csspart suffix - The suffix slot's container.
* @csspart caret - The button's caret.
* @csspart caret - The button's caret icon.
*/
@customElement('sl-button')
export default class SlButton extends ShoelaceElement {
Expand Down Expand Up @@ -219,22 +221,7 @@ export default class SlButton extends ShoelaceElement {
<slot name="suffix"></slot>
</span>
${
this.caret
? html`
<span part="caret" class="button__caret">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</span>
`
: ''
this.caret ? html` <sl-icon part="caret" class="button__caret" library="system" name="caret"></sl-icon> ` : ''
}
${this.loading ? html`<sl-spinner></sl-spinner>` : ''}
</${tag}>
Expand Down
5 changes: 0 additions & 5 deletions src/components/checkbox/checkbox.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ export default css`
height: var(--sl-toggle-size);
}
.checkbox__control .checkbox__icon svg {
width: 100%;
height: 100%;
}
/* Hover */
.checkbox:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control:hover {
border-color: var(--sl-input-border-color-hover);
Expand Down
34 changes: 7 additions & 27 deletions src/components/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { defaultValue } from '../../internal/default-value';
import { FormSubmitController } from '../../internal/form';
import ShoelaceElement from '../../internal/shoelace-element';
import { watch } from '../../internal/watch';
import '../icon/icon';
import styles from './checkbox.styles';
import type { CSSResultGroup } from 'lit';

Expand All @@ -16,6 +17,8 @@ import type { CSSResultGroup } from 'lit';
* @since 2.0
* @status stable
*
* @dependency sl-icon
*
* @slot - The checkbox's label.
*
* @event sl-blur - Emitted when the control loses focus.
Expand All @@ -24,8 +27,8 @@ import type { CSSResultGroup } from 'lit';
*
* @csspart base - The component's internal wrapper.
* @csspart control - The checkbox control.
* @csspart checked-icon - The container the wraps the checked icon.
* @csspart indeterminate-icon - The container that wraps the indeterminate icon.
* @csspart checked-icon - The checked icon.
* @csspart indeterminate-icon - The indeterminate icon.
* @csspart label - The checkbox label.
*/
@customElement('sl-checkbox')
Expand Down Expand Up @@ -155,32 +158,9 @@ export default class SlCheckbox extends ShoelaceElement {
/>
<span part="control" class="checkbox__control">
${this.checked
? html`
<svg part="checked-icon" class="checkbox__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(3.428571, 3.428571)">
<path d="M0,5.71428571 L3.42857143,9.14285714"></path>
<path d="M9.14285714,0 L3.42857143,9.14285714"></path>
</g>
</g>
</g>
</svg>
`
: ''}
${this.checked ? html` <sl-icon part="checked-icon" library="system" name="check"></sl-icon> ` : ''}
${!this.checked && this.indeterminate
? html`
<svg part="indeterminate-icon" class="checkbox__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(2.285714, 6.857143)">
<path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path>
</g>
</g>
</g>
</svg>
`
? html` <sl-icon part="indeterminate-icon" library="system" name="indeterminate"></sl-icon> `
: ''}
</span>
Expand Down
6 changes: 2 additions & 4 deletions src/components/icon-button/icon-button.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('<sl-icon-button>', () => {
html`
<sl-icon-button
library="system"
name="check-lg"
name="check"
style="color: rgb(0, 136, 221); font-size: 2rem;"
></sl-icon-button>
`
Expand All @@ -48,9 +48,7 @@ describe('<sl-icon-button>', () => {

describe('when icon attributes are present', () => {
it('renders an sl-icon from a library', async () => {
const el = await fixture<SlIconButton>(
html` <sl-icon-button library="system" name="check-lg"></sl-icon-button> `
);
const el = await fixture<SlIconButton>(html` <sl-icon-button library="system" name="check"></sl-icon-button> `);
expect(el.shadowRoot?.querySelector('sl-icon')).to.exist;
});

Expand Down
43 changes: 40 additions & 3 deletions src/components/icon/library.system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ import type { IconLibrary } from './library';
// icons are a subset of Bootstrap Icons.
//
const icons = {
'check-lg': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-lg" viewBox="0 0 16 16">
<path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425a.247.247 0 0 1 .02-.022Z"></path>
caret: `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
`,
check: `
<svg part="checked-icon" class="checkbox__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(3.428571, 3.428571)">
<path d="M0,5.71428571 L3.42857143,9.14285714"></path>
<path d="M9.14285714,0 L3.42857143,9.14285714"></path>
</g>
</g>
</g>
</svg>
`,
'chevron-down': `
Expand Down Expand Up @@ -46,6 +58,22 @@ const icons = {
<path d="M13.354.646a1.207 1.207 0 0 0-1.708 0L8.5 3.793l-.646-.647a.5.5 0 1 0-.708.708L8.293 5l-7.147 7.146A.5.5 0 0 0 1 12.5v1.793l-.854.853a.5.5 0 1 0 .708.707L1.707 15H3.5a.5.5 0 0 0 .354-.146L11 7.707l1.146 1.147a.5.5 0 0 0 .708-.708l-.647-.646 3.147-3.146a1.207 1.207 0 0 0 0-1.708l-2-2zM2 12.707l7-7L10.293 7l-7 7H2v-1.293z"></path>
</svg>
`,
'grip-vertical': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-grip-vertical" viewBox="0 0 16 16">
<path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"></path>
</svg>
`,
indeterminate: `
<svg part="indeterminate-icon" class="checkbox__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(2.285714, 6.857143)">
<path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path>
</g>
</g>
</g>
</svg>
`,
'person-fill': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-fill" viewBox="0 0 16 16">
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
Expand All @@ -61,6 +89,15 @@ const icons = {
<path d="M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5zm5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5z"></path>
</svg>
`,
radio: `
<svg part="checked-icon" class="radio__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill="currentColor">
<circle cx="8" cy="8" r="3.42857143"></circle>
</g>
</g>
</svg>
`,
'star-fill': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/image-comparer/image-comparer.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default css`
background-color: var(--sl-color-neutral-0);
border-radius: var(--sl-border-radius-circle);
font-size: calc(var(--handle-size) * 0.5);
color: var(--sl-color-neutral-600);
color: var(--sl-color-neutral-700);
cursor: inherit;
z-index: 10;
}
Expand Down
9 changes: 2 additions & 7 deletions src/components/image-comparer/image-comparer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart after - The container that holds the "after" image.
* @csspart divider - The divider that separates the images.
* @csspart handle - The handle that the user drags to expose the after image.
* @csspart handle-icon - The drag icon that appears inside the handle.
*
* @cssproperty --divider-width - The width of the dividing line.
* @cssproperty --handle-size - The size of the compare handle.
Expand Down Expand Up @@ -143,13 +144,7 @@ export default class SlImageComparer extends ShoelaceElement {
tabindex="0"
>
<slot name="handle-icon">
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="currentColor" fill-rule="nonzero">
<path
d="m21.14 12.55-5.482 4.796c-.646.566-1.658.106-1.658-.753V7a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506h.001ZM2.341 12.55l5.482 4.796c.646.566 1.658.106 1.658-.753V7a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506h-.001Z"
/>
</g>
</svg>
<sl-icon part="handle-icon" library="system" name="grip-vertical"></sl-icon>
</slot>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/menu-item/menu-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type { CSSResultGroup } from 'lit';
* @slot suffix - Used to append an icon or similar element to the menu item.
*
* @csspart base - The component's internal wrapper.
* @csspart checked-icon - The checkmark's container, only visible when the menu item is checked.
* @csspart checked-icon - The checked icon, which is only visible when the menu item is checked.
* @csspart prefix - The prefix container.
* @csspart label - The menu item label.
* @csspart suffix - The suffix container.
Expand Down Expand Up @@ -93,7 +93,7 @@ export default class SlMenuItem extends ShoelaceElement {
})}
>
<span part="checked-icon" class="menu-item__check">
<sl-icon name="check-lg" library="system" aria-hidden="true"></sl-icon>
<sl-icon name="check" library="system" aria-hidden="true"></sl-icon>
</span>
<span part="prefix" class="menu-item__prefix">
Expand Down
13 changes: 5 additions & 8 deletions src/components/radio/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import ShoelaceElement from '../../internal/shoelace-element';
import { watch } from '../../internal/watch';
import '../icon/icon';
import styles from './radio.styles';
import type { CSSResultGroup } from 'lit';

Expand All @@ -12,6 +13,8 @@ import type { CSSResultGroup } from 'lit';
* @since 2.0
* @status stable
*
* @dependency sl-icon
*
* @slot - The radio's label.
*
* @event sl-blur - Emitted when the control loses focus.
Expand All @@ -20,7 +23,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's internal wrapper.
* @csspart control - The radio control.
* @csspart control--checked - The radio control if radio is checked.
* @csspart checked-icon - The container the wraps the checked icon.
* @csspart checked-icon - The checked icon.
* @csspart label - The radio label.
*/
@customElement('sl-radio')
Expand Down Expand Up @@ -93,13 +96,7 @@ export default class SlRadio extends ShoelaceElement {
})}
>
<span part="${`control${this.checked ? ' control--checked' : ''}`}" class="radio__control">
<svg part="checked-icon" class="radio__icon" viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill="currentColor">
<circle cx="8" cy="8" r="3.42857143"></circle>
</g>
</g>
</svg>
${this.checked ? html` <sl-icon part="checked-icon" library="system" name="radio"></sl-icon> ` : ''}
</span>
<span part="label" class="radio__label">
Expand Down

0 comments on commit f64f144

Please sign in to comment.