Skip to content

Commit

Permalink
feat: Syncs Shoelace next branch
Browse files Browse the repository at this point in the history
  • Loading branch information
jeysonj2 committed Aug 4, 2023
1 parent 5e50390 commit 0999b51
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 25 deletions.
6 changes: 0 additions & 6 deletions docs/assets/styles/docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -1213,12 +1213,6 @@ html.sidebar-open #menu-toggle {
vertical-align: -2px;
}

.splash li img {
width: 1em;
height: 1em;
vertical-align: -2px;
}

.splash-end {
display: flex;
align-items: flex-end;
Expand Down
175 changes: 175 additions & 0 deletions docs/pages/components/popup.md
Original file line number Diff line number Diff line change
Expand Up @@ -1686,3 +1686,178 @@ const App = () => {
);
};
```

### Virtual Elements

In most cases, popups are anchored to an actual element. Sometimes, it can be useful to anchor them to a non-element. To do this, you can pass a `VirtualElement` to the anchor property. A virtual element must contain a function called `getBoundingClientRect()` that returns a [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect) object as shown below.

```ts
const virtualElement = {
getBoundingClientRect() {
// ...
return { width, height, x, y, top, left, right, bottom };
}
};
```

This example anchors a popup to the mouse cursor using a virtual element. As such, a mouse is required to properly view it.

```html:preview
<div class="popup-virtual-element">
<o-popup placement="right-start">
<div class="circle"></div>
</o-popup>
<o-switch>Highlight mouse cursor</o-switch>
</div>
<script>
const container = document.querySelector('.popup-virtual-element');
const popup = container.querySelector('o-popup');
const circle = container.querySelector('.circle');
const enabled = container.querySelector('o-switch');
let clientX = 0;
let clientY = 0;
// Set the virtual element as a property
popup.anchor = {
getBoundingClientRect() {
return {
width: 0,
height: 0,
x: clientX,
y: clientY,
top: clientY,
left: clientX,
right: clientX,
bottom: clientY
};
}
};
// Only activate the popup when the switch is checked
enabled.addEventListener('o-change', () => {
popup.active = enabled.checked;
});
// Listen for the mouse to move
document.addEventListener('mousemove', handleMouseMove);
// Update the virtual element as the mouse moves
function handleMouseMove(event) {
clientX = event.clientX;
clientY = event.clientY;
// Reposition the popup when the virtual anchor moves
if (popup.active) {
popup.reposition();
}
}
</script>
<style>
/* If you need to set a z-index, set it on the popup part like this */
.popup-virtual-element o-popup::part(popup) {
z-index: 1000;
pointer-events: none;
}
.popup-virtual-element .circle {
width: 100px;
height: 100px;
border: solid 4px var(--o-color-primary-600);
border-radius: 50%;
translate: -50px -50px;
animation: 1s virtual-cursor infinite;
}
@keyframes virtual-cursor {
0% { scale: 1; }
50% { scale: 1.1; }
}
</style>
```

```jsx:react
import { useRef, useState } from 'react';
import { OPopup, OSwitch } from '@shoelace-style/shoelace/dist/react';
const css = `
/* If you need to set a z-index, set it on the popup part like this */
.popup-virtual-element o-popup::part(popup) {
z-index: 1000;
pointer-events: none;
}
.popup-virtual-element .circle {
width: 100px;
height: 100px;
border: solid 4px var(--o-color-primary-600);
border-radius: 50%;
translate: -50px -50px;
animation: 1s virtual-cursor infinite;
}
@keyframes virtual-cursor {
0% { scale: 1; }
50% { scale: 1.1; }
}
`;
const App = () => {
const [enabled, setEnabled] = useState(false);
const [clientX, setClientX] = useState(0);
const [clientY, setClientY] = useState(0);
const popup = useRef(null);
const circle = useRef(null);
const virtualElement = {
getBoundingClientRect() {
return {
width: 0,
height: 0,
x: clientX,
y: clientY,
top: clientY,
left: clientX,
right: clientX,
bottom: clientY
};
}
};
// Listen for the mouse to move
document.addEventListener('mousemove', handleMouseMove);
// Update the virtual element as the mouse moves
function handleMouseMove(event) {
setClientX(event.clientX);
setClientY(event.clientY);
// Reposition the popup when the virtual anchor moves
if (popup.active) {
popup.current.reposition();
}
}
return (
<>
<div className="popup-virtual-element">
<OPopup
ref={popup}
placement="right-start"
active={enabled}
anchor={virtualElement}
>
<div ref={circle} className="circle" />
</OPopup>
<OSwitch checked={enabled} onOChange={event => setEnabled(event.target.checked)}>
Highlight mouse cursor
</OSwitch>
</div>
<style>{css}</style>
</>
);
};
```
19 changes: 0 additions & 19 deletions docs/pages/frameworks/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,6 @@ function MyComponent() {
export default MyComponent;
```

You can also import the event type for use in your callbacks, shown below.

```tsx
import { useCallback, useState } from 'react';
import { OInput, OInputEvent } from 'O-PACKAGE-FULL-NAME-O/%NPMDIR%/react';
import type OInputElement from 'O-PACKAGE-FULL-NAME-O/%NPMDIR%/components/input/input';

function MyComponent() {
const [value, setValue] = useState('');
const onInput = useCallback((event: OInputEvent) => {
setValue(event.detail);
}, []);

return <OInput value={value} onOInput={event => setValue((event.target as OInputElement).value)} />;
}

export default MyComponent;
```

## Testing with Jest

Testing with web components can be challenging if your test environment runs in a Node environment (i.e. it doesn't run in a real browser). Fortunately, [Jest](https://jestjs.io/) has made a number of strides to support web components and provide additional browser APIs. However, it's still not a complete replication of a browser environment.
Expand Down

0 comments on commit 0999b51

Please sign in to comment.