This commit is contained in:
Cory LaViska
2022-08-19 09:17:44 -04:00
parent c8f42c5bde
commit f0a3972ef6
3 changed files with 129 additions and 1 deletions

View File

@@ -770,6 +770,112 @@ const App = () => {
};
```
### Syncing with the Anchor's Dimensions
Use the `sync` attribute to make the popup the same width or height as the anchor element. This is useful for controls that need the popup to stay the same width or height as the trigger.
```html preview
<div class="popup-match">
<sl-popup placement="top" sync="width" active>
<span slot="anchor"></span>
<div class="box"></div>
</sl-popup>
<sl-select value="width" label="Sync">
<sl-menu-item value="width">Width</sl-menu-item>
<sl-menu-item value="height">Height</sl-menu-item>
<sl-menu-item value="both">Both</sl-menu-item>
<sl-menu-item value="">None</sl-menu-item>
</sl-select>
</div>
<style>
.popup-match span[slot='anchor'] {
display: inline-block;
width: 150px;
height: 150px;
border: dashed 2px var(--sl-color-neutral-600);
margin: 50px;
}
.popup-match .box {
width: 100%;
height: 100%;
min-width: 50px;
min-height: 50px;
background: var(--sl-color-primary-600);
border-radius: var(--sl-border-radius-medium);
}
.popup-match sl-switch {
margin-top: 1rem;
}
</style>
<script>
const container = document.querySelector('.popup-match');
const popup = container.querySelector('sl-popup');
const fixed = container.querySelector('sl-switch');
const sync = container.querySelector('sl-select');
sync.addEventListener('sl-change', () => (popup.sync = sync.value));
</script>
```
```jsx react
import { useState } from 'react';
import { SlPopup, SlSelect, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
const css = `
.popup-match span[slot='anchor'] {
display: inline-block;
width: 150px;
height: 150px;
border: dashed 2px var(--sl-color-neutral-600);
margin: 50px;
}
.popup-match .box {
width: 100%;
height: 100%;
min-width: 50px;
min-height: 50px;
background: var(--sl-color-primary-600);
border-radius: var(--sl-border-radius-medium);
}
.popup-match sl-switch {
margin-top: 1rem;
}
`;
const App = () => {
const [sync, setSync] = useState('width');
return (
<>
<div class="popup-match">
<SlPopup placement="top" sync={sync} active>
<span slot="anchor" />
<div class="box" />
</SlPopup>
<SlSelect value={sync} label="Sync" onSlChange={event => setSync(event.target.value)}>
<SlMenuItem value="width">Width</SlMenuItem>
<SlMenuItem value="height">Height</SlMenuItem>
<SlMenuItem value="both">Both</SlMenuItem>
<SlMenuItem value="">None</SlMenuItem>
</SlSelect>
{sync}
</div>
<style>{css}</style>
</>
);
};
```
### Positioning Strategy
By default, the popup is positioned using an absolute positioning strategy. However, if your anchor is fixed or exists within a container that has `overflow: auto|hidden`, the popup risks being clipped. To work around this, you can use a fixed positioning strategy by setting the `strategy` attribute to `fixed`.

View File

@@ -10,6 +10,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
## Next
- Added the `sync` attribute to `<sl-popup>`
- Fixed a bug in `<sl-tree>` where dynamically changing slotted items wouldn't update the tree properly
- Fixed a bug in `<sl-split-panel>` that caused the panel to stack when clicking on the divider in mobile versions of Chrome [#862](https://github.com/shoelace-style/shoelace/issues/862)
- Improved single selection in `<sl-tree>` so nodes expand and collapse and receive selection when clicking on the label

View File

@@ -160,6 +160,9 @@ export default class SlPopup extends ShoelaceElement {
/** When set, this will cause the popup to automatically resize itself to prevent it from overflowing. */
@property({ attribute: 'auto-size', type: Boolean }) autoSize = false;
/** Syncs the popup's width or height to that of the anchor element. */
@property() sync: 'width' | 'height' | 'both';
/**
* The auto-size boundary describes clipping element(s) that overflow will be checked relative to when resizing. By
* default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can
@@ -277,7 +280,25 @@ export default class SlPopup extends ShoelaceElement {
offset({ mainAxis: this.distance, crossAxis: this.skidding })
];
// First we flip
// First we sync width/height
if (this.sync) {
middleware.push(
size({
apply: ({ rects }) => {
const syncWidth = this.sync === 'width' || this.sync === 'both';
const syncHeight = this.sync === 'height' || this.sync === 'both';
this.popup.style.width = syncWidth ? `${rects.reference.width}px` : '';
this.popup.style.height = syncHeight ? `${rects.reference.height}px` : '';
}
})
);
} else {
// Cleanup styles if we're not matching width/height
this.popup.style.width = '';
this.popup.style.height = '';
}
// Then we flip
if (this.flip) {
middleware.push(
flip({