-
-
Notifications
You must be signed in to change notification settings - Fork 332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integration: Floating UI React/Svelte (Popups) #1916
Comments
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Suggestion/Feature Request, possibly expanding on An example to provide some context: Imagine you have a list of items (i.e. an
From a developer UX perspective, it would be nice to use popups in this context along the lines of <script>
const settings: PopupSettings = { ... }
</script>
{#each fruits as fruit}
{fruit.name} - <button use:popup={{settings, component: MyPopupComponent, props: { fruit }}}>...</button>
{/each} Or possibly even have a generator for the popup action along the lines of <script>
const fruitPopup = GeneratePopupAction({
event: 'click',
placement: 'top',
component: MyPopupComponent // Ideally the generated action would be typed such the the component props are the action parameters
})
</script>
{#each fruits as fruit}
{fruit.name} - <button use:fruitPopup={{ fruit }}>...</button>
{/each} |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Suggestion/Feature Request: Ability to disable/turn off popup(s) through the use of a prop or have popup check the disabled state on the trigger element when open event occurs. An example would be below where we have a popup using the event: 'hover' but we do not want said popup if this element is clicked: const popupHover: PopupSettings = {
event: 'hover',
target: 'popupHover',
placement: 'top'
};
<button class="btn variant-filled [&>*]:pointer-events-none" use:popup={popupHover}>
<span>(icon)</span>
<span>Hover</span>
</button> Current workaround thanks to Chris would be along the lines of the below where we maintain a local variable for state to control to when to show element: use:popup={someBool ? popupHover : {}} |
To solve or alongside Joseph's request above, I think we need to check the |
This comment was marked as resolved.
This comment was marked as resolved.
Currently the However, setting closeQuery to We should probably adjust the function onWindowClick(event: any): void {
// Return if the popup is not yet open
if (popupState.open === false) return;
// Return if click is the trigger element
if (triggerNode.contains(event.target)) return;
// If click it outside the popup
if (elemPopup && elemPopup.contains(event.target) === false) {
close();
return;
}
// Handle Close Query State
const closeQueryString: string = args.closeQuery === undefined ? 'a[href], button' : args.closeQuery;
// Respect not querying for things if the string is empty
if (closeQueryString === '') {
return;
}
const closableMenuElements = elemPopup?.querySelectorAll(closeQueryString);
closableMenuElements?.forEach((elem) => {
if (elem.contains(event.target)) close();
});
} Also I would propose that we could potentially solve some issues with Example: <script lang="ts">
// Let the user maintain their own reference to the target
let popupEl: HTMLElement | null = null;
const popupFeatured: PopupSettings = {
event: 'focus-click',
// Matches the real element from bind:this
target: popupEl,
placement: 'bottom',
};
</script>
<button class="btn variant-filled" use:popup={popupFeatured}>Show Popup</button>
<div class="card p-4 w-72 shadow-xl" bind:this={popupEl}>
<div><p>Demo Content</p></div>
</div> Accomplishing this would likely be fairly straightforward as well by modifying the function setDomElements(): void {
// If a real element was passed, use it as the elemPopup
if (args.target instanceof Element) {
elemPopup = args.target;
} else {
elemPopup = document.querySelector(`[data-popup="${args.target}"]`) ?? document.createElement('div');
}
elemArrow = elemPopup.querySelector(`.arrow`) ?? document.createElement('div');
} |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
If the |
POC for a react/vue like hook pattern using svelte runes. API looks like: const { refs } = useFloating({
middleware: [flip()],
placement: 'top',
}); <button bind:this={refs.reference}>Button</button>
<div bind:this={refs.floating}></div> |
FYI everyone, progress on this issue is starting this week. The goal is to determine how best to handle Floating UI integration for popovers, tooltips, etc. Note that I've updated the "Proposals" section in the original post at the top discussing the ways we can approach this. I'll aim to provided at least a rudimentary recommendation in a follow up sometime later this week. In the meantime I will be consolidating all requests and feedback to ensure we're provide the best solution long term. |
Still working through this, but wanted to summarize my current thoughts and progress... Reacthttps://floating-ui.com/docs/react Overall this provides an extensive toolkit for interacting handling overlay elements in React. It adds ton of critical features, with a number of utilities that provide handy quality of life improvements. I've provided a summary and prioritized list below: ## Critical to Skeleton
- `useFloating` - the core feature, handles most config
- `useInteractions` - opts into event handler hooks, such as:
- `useHover`
- `useFocus`
- `useClick`
- `useRole` - utility to assign ARIA roles to elements
- `useDismiss` - dismiss on request or on click "outside"
- `useTrasition` - allows you to control open/close transitions
- `useClientPoint` - positon floating element at set x/y position
- `FloatingArrow` - handles the floating arrow (pairs with a SVG component)
- `FloatingFocusManager` - focus trap for dialogs
## Nice to Have
- `useListNavigation` - adds arrow navigation to menu lists
- `useTypeahead` - focuses element on typing, NOT for use with inputs or combobox
- `FloatingPortal` - positions floating element outside root/body scope
- `FloatingTree` - context for nested floating elements that are not children
- `FloatingOverlay` - handles backdrops for fades behind dialogs
- `FloatingList` - composable children API for list components
- `FloatingDelayGroup` - handles offset group delays
- `Composite` - (not sure I understand this one)
- `Inner` - allows you to anchor a floating element to a reference centerpoint Vuehttps://floating-ui.com/docs/vue This is limited to bindings for the core library - for positioning ONLY. It does not offer any features beyond this. Sveltehttps://floating-ui.com/docs/getting-started#vanilla This would currently lean into the core package, similar to Vue, but without the dedicated bindings. |
We've provided a more in-depth exploration of our proposal for Skeleton v3 popover features here:
We encourage feedback about the proposal be confined to the post linked above. |
Quick update, I encourage everyone to check out our new announcement for Floating UI Svelte. This will act as our long term solution for popovers for Svelte in Skeleton v3: Additionally, for React users, we'll lean directly into the Floating UI React package: |
I'll be posting a new Discussions announcement tomorrow that details our solutions for Popovers in v3. Please refer to this PR, or the updated docs Popover Integrations section on the v3 docs. Note that work on Floating UI Svelte will continue beyond the Skeleton v3 launch. Progress should be tracked on GitHub. |
Warning
While we prep and plan for Skeleton v3, we're going to implement a feature freeze on the current popup implementation. This helps prevent redundant effort and avoids pushing out the goalpost even further.
This acts as a centralize HUB for requests related to popups, popovers, drop-downs, tooltips, and similar UI patterns.
The Issue
The Skeleton popup feature was originally implemented to provide very rudimentary popups. This included interacting with a single trigger element that would then show a single popup. Over time, the scope of this feature has grown and users are expecting more and more. To accomplish this, we've opted to integrate Floating UI.
To keep this dependency optional in Skeleton, users have been required to jump through extra hoops to import Floating UI as a dependency, pass several modules to a dedicated Svelte store, and then all implementation is based around these optional modules. This roundabout means for implementing the dependency has resulted is very limited capabilities, and prevented direct access to Typescript types provided by Floating UI.
The Goal
Seek the simplest and most direct integration path between Floating UI and each framework Skeleton supports, while still providing a friendly interface for common overlay patterns, such as: popovers, drop-down menus, tooltips, context menus, etc.
Solution:
Maintainer Requests
The follow requests are coming from the Skeleton core team and maintains, these highly likely to be implemented:
Community Requests
The following requests come from the Skeleton community and are pending review. They may or may not move forward:
Feedback
If you have additional updates or requests for this feature, please do so in the comments section below.
The text was updated successfully, but these errors were encountered: