kopia lustrzana https://github.com/shoelace-style/shoelace
add arrow-placement
rodzic
81d393fbc1
commit
098db9c3fa
|
@ -681,15 +681,41 @@ const App = () => {
|
||||||
|
|
||||||
Add an arrow to your popup with the `arrow` attribute. It's usually a good idea to set a `distance` to make room for the arrow. To adjust the arrow's color and size, use the `--arrow-color` and `--arrow-size` custom properties, respectively. You can also target the `arrow` part to add additional styles such as shadows and borders.
|
Add an arrow to your popup with the `arrow` attribute. It's usually a good idea to set a `distance` to make room for the arrow. To adjust the arrow's color and size, use the `--arrow-color` and `--arrow-size` custom properties, respectively. You can also target the `arrow` part to add additional styles such as shadows and borders.
|
||||||
|
|
||||||
|
By default, the arrow will be aligned as close to the center of the _anchor_ as possible, considering available space and `arrow-padding`. You can use the `arrow-placement` attribute to force the arrow to align to the start, end, or center of the _popup_ instead.
|
||||||
|
|
||||||
```html preview
|
```html preview
|
||||||
<div class="popup-arrow">
|
<div class="popup-arrow">
|
||||||
<sl-popup placement="top" arrow distance="8" active>
|
<sl-popup placement="top" arrow arrow-placement="anchor" distance="8" active>
|
||||||
<span slot="anchor"></span>
|
<span slot="anchor"></span>
|
||||||
<div class="box"></div>
|
<div class="box"></div>
|
||||||
</sl-popup>
|
</sl-popup>
|
||||||
|
|
||||||
<br />
|
<div class="popup-arrow-options">
|
||||||
<sl-switch checked>Arrow</sl-switch>
|
<sl-select label="Placement" name="placement" value="top" class="popup-overview-select">
|
||||||
|
<sl-menu-item value="top">top</sl-menu-item>
|
||||||
|
<sl-menu-item value="top-start">top-start</sl-menu-item>
|
||||||
|
<sl-menu-item value="top-end">top-end</sl-menu-item>
|
||||||
|
<sl-menu-item value="bottom">bottom</sl-menu-item>
|
||||||
|
<sl-menu-item value="bottom-start">bottom-start</sl-menu-item>
|
||||||
|
<sl-menu-item value="bottom-end">bottom-end</sl-menu-item>
|
||||||
|
<sl-menu-item value="right">right</sl-menu-item>
|
||||||
|
<sl-menu-item value="right-start">right-start</sl-menu-item>
|
||||||
|
<sl-menu-item value="right-end">right-end</sl-menu-item>
|
||||||
|
<sl-menu-item value="left">left</sl-menu-item>
|
||||||
|
<sl-menu-item value="left-start">left-start</sl-menu-item>
|
||||||
|
<sl-menu-item value="left-end">left-end</sl-menu-item>
|
||||||
|
</sl-select>
|
||||||
|
|
||||||
|
<sl-select label="Arrow Placement" name="arrow-placement" value="anchor">
|
||||||
|
<sl-menu-item value="anchor">anchor</sl-menu-item>
|
||||||
|
<sl-menu-item value="start">start</sl-menu-item>
|
||||||
|
<sl-menu-item value="end">end</sl-menu-item>
|
||||||
|
<sl-menu-item value="center">center</sl-menu-item>
|
||||||
|
</sl-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="popup-arrow-options">
|
||||||
|
<sl-switch name="arrow" checked>Arrow</sl-switch>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -711,20 +737,40 @@ Add an arrow to your popup with the `arrow` attribute. It's usually a good idea
|
||||||
background: var(--sl-color-primary-600);
|
background: var(--sl-color-primary-600);
|
||||||
border-radius: var(--sl-border-radius-medium);
|
border-radius: var(--sl-border-radius-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: end;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options sl-select {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options + .popup-arrow-options {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const container = document.querySelector('.popup-arrow');
|
const container = document.querySelector('.popup-arrow');
|
||||||
const popup = container.querySelector('sl-popup');
|
const popup = container.querySelector('sl-popup');
|
||||||
const arrow = container.querySelector('sl-switch');
|
const placement = container.querySelector('[name="placement"]');
|
||||||
|
const arrowPlacement = container.querySelector('[name="arrow-placement"]');
|
||||||
|
const arrow = container.querySelector('[name="arrow"]');
|
||||||
|
|
||||||
|
placement.addEventListener('sl-change', () => (popup.placement = placement.value));
|
||||||
|
arrowPlacement.addEventListener('sl-change', () => (popup.arrowPlacement = arrowPlacement.value));
|
||||||
arrow.addEventListener('sl-change', () => (popup.arrow = arrow.checked));
|
arrow.addEventListener('sl-change', () => (popup.arrow = arrow.checked));
|
||||||
</script>
|
</script>
|
||||||
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx react
|
```jsx react
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { SlPopup, SlSwitch } from '@shoelace-style/shoelace/dist/react';
|
import { SlPopup, SlSelect, SlMenuItem, SlSwitch } from '@shoelace-style/shoelace/dist/react';
|
||||||
|
|
||||||
const css = `
|
const css = `
|
||||||
.popup-arrow sl-popup {
|
.popup-arrow sl-popup {
|
||||||
|
@ -745,24 +791,77 @@ const css = `
|
||||||
background: var(--sl-color-primary-600);
|
background: var(--sl-color-primary-600);
|
||||||
border-radius: var(--sl-border-radius-medium);
|
border-radius: var(--sl-border-radius-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: end;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options sl-select {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-arrow-options + .popup-arrow-options {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
const [placement, setPlacement] = useState('top');
|
||||||
|
const [arrowPlacement, setArrowPlacement] = useState('anchor');
|
||||||
const [arrow, setArrow] = useState(true);
|
const [arrow, setArrow] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="popup-arrow">
|
<div className="popup-arrow">
|
||||||
<SlPopup placement="top" arrow={arrow} distance="8" active>
|
<SlPopup placement={placement} arrow={arrow || null} arrow-placement={arrowPlacement} distance="8" active>
|
||||||
<span slot="anchor" />
|
<span slot="anchor" />
|
||||||
<div className="box" />
|
<div className="box" />
|
||||||
</SlPopup>
|
</SlPopup>
|
||||||
|
|
||||||
<br />
|
<div className="popup-arrow-options">
|
||||||
<SlSwitch checked={arrow} onSlChange={event => setArrow(event.target.checked)}>
|
<SlSelect
|
||||||
|
label="Placement"
|
||||||
|
name="placement"
|
||||||
|
value={placement}
|
||||||
|
className="popup-overview-select"
|
||||||
|
onSlChange={event => setPlacement(event.target.value)}
|
||||||
|
>
|
||||||
|
<SlMenuItem value="top">top</SlMenuItem>
|
||||||
|
<SlMenuItem value="top-start">top-start</SlMenuItem>
|
||||||
|
<SlMenuItem value="top-end">top-end</SlMenuItem>
|
||||||
|
<SlMenuItem value="bottom">bottom</SlMenuItem>
|
||||||
|
<SlMenuItem value="bottom-start">bottom-start</SlMenuItem>
|
||||||
|
<SlMenuItem value="bottom-end">bottom-end</SlMenuItem>
|
||||||
|
<SlMenuItem value="right">right</SlMenuItem>
|
||||||
|
<SlMenuItem value="right-start">right-start</SlMenuItem>
|
||||||
|
<SlMenuItem value="right-end">right-end</SlMenuItem>
|
||||||
|
<SlMenuItem value="left">left</SlMenuItem>
|
||||||
|
<SlMenuItem value="left-start">left-start</SlMenuItem>
|
||||||
|
<SlMenuItem value="left-end">left-end</SlMenuItem>
|
||||||
|
</SlSelect>
|
||||||
|
|
||||||
|
<SlSelect
|
||||||
|
label="Arrow Placement"
|
||||||
|
name="arrow-placement"
|
||||||
|
value={arrowPlacement}
|
||||||
|
onSlChange={event => setArrowPlacement(event.target.value)}
|
||||||
|
>
|
||||||
|
<SlMenuItem value="anchor">anchor</SlMenuItem>
|
||||||
|
<SlMenuItem value="start">start</SlMenuItem>
|
||||||
|
<SlMenuItem value="end">end</SlMenuItem>
|
||||||
|
<SlMenuItem value="center">center</SlMenuItem>
|
||||||
|
</SlSelect>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="popup-arrow-options">
|
||||||
|
<SlSwitch name="arrow" checked={arrow} onSlChange={event => setArrow(event.target.checked)}>
|
||||||
Arrow
|
Arrow
|
||||||
</SlSwitch>
|
</SlSwitch>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>{css}</style>
|
<style>{css}</style>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -10,7 +10,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
- Added the `sync` attribute to `<sl-popup>`
|
- Added the `sync` and `arrow-placement` attributes to `<sl-popup>`
|
||||||
- Changed the `auto-size` attribute of the experimental `<sl-popup>` component so it accepts `horizontal`, `vertical`, and `both` instead of a boolean value
|
- Changed the `auto-size` attribute of the experimental `<sl-popup>` component so it accepts `horizontal`, `vertical`, and `both` instead of a boolean value
|
||||||
- Changed the `flip-fallback-placement` attribute of the experimental `<sl-popup>` component to `flip-fallback-placements`
|
- Changed the `flip-fallback-placement` attribute of the experimental `<sl-popup>` component to `flip-fallback-placements`
|
||||||
- Changed the `flip-fallback-strategy` in the experimental `<sl-popup>` component to accept `best-fit` and `initial` instead of `bestFit` and `initialPlacement`
|
- Changed the `flip-fallback-strategy` in the experimental `<sl-popup>` component to accept `best-fit` and `initial` instead of `bestFit` and `initialPlacement`
|
||||||
|
|
|
@ -93,6 +93,13 @@ export default class SlPopup extends ShoelaceElement {
|
||||||
*/
|
*/
|
||||||
@property({ type: Boolean }) arrow = false;
|
@property({ type: Boolean }) arrow = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The placement of the arrow. The default is `anchor`, which will align the arrow as close to the center of the
|
||||||
|
* anchor as possible, considering available space and `arrow-padding`. A value of `start`, `end`, or `center` will
|
||||||
|
* align the arrow to the start, end, or center of the popover instead.
|
||||||
|
*/
|
||||||
|
@property({ attribute: 'arrow-placement' }) arrowPlacement: 'start' | 'end' | 'center' | 'anchor' = 'anchor';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of padding between the arrow and the edges of the popup. If the popup has a border-radius, for example,
|
* The amount of padding between the arrow and the edges of the popup. If the popup has a border-radius, for example,
|
||||||
* this will prevent it from overflowing the corners.
|
* this will prevent it from overflowing the corners.
|
||||||
|
@ -372,14 +379,36 @@ export default class SlPopup extends ShoelaceElement {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.arrow) {
|
if (this.arrow) {
|
||||||
const arrowX = middlewareData.arrow?.x;
|
const arrowX = middlewareData.arrow!.x;
|
||||||
const arrowY = middlewareData.arrow?.y;
|
const arrowY = middlewareData.arrow!.y;
|
||||||
|
let top = '';
|
||||||
|
let right = '';
|
||||||
|
let bottom = '';
|
||||||
|
let left = '';
|
||||||
|
|
||||||
|
if (this.arrowPlacement === 'start') {
|
||||||
|
// Start
|
||||||
|
left = typeof arrowX === 'number' ? `${this.arrowPadding}px` : '';
|
||||||
|
top = typeof arrowY === 'number' ? `${this.arrowPadding}px` : '';
|
||||||
|
} else if (this.arrowPlacement === 'end') {
|
||||||
|
// End
|
||||||
|
right = typeof arrowX === 'number' ? `${this.arrowPadding}px` : '';
|
||||||
|
bottom = typeof arrowY === 'number' ? `${this.arrowPadding}px` : '';
|
||||||
|
} else if (this.arrowPlacement === 'center') {
|
||||||
|
// Center
|
||||||
|
left = typeof arrowX === 'number' ? `calc(50% - var(--arrow-size))` : '';
|
||||||
|
top = typeof arrowY === 'number' ? `calc(50% - var(--arrow-size))` : '';
|
||||||
|
} else {
|
||||||
|
// Anchor (default)
|
||||||
|
left = typeof arrowX === 'number' ? `${arrowX}px` : '';
|
||||||
|
top = typeof arrowY === 'number' ? `${arrowY}px` : '';
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(this.arrowEl.style, {
|
Object.assign(this.arrowEl.style, {
|
||||||
left: typeof arrowX === 'number' ? `${arrowX}px` : '',
|
top,
|
||||||
top: typeof arrowY === 'number' ? `${arrowY}px` : '',
|
right,
|
||||||
right: '',
|
bottom,
|
||||||
bottom: '',
|
left,
|
||||||
[staticSide]: 'calc(var(--arrow-size) * -1)'
|
[staticSide]: 'calc(var(--arrow-size) * -1)'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue