pull/853/head
Cory LaViska 2022-08-10 11:01:13 -04:00
rodzic 4b9e35313d
commit a8e8325ea7
9 zmienionych plików z 83 dodań i 80 usunięć

Wyświetl plik

@ -6,7 +6,7 @@ Popup is a utility that lets you declaratively anchor "popup" containers to anot
This component's name is inspired by [`<popup>`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md). It uses [Floating UI](https://floating-ui.com/) under the hood to provide a well-tested, lightweight, and fully declarative positioning utility for tooltips, dropdowns, and more.
The popup's preferred placement, distance, and skidding (offset) can be configured using attributes. An arrow that points to the anchor can be shown and customized to your liking. Additional positioning options are available and described in more detail below.
Popup doesn't provide any styles — just positioning! The popup's preferred placement, distance, and skidding (offset) can be configured using attributes. An arrow that points to the anchor can be shown and customized to your liking. Additional positioning options are available and described in more detail below.
```html preview
<div class="popup-overview">
@ -215,7 +215,7 @@ const App = () => {
};
```
?> A popup's anchor should never be styled with `display: contents` since the coordinates will not be eligible for calculation. However, if the anchor is a `<slot>` element, popup will use the first assigned element as the anchor. This behavior allows other components to pass anchors through more easily via composition.
?> A popup's anchor should not be styled with `display: contents` since the coordinates will not be eligible for calculation. However, if the anchor is a `<slot>` element, popup will use the first assigned element as the anchor. This behavior allows other components to pass anchors through more easily via composition.
## Examples
@ -1029,16 +1029,16 @@ const App = () => {
### Auto-size
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from overflowing. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option.
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from getting clipped. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
For best results, set a preferred width/height on the `popup` part and set `width: 100%; height: 100%;` on your content's wrapper. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
When using auto-size, two read-only custom properties called `--auto-size-available-width` and `--auto-size-available-height` will be applied to the host element. These values determine the available space the popover has before clipping will occur. Since they cascade, you can use them to set a max-width/height on your popup's content and easily control its overflow.
Scroll the container to see auto-size in action.
Scroll the container to see the popup resize as its available space changes.
```html preview
<div class="popup-auto-size">
<div class="overflow">
<sl-popup placement="bottom" auto-size active>
<sl-popup placement="top" auto-size active>
<span slot="anchor"></span>
<div class="box"></div>
</sl-popup>
@ -1061,19 +1061,21 @@ Scroll the container to see auto-size in action.
width: 150px;
height: 150px;
border: dashed 2px var(--sl-color-neutral-600);
margin: 100px 50px 250px 50px;
}
.popup-auto-size sl-popup::part(popup) {
width: 100px;
height: 200px;
margin: 250px 50px 100px 50px;
}
.popup-auto-size .box {
width: 100%;
height: 100%;
background: var(--sl-color-primary-600);
border-radius: var(--sl-border-radius-medium);
/* This sets the preferred size of the popup's content */
width: 100px;
height: 200px;
/* This sets the maximum dimensions and allows scrolling when auto-size kicks in */
max-width: var(--auto-size-available-width);
max-height: var(--auto-size-available-height);
overflow: auto;
}
</style>
@ -1103,19 +1105,21 @@ const css = `
width: 150px;
height: 150px;
border: dashed 2px var(--sl-color-neutral-600);
margin: 100px 50px 250px 50px;
}
.popup-auto-size sl-popup::part(popup) {
width: 100px;
height: 200px;
margin: 250px 50px 100px 50px;
}
.popup-auto-size .box {
width: 100%;
height: 100%;
background: var(--sl-color-primary-600);
border-radius: var(--sl-border-radius-medium);
/* This sets the preferred size of the popup's content */
width: 100px;
height: 200px;
/* This sets the maximum dimensions and allows scrolling when auto-size kicks in */
max-width: var(--auto-size-available-width);
max-height: var(--auto-size-available-height);
overflow: auto;
}
`;
@ -1126,7 +1130,7 @@ const App = () => {
<>
<div className="popup-auto-size">
<div className="overflow">
<SlPopup placement="bottom" auto-size={autoSize || null} auto-size-padding="10" active>
<SlPopup placement="top" auto-size={autoSize || null} auto-size-padding="10" active>
<span slot="anchor" />
<div className="box" />
</SlPopup>

Wyświetl plik

@ -8,6 +8,13 @@ New versions of Shoelace are released as-needed and generally occur when a criti
_During the beta period, these restrictions may be relaxed in the event of a mission-critical bug._ 🐛
## Next
- 🚨 BREAKING: removed the `base` part from `<sl-menu>` and removed an unnecessary `<div>` that made styling more difficult
- Added read-only custom properties `--auto-size-available-width` and `--auto-size-available-height` to `<sl-popup>` to improve support for overflowing popup content
- Fixed a bug where auto-size wasn't being applied to `<sl-dropdown>` and `<sl-select>`
- Fixed a bug in `<sl-popup>` that caused auto-size to kick in before flip
## 2.0.0-beta.80
This release breaks radio buttons, which is something that needed to happen to solve a longstanding accessibility issue where screen readers announced an incorrect number of radios, e.g. "1 of 1" instead of "1 of 3." Many attempts to solve this without breaking the existing API were made, but none worked across the board. The new implementation upgrades `<sl-radio-group>` to serve as the "form control" while `<sl-radio>` and `<sl-radio-button>` serve as options within the form control.

Wyświetl plik

@ -38,12 +38,16 @@ export default css`
font-weight: var(--sl-font-weight-normal);
color: var(--color);
box-shadow: var(--sl-shadow-large);
overflow: auto;
overscroll-behavior: none;
pointer-events: none;
}
.dropdown--open .dropdown__panel {
pointer-events: all;
}
/* When users slot a menu, make sure it conforms to the popup's auto-size */
::slotted(sl-menu) {
max-width: var(--auto-size-available-width) !important;
max-height: var(--auto-size-available-height) !important;
}
`;

Wyświetl plik

@ -396,6 +396,8 @@ export default class SlDropdown extends LitElement {
strategy=${this.hoist ? 'fixed' : 'absolute'}
flip
shift
auto-size
auto-size-padding="10"
class=${classMap({
dropdown: true,
'dropdown--open': this.open

Wyświetl plik

@ -6,13 +6,13 @@ export default css`
:host {
display: block;
}
.menu {
position: relative;
background: var(--sl-panel-background-color);
border: solid var(--sl-panel-border-width) var(--sl-panel-border-color);
border-radius: var(--sl-border-radius-medium);
padding: var(--sl-spacing-x-small) 0;
overflow: auto;
overscroll-behavior: none;
}
::slotted(sl-divider) {

Wyświetl plik

@ -16,14 +16,11 @@ export interface MenuSelectEventDetail {
* @slot - The menu's content, including menu items, menu labels, and dividers.
*
* @event {{ item: SlMenuItem }} sl-select - Emitted when a menu item is selected.
*
* @csspart base - The component's internal wrapper.
*/
@customElement('sl-menu')
export default class SlMenu extends LitElement {
static styles: CSSResultGroup = styles;
@query('.menu') menu: HTMLElement;
@query('slot') defaultSlot: HTMLSlotElement;
private typeToSelectString = '';
@ -183,15 +180,12 @@ export default class SlMenu extends LitElement {
render() {
return html`
<div
part="base"
class="menu"
<slot
@slotchange=${this.handleSlotChange}
@click=${this.handleClick}
@keydown=${this.handleKeyDown}
@mousedown=${this.handleMouseDown}
>
<slot @slotchange=${this.handleSlotChange}></slot>
</div>
></slot>
`;
}
}

Wyświetl plik

@ -14,6 +14,8 @@ export default css`
.popup {
position: absolute;
isolation: isolate;
max-width: var(--auto-size-available-width, none);
max-height: var(--auto-size-available-height, none);
}
.popup--fixed {

Wyświetl plik

@ -21,8 +21,15 @@ import type { CSSResultGroup } from 'lit';
* maybe a border or box shadow.
* @csspart popup - The popup's container. Useful for setting a background color, box shadow, etc.
*
* @cssproperty [--arrow-size=4px] - The size of the arrow. Note that an arrow won't be shown unless the `arrow` attribute is used.
* @cssproperty [--arrow-size=4px] - The size of the arrow. Note that an arrow won't be shown unless the `arrow`
* attribute is used.
* @cssproperty [--arrow-color=var(--sl-color-neutral-0)] - The color of the arrow.
* @cssproperty [--auto-size-available-width] - A read-only custom property that determines the amount of width the
* popup can be before overflowing. Useful for positioning child elements that need to overflow. This property is only
* available when using `auto-size`.
* @cssproperty [--auto-size-available-height] - A read-only custom property that determines the amount of height the
* popup can be before overflowing. Useful for positioning child elements that need to overflow. This property is only
* available when using `auto-size`.
*/
@customElement('sl-popup')
export default class SlPopup extends LitElement {
@ -127,11 +134,7 @@ export default class SlPopup extends LitElement {
@property({ type: Object }) flipBoundary: Element | Element[];
/** The amount of padding, in pixels, to exceed before the flip behavior will occur. */
@property({
attribute: 'flip-padding',
type: Number
})
flipPadding = 0;
@property({ attribute: 'flip-padding', type: Number }) flipPadding = 0;
/** Moves the popup along the axis to keep it in view when clipped. */
@property({ type: Boolean }) shift = false;
@ -144,11 +147,7 @@ export default class SlPopup extends LitElement {
@property({ type: Object }) shiftBoundary: Element | Element[];
/** The amount of padding, in pixels, to exceed before the shift behavior will occur. */
@property({
attribute: 'shift-padding',
type: Number
})
shiftPadding = 0;
@property({ attribute: 'shift-padding', type: Number }) shiftPadding = 0;
/** When set, this will cause the popup to automatically resize itself to prevent it from overflowing. */
@property({ attribute: 'auto-size', type: Boolean }) autoSize = false;
@ -161,11 +160,7 @@ export default class SlPopup extends LitElement {
@property({ type: Object }) autoSizeBoundary: Element | Element[];
/** The amount of padding, in pixels, to exceed before the auto-size behavior will occur. */
@property({
attribute: 'auto-size-padding',
type: Number
})
autoSizePadding = 0;
@property({ attribute: 'auto-size-padding', type: Number }) autoSizePadding = 0;
async connectedCallback() {
super.connectedCallback();
@ -214,6 +209,8 @@ export default class SlPopup extends LitElement {
this.cleanup();
this.cleanup = undefined;
this.removeAttribute('data-current-placement');
this.style.removeProperty('--auto-size-available-width');
this.style.removeProperty('--auto-size-available-height');
requestAnimationFrame(() => resolve());
} else {
resolve();
@ -255,27 +252,7 @@ export default class SlPopup extends LitElement {
offset({ mainAxis: this.distance, crossAxis: this.skidding })
];
// First, we adjust the size as needed
if (this.autoSize) {
middleware.push(
size({
boundary: this.autoSizeBoundary,
padding: this.autoSizePadding,
apply: ({ availableWidth, availableHeight }) => {
// Ensure the panel stays within the viewport when we have lots of menu items
Object.assign(this.popup.style, {
maxWidth: `${availableWidth}px`,
maxHeight: `${availableHeight}px`
});
}
})
);
} else {
// Unset max-width/max-height when we're no longer using this middleware
Object.assign(this.popup.style, { maxWidth: '', maxHeight: '' });
}
// Then we flip, as needed
// First we flip
if (this.flip) {
middleware.push(
flip({
@ -288,7 +265,7 @@ export default class SlPopup extends LitElement {
);
}
// Then we shift, as needed
// Then we shift
if (this.shift) {
middleware.push(
shift({
@ -298,6 +275,24 @@ export default class SlPopup extends LitElement {
);
}
// Now we adjust the size as needed
if (this.autoSize) {
middleware.push(
size({
boundary: this.autoSizeBoundary,
padding: this.autoSizePadding,
apply: ({ availableWidth, availableHeight }) => {
this.style.setProperty('--auto-size-available-width', `${availableWidth}px`);
this.style.setProperty('--auto-size-available-height', `${availableHeight}px`);
}
})
);
} else {
// Cleanup styles if we're no longer using auto-size
this.style.removeProperty('--auto-size-available-width');
this.style.removeProperty('--auto-size-available-height');
}
// Finally, we add an arrow
if (this.arrow) {
middleware.push(

Wyświetl plik

@ -33,11 +33,6 @@ export default css`
cursor: pointer;
}
.select__menu {
max-height: 50vh;
overflow: auto;
}
.select__menu::part(base) {
border: none;
}