kopia lustrzana https://github.com/shoelace-style/shoelace
fix popup
rodzic
4b9e35313d
commit
a8e8325ea7
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -33,11 +33,6 @@ export default css`
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select__menu {
|
||||
max-height: 50vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.select__menu::part(base) {
|
||||
border: none;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue