@ui-sdk/web 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +10 -2
- package/browser/web/accordion.js +1 -0
- package/browser/web/alert-dialog.js +1 -0
- package/browser/web/autocomplete.js +1 -0
- package/browser/web/avatar.js +1 -0
- package/browser/web/button.js +1 -0
- package/browser/web/calendar.js +1 -0
- package/browser/web/carousel.js +1 -0
- package/browser/web/checkbox.js +1 -0
- package/browser/web/chunks/0eRGibL6.js +1 -0
- package/browser/web/chunks/2bIEUO6_.js +1 -0
- package/browser/web/chunks/5A9w2ULz.js +1 -0
- package/browser/web/chunks/5RSyydjV.js +1 -0
- package/browser/web/chunks/9pWTy2wl.js +1 -0
- package/browser/web/chunks/B0f2j6zz.js +1 -0
- package/browser/web/chunks/B1rux6br.js +1 -0
- package/browser/web/chunks/B3-APaNf.js +1 -0
- package/browser/web/chunks/B7EgSgjQ.js +1 -0
- package/browser/web/chunks/B8QcOzJU.js +1 -0
- package/browser/web/chunks/BFueEkwm.js +3 -0
- package/browser/web/chunks/BJj3oS29.js +1 -0
- package/browser/web/chunks/BNSvTCpr.js +1 -0
- package/browser/web/chunks/BPD0kAZB.js +1 -0
- package/browser/web/chunks/BQeduZqT.js +1 -0
- package/browser/web/chunks/B_CVFyiz.js +1 -0
- package/browser/web/chunks/B_ns1YHO.js +1 -0
- package/browser/web/chunks/BcwkVTsR.js +1 -0
- package/browser/web/chunks/BeaQ6TYM.js +1 -0
- package/browser/web/chunks/BgBB013u.js +1 -0
- package/browser/web/chunks/BgsKhHDm.js +1 -0
- package/browser/web/chunks/BjMcbuhi.js +9 -0
- package/browser/web/chunks/Bjiy_F2N.js +1 -0
- package/browser/web/chunks/BqScCLwv.js +1 -0
- package/browser/web/chunks/BqX3Utqx.js +1 -0
- package/browser/web/chunks/BtVkQf3z.js +1 -0
- package/browser/web/chunks/By30h-7B.js +1 -0
- package/browser/web/chunks/C1zqYpy2.js +1 -0
- package/browser/web/chunks/C436juFf.js +1 -0
- package/browser/web/chunks/C4_bULs1.js +1 -0
- package/browser/web/chunks/C4omqJEz.js +1 -0
- package/browser/web/chunks/C7tt0T3n.js +1 -0
- package/browser/web/chunks/C8w7s5dg.js +1 -0
- package/browser/web/chunks/CElY4erO.js +1 -0
- package/browser/web/chunks/CFODo-m2.js +1 -0
- package/browser/web/chunks/CL4wjam9.js +1 -0
- package/browser/web/chunks/CMg-8UVf.js +1 -0
- package/browser/web/chunks/COWKfakj.js +1 -0
- package/browser/web/chunks/CQBU0qZ4.js +1 -0
- package/browser/web/chunks/CV6uABgc.js +1 -0
- package/browser/web/chunks/C_SWFpWQ.js +1 -0
- package/browser/web/chunks/C_Uanbrl.js +1 -0
- package/browser/web/chunks/Ce_CSanC.js +1 -0
- package/browser/web/chunks/Cg-ZmRhS.js +1 -0
- package/browser/web/chunks/Cgf2wPI_.js +1 -0
- package/browser/web/chunks/Cuep_3Vf.js +1 -0
- package/browser/web/chunks/D02PaHn6.js +1 -0
- package/browser/web/chunks/D5LiaI5R.js +1 -0
- package/browser/web/chunks/D9UgVYvF.js +1 -0
- package/browser/web/chunks/DC08tnkE.js +2 -0
- package/browser/web/chunks/DG8YGSvu.js +1 -0
- package/browser/web/chunks/DIQd0FYD.js +1 -0
- package/browser/web/chunks/DMLqacE8.js +1 -0
- package/browser/web/chunks/DSUI3yI-.js +1 -0
- package/browser/web/chunks/DT3Hb76X.js +1 -0
- package/browser/web/chunks/DY75g3-W.js +1 -0
- package/browser/web/chunks/DZpNQKZ9.js +1 -0
- package/browser/web/chunks/Db-W1wrC.js +1 -0
- package/browser/web/chunks/Dc1xK3Ii.js +1 -0
- package/browser/web/chunks/DdF6awFs.js +1 -0
- package/browser/web/chunks/DdaCLml8.js +1 -0
- package/browser/web/chunks/Dh8MLjQO.js +1 -0
- package/browser/web/chunks/DiuslJRy.js +1 -0
- package/browser/web/chunks/DjRcw3Y0.js +1 -0
- package/browser/web/chunks/Djdv-16J.js +1 -0
- package/browser/web/chunks/DnFXe_lF.js +1 -0
- package/browser/web/chunks/DneGv1oC.js +1 -0
- package/browser/web/chunks/DsVxP-p-.js +1 -0
- package/browser/web/chunks/DwDilCo2.js +1 -0
- package/browser/web/chunks/DwV48AXv.js +1 -0
- package/browser/web/chunks/F37aF4-L.js +1 -0
- package/browser/web/chunks/LyB6XIbN.js +1 -0
- package/browser/web/chunks/NKnbYGjC.js +1 -0
- package/browser/web/chunks/Vk-rVi16.js +1 -0
- package/browser/web/chunks/XsM0J1Ex.js +1 -0
- package/browser/web/chunks/asSN9iEp.js +1 -0
- package/browser/web/chunks/c-AjHfdF.js +1 -0
- package/browser/web/chunks/dR-12TPY.js +1 -0
- package/browser/web/chunks/hR4xM0EC.js +1 -0
- package/browser/web/chunks/hqOaBxAg.js +1 -0
- package/browser/web/chunks/kMKqqeG4.js +1 -0
- package/browser/web/chunks/kXboBcfi.js +1 -0
- package/browser/web/chunks/l4aQIg22.js +1 -0
- package/browser/web/chunks/tJC0JSU4.js +1 -0
- package/browser/web/chunks/wHdS_QYM.js +1 -0
- package/browser/web/chunks/yv8dTvNI.js +1 -0
- package/browser/web/chunks/yw9M3nfi.js +1 -0
- package/browser/web/collapsible.js +1 -0
- package/browser/web/color-picker.js +1 -0
- package/browser/web/combobox.js +2 -0
- package/browser/web/command.js +1 -0
- package/browser/web/core.js +5 -0
- package/browser/web/date-input.js +1 -0
- package/browser/web/date-picker.js +1 -0
- package/browser/web/dialog.js +1 -0
- package/browser/web/drawer.js +1 -0
- package/browser/web/field.js +1 -0
- package/browser/web/file-input.js +1 -0
- package/browser/web/hover-card.js +1 -0
- package/browser/web/image-cropper.js +1 -0
- package/browser/web/input.js +1 -0
- package/browser/web/label.js +1 -0
- package/browser/web/listbox.js +1 -0
- package/browser/web/menu.js +1 -0
- package/browser/web/menubar.js +1 -0
- package/browser/web/meter.js +1 -0
- package/browser/web/navigation-menu.js +1 -0
- package/browser/web/number-input.js +1 -0
- package/browser/web/otp-input.js +2 -0
- package/browser/web/overlays.js +1 -0
- package/browser/web/pagination.js +1 -0
- package/browser/web/password-input.js +1 -0
- package/browser/web/popover.js +1 -0
- package/browser/web/preferences.js +1 -0
- package/browser/web/progress.js +1 -0
- package/browser/web/radio.js +1 -0
- package/browser/web/rating.js +1 -0
- package/browser/web/resizable.js +1 -0
- package/browser/web/scroll-area.js +1 -0
- package/browser/web/segmented-control.js +1 -0
- package/browser/web/select.js +1 -0
- package/browser/web/separator.js +1 -0
- package/browser/web/slider.js +1 -0
- package/browser/web/switch.js +1 -0
- package/browser/web/tabs.js +1 -0
- package/browser/web/textarea.js +1 -0
- package/browser/web/time-input.js +1 -0
- package/browser/web/timeline.js +1 -0
- package/browser/web/toast.js +1 -0
- package/browser/web/toggle.js +1 -0
- package/browser/web/token-input.js +8 -0
- package/browser/web/toolbar.js +1 -0
- package/browser/web/tooltip.js +1 -0
- package/browser/web/tree.js +1 -0
- package/browser/web/trigger-menu.js +4 -0
- package/browser/web/waterfall.js +1 -0
- package/browser/web.css +3378 -0
- package/browser/web.js +3 -0
- package/custom-elements.json +32315 -0
- package/dist/accordion.d.ts +2 -0
- package/dist/accordion.js +57 -0
- package/dist/action.d.ts +16 -0
- package/dist/action.js +39 -0
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +7 -0
- package/dist/autocomplete.d.ts +2 -0
- package/dist/autocomplete.js +120 -0
- package/dist/autoload.d.ts +18 -0
- package/dist/autoload.js +63 -0
- package/dist/avatar.d.ts +2 -0
- package/dist/avatar.js +27 -0
- package/dist/browser-core.d.ts +2 -0
- package/dist/browser-core.js +8 -0
- package/dist/button.d.ts +2 -0
- package/dist/button.js +35 -0
- package/dist/calendar.d.ts +23 -0
- package/dist/calendar.js +429 -0
- package/dist/carousel.d.ts +2 -0
- package/dist/carousel.js +54 -0
- package/dist/checkbox.d.ts +4 -0
- package/dist/checkbox.js +75 -0
- package/dist/collapsible.d.ts +2 -0
- package/dist/collapsible.js +28 -0
- package/dist/color-picker.d.ts +2 -0
- package/dist/color-picker.js +64 -0
- package/dist/combobox.d.ts +2 -0
- package/dist/combobox.js +334 -0
- package/dist/command.d.ts +2 -0
- package/dist/command.js +122 -0
- package/dist/date-input.d.ts +3 -0
- package/dist/date-input.js +87 -0
- package/dist/date-picker.d.ts +2 -0
- package/dist/date-picker.js +174 -0
- package/dist/default-text.d.ts +3 -0
- package/dist/default-text.js +24 -0
- package/dist/define-element.d.ts +404 -0
- package/dist/define-element.js +1489 -0
- package/dist/dialog.d.ts +3 -0
- package/dist/dialog.js +94 -0
- package/dist/drawer.d.ts +2 -0
- package/dist/drawer.js +96 -0
- package/dist/entries/accordion.d.ts +3 -0
- package/dist/entries/accordion.js +7 -0
- package/dist/entries/alert-dialog.d.ts +3 -0
- package/dist/entries/alert-dialog.js +13 -0
- package/dist/entries/autocomplete.d.ts +3 -0
- package/dist/entries/autocomplete.js +7 -0
- package/dist/entries/avatar.d.ts +2 -0
- package/dist/entries/avatar.js +3 -0
- package/dist/entries/button.d.ts +2 -0
- package/dist/entries/button.js +3 -0
- package/dist/entries/calendar.d.ts +3 -0
- package/dist/entries/calendar.js +7 -0
- package/dist/entries/carousel.d.ts +3 -0
- package/dist/entries/carousel.js +7 -0
- package/dist/entries/checkbox.d.ts +3 -0
- package/dist/entries/checkbox.js +15 -0
- package/dist/entries/collapsible.d.ts +3 -0
- package/dist/entries/collapsible.js +7 -0
- package/dist/entries/color-picker.d.ts +3 -0
- package/dist/entries/color-picker.js +7 -0
- package/dist/entries/combobox.d.ts +3 -0
- package/dist/entries/combobox.js +7 -0
- package/dist/entries/command.d.ts +3 -0
- package/dist/entries/command.js +7 -0
- package/dist/entries/date-input.d.ts +3 -0
- package/dist/entries/date-input.js +7 -0
- package/dist/entries/date-picker.d.ts +3 -0
- package/dist/entries/date-picker.js +7 -0
- package/dist/entries/dialog.d.ts +3 -0
- package/dist/entries/dialog.js +7 -0
- package/dist/entries/drawer.d.ts +3 -0
- package/dist/entries/drawer.js +8 -0
- package/dist/entries/field.d.ts +2 -0
- package/dist/entries/field.js +3 -0
- package/dist/entries/file-input.d.ts +3 -0
- package/dist/entries/file-input.js +13 -0
- package/dist/entries/hover-card.d.ts +3 -0
- package/dist/entries/hover-card.js +7 -0
- package/dist/entries/image-cropper.d.ts +3 -0
- package/dist/entries/image-cropper.js +7 -0
- package/dist/entries/input.d.ts +3 -0
- package/dist/entries/input.js +8 -0
- package/dist/entries/label.d.ts +2 -0
- package/dist/entries/label.js +3 -0
- package/dist/entries/listbox.d.ts +3 -0
- package/dist/entries/listbox.js +7 -0
- package/dist/entries/menu.d.ts +3 -0
- package/dist/entries/menu.js +7 -0
- package/dist/entries/menubar.d.ts +3 -0
- package/dist/entries/menubar.js +7 -0
- package/dist/entries/meter.d.ts +2 -0
- package/dist/entries/meter.js +3 -0
- package/dist/entries/navigation-menu.d.ts +3 -0
- package/dist/entries/navigation-menu.js +7 -0
- package/dist/entries/number-input.d.ts +3 -0
- package/dist/entries/number-input.js +7 -0
- package/dist/entries/otp-input.d.ts +3 -0
- package/dist/entries/otp-input.js +7 -0
- package/dist/entries/overlays.d.ts +2 -0
- package/dist/entries/overlays.js +3 -0
- package/dist/entries/pagination.d.ts +3 -0
- package/dist/entries/pagination.js +11 -0
- package/dist/entries/password-input.d.ts +3 -0
- package/dist/entries/password-input.js +7 -0
- package/dist/entries/popover.d.ts +3 -0
- package/dist/entries/popover.js +7 -0
- package/dist/entries/preferences.d.ts +3 -0
- package/dist/entries/preferences.js +13 -0
- package/dist/entries/progress.d.ts +2 -0
- package/dist/entries/progress.js +3 -0
- package/dist/entries/radio.d.ts +3 -0
- package/dist/entries/radio.js +7 -0
- package/dist/entries/rating.d.ts +3 -0
- package/dist/entries/rating.js +8 -0
- package/dist/entries/resizable.d.ts +3 -0
- package/dist/entries/resizable.js +11 -0
- package/dist/entries/scroll-area.d.ts +3 -0
- package/dist/entries/scroll-area.js +7 -0
- package/dist/entries/segmented-control.d.ts +3 -0
- package/dist/entries/segmented-control.js +7 -0
- package/dist/entries/select.d.ts +3 -0
- package/dist/entries/select.js +7 -0
- package/dist/entries/separator.d.ts +2 -0
- package/dist/entries/separator.js +3 -0
- package/dist/entries/slider.d.ts +3 -0
- package/dist/entries/slider.js +7 -0
- package/dist/entries/switch.d.ts +3 -0
- package/dist/entries/switch.js +7 -0
- package/dist/entries/tabs.d.ts +3 -0
- package/dist/entries/tabs.js +7 -0
- package/dist/entries/textarea.d.ts +3 -0
- package/dist/entries/textarea.js +7 -0
- package/dist/entries/time-input.d.ts +3 -0
- package/dist/entries/time-input.js +7 -0
- package/dist/entries/timeline.d.ts +3 -0
- package/dist/entries/timeline.js +7 -0
- package/dist/entries/toast.d.ts +2 -0
- package/dist/entries/toast.js +3 -0
- package/dist/entries/toggle.d.ts +3 -0
- package/dist/entries/toggle.js +12 -0
- package/dist/entries/token-input.d.ts +3 -0
- package/dist/entries/token-input.js +17 -0
- package/dist/entries/toolbar.d.ts +3 -0
- package/dist/entries/toolbar.js +7 -0
- package/dist/entries/tooltip.d.ts +3 -0
- package/dist/entries/tooltip.js +7 -0
- package/dist/entries/tree.d.ts +3 -0
- package/dist/entries/tree.js +17 -0
- package/dist/entries/trigger-menu.d.ts +3 -0
- package/dist/entries/trigger-menu.js +11 -0
- package/dist/entries/waterfall.d.ts +3 -0
- package/dist/entries/waterfall.js +11 -0
- package/dist/events.d.ts +1658 -0
- package/dist/events.js +0 -0
- package/dist/field.d.ts +2 -0
- package/dist/field.js +101 -0
- package/dist/file-input.d.ts +2 -0
- package/dist/file-input.js +140 -0
- package/dist/forward-attributes.d.ts +2 -0
- package/dist/forward-attributes.js +22 -0
- package/dist/history.d.ts +2 -0
- package/dist/history.js +11 -0
- package/dist/hover-card.d.ts +2 -0
- package/dist/hover-card.js +31 -0
- package/dist/image-cropper.d.ts +2 -0
- package/dist/image-cropper.js +66 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +269 -0
- package/dist/input.d.ts +3 -0
- package/dist/input.js +69 -0
- package/dist/label.d.ts +2 -0
- package/dist/label.js +11 -0
- package/dist/list.d.ts +40 -0
- package/dist/list.js +192 -0
- package/dist/listbox.d.ts +2 -0
- package/dist/listbox.js +84 -0
- package/dist/menu.d.ts +4 -0
- package/dist/menu.js +295 -0
- package/dist/menubar.d.ts +4 -0
- package/dist/menubar.js +30 -0
- package/dist/meter.d.ts +2 -0
- package/dist/meter.js +22 -0
- package/dist/navigation-menu.d.ts +2 -0
- package/dist/navigation-menu.js +114 -0
- package/dist/number-input.d.ts +2 -0
- package/dist/number-input.js +73 -0
- package/dist/observe.d.ts +2 -0
- package/dist/observe.js +7 -0
- package/dist/otp-input.d.ts +2 -0
- package/dist/otp-input.js +72 -0
- package/dist/overlays.d.ts +13 -0
- package/dist/overlays.js +156 -0
- package/dist/pagination.d.ts +2 -0
- package/dist/pagination.js +127 -0
- package/dist/password-input.d.ts +2 -0
- package/dist/password-input.js +57 -0
- package/dist/popover.d.ts +2 -0
- package/dist/popover.js +64 -0
- package/dist/popup.d.ts +40 -0
- package/dist/popup.js +112 -0
- package/dist/preferences.d.ts +2 -0
- package/dist/preferences.js +56 -0
- package/dist/progress.d.ts +2 -0
- package/dist/progress.js +22 -0
- package/dist/radio.d.ts +2 -0
- package/dist/radio.js +33 -0
- package/dist/rating.d.ts +2 -0
- package/dist/rating.js +64 -0
- package/dist/resizable.d.ts +2 -0
- package/dist/resizable.js +42 -0
- package/dist/scroll-area.d.ts +2 -0
- package/dist/scroll-area.js +45 -0
- package/dist/segmented-control.d.ts +2 -0
- package/dist/segmented-control.js +28 -0
- package/dist/select.d.ts +2 -0
- package/dist/select.js +239 -0
- package/dist/separator.d.ts +2 -0
- package/dist/separator.js +11 -0
- package/dist/slider.d.ts +2 -0
- package/dist/slider.js +77 -0
- package/dist/tabs.d.ts +2 -0
- package/dist/tabs.js +37 -0
- package/dist/timeline.d.ts +2 -0
- package/dist/timeline.js +27 -0
- package/dist/toast.d.ts +20 -0
- package/dist/toast.js +177 -0
- package/dist/toggle.d.ts +3 -0
- package/dist/toggle.js +64 -0
- package/dist/token-input.d.ts +2 -0
- package/dist/token-input.js +103 -0
- package/dist/toolbar.d.ts +2 -0
- package/dist/toolbar.js +36 -0
- package/dist/tooltip.d.ts +2 -0
- package/dist/tooltip.js +35 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.js +147 -0
- package/dist/trigger-menu.d.ts +2 -0
- package/dist/trigger-menu.js +133 -0
- package/dist/waterfall.d.ts +2 -0
- package/dist/waterfall.js +140 -0
- package/docs/README.md +89 -0
- package/docs/agents.md +1523 -0
- package/docs/components/accordion.md +1401 -0
- package/docs/components/alert-dialog.md +788 -0
- package/docs/components/autocomplete.md +1692 -0
- package/docs/components/avatar.md +261 -0
- package/docs/components/button.md +441 -0
- package/docs/components/calendar.md +1536 -0
- package/docs/components/carousel.md +1055 -0
- package/docs/components/checkbox.md +1045 -0
- package/docs/components/collapsible.md +535 -0
- package/docs/components/color-picker.md +651 -0
- package/docs/components/combobox.md +3274 -0
- package/docs/components/command.md +1431 -0
- package/docs/components/date-input.md +563 -0
- package/docs/components/date-picker.md +1136 -0
- package/docs/components/dialog.md +1360 -0
- package/docs/components/drawer.md +1201 -0
- package/docs/components/field.md +519 -0
- package/docs/components/file-input.md +617 -0
- package/docs/components/hover-card.md +486 -0
- package/docs/components/image-cropper.md +489 -0
- package/docs/components/input.md +327 -0
- package/docs/components/label.md +208 -0
- package/docs/components/listbox.md +1015 -0
- package/docs/components/menu.md +1212 -0
- package/docs/components/menubar.md +460 -0
- package/docs/components/meter.md +298 -0
- package/docs/components/navigation-menu.md +1573 -0
- package/docs/components/number-input.md +1087 -0
- package/docs/components/otp-input.md +558 -0
- package/docs/components/pagination.md +639 -0
- package/docs/components/password-input.md +649 -0
- package/docs/components/popover.md +1433 -0
- package/docs/components/preferences.md +243 -0
- package/docs/components/progress.md +406 -0
- package/docs/components/radio.md +855 -0
- package/docs/components/rating.md +431 -0
- package/docs/components/resizable.md +866 -0
- package/docs/components/scroll-area.md +898 -0
- package/docs/components/segmented-control.md +421 -0
- package/docs/components/select.md +1957 -0
- package/docs/components/separator.md +238 -0
- package/docs/components/slider.md +1018 -0
- package/docs/components/switch.md +583 -0
- package/docs/components/tabs.md +948 -0
- package/docs/components/textarea.md +331 -0
- package/docs/components/time-input.md +235 -0
- package/docs/components/timeline.md +622 -0
- package/docs/components/toast.md +1223 -0
- package/docs/components/toggle.md +522 -0
- package/docs/components/token-input.md +854 -0
- package/docs/components/toolbar.md +815 -0
- package/docs/components/tooltip.md +860 -0
- package/docs/components/tree.md +1243 -0
- package/docs/components/trigger-menu.md +1110 -0
- package/docs/components/waterfall.md +709 -0
- package/docs/controllers.md +66 -0
- package/docs/core.md +8027 -0
- package/docs/custom-parts.md +91 -0
- package/docs/first-component.md +88 -0
- package/docs/forms.md +125 -0
- package/docs/installation.md +141 -0
- package/docs/introduction.md +32 -0
- package/docs/lists-and-menus.md +166 -0
- package/docs/llms.txt +1566 -0
- package/docs/parts-and-composition.md +57 -0
- package/docs/popups.md +92 -0
- package/docs/rendering.md +71 -0
- package/docs/server-rendering.md +118 -0
- package/docs/state-and-events.md +134 -0
- package/docs/styling-and-animation.md +104 -0
- package/docs/utilities/async-options.md +332 -0
- package/docs/utilities/shortcuts.md +184 -0
- package/html-custom-data.json +14792 -0
- package/package.json +302 -3
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# Hover Card
|
|
2
|
+
|
|
3
|
+
Preview a link on hover or keyboard focus while keeping its normal navigation.
|
|
4
|
+
|
|
5
|
+
A hover card shows a preview of where a link goes, like a person's profile, to someone who pauses on it. The link still works as a link.
|
|
6
|
+
|
|
7
|
+
```ts title="basic.ts"
|
|
8
|
+
import "@ui-sdk/web/hover-card"
|
|
9
|
+
|
|
10
|
+
function mount(root: HTMLElement) {
|
|
11
|
+
root.innerHTML = `
|
|
12
|
+
<ui-hover-card>
|
|
13
|
+
<ui-hover-card-trigger><a href="https://example.com/people/hollis">@hollis</a></ui-hover-card-trigger>
|
|
14
|
+
<ui-hover-card-content hidden>
|
|
15
|
+
<div data-slot="row">
|
|
16
|
+
<span data-slot="initials" aria-hidden="true">HG</span>
|
|
17
|
+
<div data-slot="stack">
|
|
18
|
+
<p>Hollis Grant</p>
|
|
19
|
+
<p>Design engineer on the payments team. Writes about forms and motion.</p>
|
|
20
|
+
<p data-slot="hint">Joined March 2021</p>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</ui-hover-card-content>
|
|
24
|
+
</ui-hover-card>
|
|
25
|
+
`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { mount }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Hover @hollis, or Tab to it and wait, to open Hollis Grant's profile preview. Move the pointer away or press Escape to close it.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @ui-sdk/web @ui-sdk/core
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Import the component to register its elements. The import is safe on the server.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import "@ui-sdk/web/hover-card"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Composition
|
|
46
|
+
|
|
47
|
+
Use the following composition to build a `ui-hover-card`:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
ui-hover-card
|
|
51
|
+
├── ui-hover-card-trigger
|
|
52
|
+
│ └── a
|
|
53
|
+
└── ui-hover-card-content
|
|
54
|
+
└── ui-hover-card-arrow
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The trigger wraps your own link (an `<a>`, so give it an `href`), and pressing it follows the link. The content is the preview, and the arrow is optional.
|
|
58
|
+
|
|
59
|
+
The card only adds a preview for people who pause on the link: everything in it should be reachable from the page the link goes to, since touch and screen reader users may never open it. For a tip on a button, use a [Tooltip](./tooltip.md). For content that opens with a press, use a [Popover](./popover.md).
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
Import the parts and put them together:
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<script type="module">
|
|
67
|
+
import "@ui-sdk/web/hover-card"
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<ui-hover-card>
|
|
71
|
+
<ui-hover-card-trigger
|
|
72
|
+
><a href="/people/hollis">@hollis</a></ui-hover-card-trigger
|
|
73
|
+
>
|
|
74
|
+
<ui-hover-card-content hidden>
|
|
75
|
+
<p>Hollis Grant</p>
|
|
76
|
+
<p>Design engineer on the payments team.</p>
|
|
77
|
+
</ui-hover-card-content>
|
|
78
|
+
</ui-hover-card>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Positioning
|
|
82
|
+
|
|
83
|
+
`side` picks where the card opens, `bottom` by default, and `align` lines it up with the start, center or end of the link. The card flips to the other side when there isn't room and shifts along the link to stay on screen.
|
|
84
|
+
|
|
85
|
+
`ui-hover-card-arrow` follows the side the card actually lands on, including after a flip, and gets the same `data-side`. It points at the middle of the link and keeps `arrow-padding` away from the corners; `data-arrow-clamped` tells you when it can't reach the middle.
|
|
86
|
+
|
|
87
|
+
```ts title="side.ts"
|
|
88
|
+
import "@ui-sdk/web/hover-card"
|
|
89
|
+
import "@ui-sdk/web/select"
|
|
90
|
+
import { Check, ChevronDown, createElement } from "lucide"
|
|
91
|
+
|
|
92
|
+
const sides = [
|
|
93
|
+
{ value: "top", label: "Top" },
|
|
94
|
+
{ value: "right", label: "Right" },
|
|
95
|
+
{ value: "bottom", label: "Bottom" },
|
|
96
|
+
{ value: "left", label: "Left" },
|
|
97
|
+
]
|
|
98
|
+
const aligns = [
|
|
99
|
+
{ value: "start", label: "Start" },
|
|
100
|
+
{ value: "center", label: "Center" },
|
|
101
|
+
{ value: "end", label: "End" },
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
const select = (
|
|
105
|
+
name: string,
|
|
106
|
+
label: string,
|
|
107
|
+
options: { value: string; label: string }[],
|
|
108
|
+
value: string
|
|
109
|
+
) => `
|
|
110
|
+
<ui-select data-control="${name}" default-value="${value}">
|
|
111
|
+
<ui-select-label>${label}</ui-select-label>
|
|
112
|
+
<ui-select-trigger>
|
|
113
|
+
<button>
|
|
114
|
+
<ui-select-value></ui-select-value>
|
|
115
|
+
${createElement(ChevronDown, { "aria-hidden": "true" }).outerHTML}
|
|
116
|
+
</button>
|
|
117
|
+
</ui-select-trigger>
|
|
118
|
+
<ui-select-content hidden>
|
|
119
|
+
${options
|
|
120
|
+
.map(
|
|
121
|
+
(option) => `
|
|
122
|
+
<ui-select-item value="${option.value}">
|
|
123
|
+
${option.label}
|
|
124
|
+
<ui-select-item-indicator>${createElement(Check, { "aria-hidden": "true" }).outerHTML}</ui-select-item-indicator>
|
|
125
|
+
</ui-select-item>
|
|
126
|
+
`
|
|
127
|
+
)
|
|
128
|
+
.join("")}
|
|
129
|
+
</ui-select-content>
|
|
130
|
+
</ui-select>
|
|
131
|
+
`
|
|
132
|
+
|
|
133
|
+
function mount(root: HTMLElement) {
|
|
134
|
+
root.innerHTML = `
|
|
135
|
+
<div data-slot="stack">
|
|
136
|
+
<div data-slot="controls">
|
|
137
|
+
${select("side", "Side", sides, "bottom")}
|
|
138
|
+
${select("align", "Align", aligns, "center")}
|
|
139
|
+
</div>
|
|
140
|
+
<ui-hover-card>
|
|
141
|
+
<ui-hover-card-trigger><a href="https://example.com/people/ines">@ines</a></ui-hover-card-trigger>
|
|
142
|
+
<ui-hover-card-content hidden side="bottom" align="center" side-offset="10">
|
|
143
|
+
<ui-hover-card-arrow></ui-hover-card-arrow>
|
|
144
|
+
<p>Inès Moreau</p>
|
|
145
|
+
<p>Product designer. Leads the checkout redesign.</p>
|
|
146
|
+
</ui-hover-card-content>
|
|
147
|
+
</ui-hover-card>
|
|
148
|
+
</div>
|
|
149
|
+
`
|
|
150
|
+
const content = root.querySelector("ui-hover-card-content")!
|
|
151
|
+
for (const control of root.querySelectorAll("ui-select")) {
|
|
152
|
+
control.addEventListener("valuechange", (event) => {
|
|
153
|
+
if (event.detail.value) {
|
|
154
|
+
content.setAttribute(
|
|
155
|
+
control.dataset.control!,
|
|
156
|
+
String(event.detail.value)
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { mount }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Choose a side and an alignment, then hover @ines. The card opens there and its arrow points at the link.
|
|
167
|
+
|
|
168
|
+
`side-offset` is the gap to the link, 4 pixels by default. `align-offset` shifts the card along it, and `collision-padding` is the space kept from the edges of the window. `anchor` positions the card against something other than the link, named by a CSS selector.
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<ui-hover-card-content
|
|
172
|
+
side="right"
|
|
173
|
+
align="start"
|
|
174
|
+
side-offset="8"
|
|
175
|
+
collision-padding="16"
|
|
176
|
+
anchor="#row"
|
|
177
|
+
hidden
|
|
178
|
+
></ui-hover-card-content>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Delays
|
|
182
|
+
|
|
183
|
+
`delay` is how long the pointer rests on the link, or keyboard focus stays on it, before the card opens: 600 milliseconds by default. `close-delay` is how long it stays open once the pointer leaves the link and the card: 300 milliseconds by default. The pointer can cross the gap between the link and the card without closing it.
|
|
184
|
+
|
|
185
|
+
`disabled` stops the card from opening and leaves a plain link.
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<ui-hover-card delay="300" close-delay="150" disabled></ui-hover-card>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Controlled
|
|
192
|
+
|
|
193
|
+
Set the element's `open` property and listen for `openchange`; the `open` attribute sets where it starts. Every change carries a [reason](#reasons) in `event.detail.reason`, like `trigger-hover`, `trigger-focus`, `focus-out`, `escape-key` or `outside-press`. Call `event.preventDefault()` to stop it.
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<ui-hover-card></ui-hover-card>
|
|
197
|
+
|
|
198
|
+
<script type="module">
|
|
199
|
+
const card = document.querySelector("ui-hover-card")
|
|
200
|
+
card.addEventListener("openchange", (event) => (open = event.detail.value))
|
|
201
|
+
card.open = true
|
|
202
|
+
</script>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## One Card for Many Links
|
|
206
|
+
|
|
207
|
+
A feed or a list can share one card instead of rendering one per link. Give the card an `id` and name it from each trigger with `for`. Each trigger takes a `payload` property, like its person, read when it connects, so set it before the trigger goes into the page. The card's `payloadchange` event carries it in `event.detail.value`; render the content from it there. Only the link that opened the card gets `data-open`. The card's `api.open({ payload })` opens it from code.
|
|
208
|
+
|
|
209
|
+
```html
|
|
210
|
+
<ui-hover-card id="profile">
|
|
211
|
+
<ui-hover-card-content hidden><p></p></ui-hover-card-content>
|
|
212
|
+
</ui-hover-card>
|
|
213
|
+
|
|
214
|
+
<script type="module">
|
|
215
|
+
const card = document.querySelector("#profile")
|
|
216
|
+
for (const person of people) {
|
|
217
|
+
const trigger = Object.assign(
|
|
218
|
+
document.createElement("ui-hover-card-trigger"),
|
|
219
|
+
{ payload: person }
|
|
220
|
+
)
|
|
221
|
+
trigger.setAttribute("for", "profile")
|
|
222
|
+
trigger.innerHTML = `<a href="${person.url}">${person.name}</a>`
|
|
223
|
+
feed.append(trigger)
|
|
224
|
+
}
|
|
225
|
+
card.addEventListener("payloadchange", (event) => {
|
|
226
|
+
card.querySelector("p").textContent = event.detail.value?.bio
|
|
227
|
+
})
|
|
228
|
+
</script>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
A card can have links of its own. Tab from a link with an open card moves into the card, and Tab past its end moves on to the page after the link. Focus leaving the card closes it.
|
|
232
|
+
|
|
233
|
+
## Container
|
|
234
|
+
|
|
235
|
+
Cards render in place and show in the top layer, so no ancestor clips or covers them. `container` renders the card somewhere else, named by a CSS selector, for iframes, shadow roots or a specific stacking context. See the shared [popup guide](../popups.md).
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<ui-hover-card-content container="#card-host" hidden></ui-hover-card-content>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Animation
|
|
242
|
+
|
|
243
|
+
The content has `data-starting-style` while it opens and `data-ending-style` while it closes. Transition from those states, and the card stays mounted until the exit finishes. `openchangecomplete` fires after the transition, and `keep-mounted` keeps the closed card in the page, hidden, for animation libraries that drive the exit from state.
|
|
244
|
+
|
|
245
|
+
```css
|
|
246
|
+
[data-slot="hover-card-content"] {
|
|
247
|
+
transition:
|
|
248
|
+
opacity 150ms,
|
|
249
|
+
scale 150ms;
|
|
250
|
+
|
|
251
|
+
&:is([data-starting-style], [data-ending-style]) {
|
|
252
|
+
opacity: 0;
|
|
253
|
+
scale: 0.96;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Custom Rendering
|
|
259
|
+
|
|
260
|
+
Elements have no render functions. The trigger wraps your own link, so the link can hold anything, like an avatar and a name. The link gets `data-open` while the card is open from it.
|
|
261
|
+
|
|
262
|
+
```html
|
|
263
|
+
<ui-hover-card-trigger>
|
|
264
|
+
<a href="/people/hollis">
|
|
265
|
+
<span aria-hidden="true">HG</span>
|
|
266
|
+
Hollis Grant
|
|
267
|
+
</a>
|
|
268
|
+
</ui-hover-card-trigger>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Styling
|
|
272
|
+
|
|
273
|
+
Each element has a `data-slot`, such as `hover-card-content`, and shows its state through the attributes listed under [Data Attributes](#data-attributes). Use `data-open` on the trigger's link to mark the link whose card is showing, and `data-side` to style the content and arrow for the side they landed on. Put `transform-origin: var(--transform-origin)` on the content so it scales from the link.
|
|
274
|
+
|
|
275
|
+
Keep overflow visible around an arrow that extends outside the card. If the body needs to scroll, put scrolling on an inner element.
|
|
276
|
+
|
|
277
|
+
### `<ui-hover-card-content>`
|
|
278
|
+
- `--anchor-width`: Width of the anchor, usually the trigger. Use it to match widths.
|
|
279
|
+
- `--anchor-height`: Height of the anchor.
|
|
280
|
+
- `--available-width`: Space beside the popup, up to the viewport edge. Not inherited either.
|
|
281
|
+
- `--available-height`: Space between the anchor and the viewport edge. Use it for max-height. Not inherited, so a child that needs it copies it on the popup, like `[--list-height:var(--available-height)]`, and reads `max-h-(--list-height)`. The first popup registers both names for the whole page with `CSS.registerProperty`, so they don't inherit anywhere. A page that needs them to inherit calls it first, with `inherits: true`. An `@property` rule can't, since a registration in script wins.
|
|
282
|
+
- `--transform-origin`: The point on the anchor the popup opens from. Use it to scale from the right place.
|
|
283
|
+
- `--arrow-offset`: Where the anchor's center falls along the popup's edge, kept `arrowPadding` from the corners. Position a ::before arrow with it.
|
|
284
|
+
|
|
285
|
+
## Data Attributes
|
|
286
|
+
|
|
287
|
+
### `<ui-hover-card-trigger>`
|
|
288
|
+
`[data-slot="hover-card-trigger"]`
|
|
289
|
+
|
|
290
|
+
- `data-closed`: Present while the card is closed, including while it animates out.
|
|
291
|
+
- `data-open`: Present while the card is open. On a trigger, while it's open from that trigger.
|
|
292
|
+
|
|
293
|
+
### `<ui-hover-card-content>`
|
|
294
|
+
`[data-slot="hover-card-content"]`
|
|
295
|
+
|
|
296
|
+
- `data-closed`: Present while the card is closed, including while it animates out.
|
|
297
|
+
- `data-open`: Present while the card is open. On a trigger, while it's open from that trigger.
|
|
298
|
+
- `data-starting-style`: Present for the first frame. Style the state you animate from.
|
|
299
|
+
- `data-ending-style`: Present while the card animates out. Style the state you animate to.
|
|
300
|
+
|
|
301
|
+
### `<ui-hover-card-arrow>`
|
|
302
|
+
`[data-slot="hover-card-arrow"]`
|
|
303
|
+
|
|
304
|
+
- `data-closed`: Present while the card is closed, including while it animates out.
|
|
305
|
+
- `data-open`: Present while the card is open. On a trigger, while it's open from that trigger.
|
|
306
|
+
|
|
307
|
+
## API Reference
|
|
308
|
+
|
|
309
|
+
Props are attributes in kebab case, like `close-delay` and `side-offset`: `"false"` is false, and numbers are numbers. `anchor` and `container` take CSS selectors, and `controller` is a property. Callbacks are DOM events.
|
|
310
|
+
|
|
311
|
+
### HoverCard
|
|
312
|
+
|
|
313
|
+
- `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
|
|
314
|
+
- `open?` (`boolean`): Whether the card is open. Pass it to control the card.
|
|
315
|
+
- `defaultOpen?` (`boolean`): Whether the card starts open, when uncontrolled.
|
|
316
|
+
- `openchange event`: Runs when the card wants to open or close. `details.reason` says why, and `details.cancel()` stops it.
|
|
317
|
+
- `openchangecomplete event`: Runs once the card has finished opening or closing, after any animation.
|
|
318
|
+
- `payloadchange event`: Runs when the payload the content shows changes: a trigger with another payload opens the card, or takes the open card over, which fires no `openchange`, and so does a controller's `open({ payload })` on the open card. `details.cancel()` keeps the previous payload.
|
|
319
|
+
- `delay?` (`number`): Milliseconds the pointer rests on the trigger, or keyboard focus stays on it, before the card opens.
|
|
320
|
+
- `closeDelay?` (`number`): Milliseconds before the card closes once the pointer leaves the trigger and the card.
|
|
321
|
+
- `disabled?` (`boolean`): Stops the card from opening. The trigger keeps working as a link.
|
|
322
|
+
- `controller?` (`PopupController<any, HoverCardOpenChangeReason, {}, string, HoverCardPayloadChangeReason>`): Opens, closes and inspects the card from anywhere, and connects triggers outside it. Create one with `createHoverCardController()`.
|
|
323
|
+
- `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.
|
|
324
|
+
|
|
325
|
+
### HoverCardTrigger
|
|
326
|
+
|
|
327
|
+
A trigger outside the card names it with `for="card-id"`, and takes `payload` as a property.
|
|
328
|
+
|
|
329
|
+
- `payload?` (`unknown`): Data for the content to render when this trigger opens the card, like the profile it links to.
|
|
330
|
+
- `controller?` (`PopupController<any, HoverCardOpenChangeReason, {}, string, HoverCardPayloadChangeReason>`): Connects a trigger outside the card, like every author link in a feed, to the card with this controller.
|
|
331
|
+
|
|
332
|
+
### HoverCardContent
|
|
333
|
+
|
|
334
|
+
- `side?` (`Side`): Which side of the anchor the popup opens on. Flips to the other side when there isn't room. Which side of the trigger the card opens on.
|
|
335
|
+
- `align?` (`Align`): How the popup lines up with the anchor along that side. `start` and `end` follow the reading direction. How the card lines up with the trigger along that side.
|
|
336
|
+
- `sideOffset?` (`number`): Gap between the anchor and the popup, in pixels. Gap between the trigger and the card, in pixels.
|
|
337
|
+
- `alignOffset?` (`number`): Shift along the anchor, in pixels. Shift along the trigger, in pixels.
|
|
338
|
+
- `collisionPadding?` (`number`): Space to keep from the viewport edges, in pixels.
|
|
339
|
+
- `arrowPadding?` (`number`): Space to keep between the arrow and the popup's corners, in pixels.
|
|
340
|
+
- `anchor?` (`string | Anchor | null`): Positions the popup against this instead of its trigger: an element, a CSS selector, a point like `{ x, y }`, or anything with `getBoundingClientRect()`. It's read on every check, so it can move. A controller's `open({ anchor })` wins for that open.
|
|
341
|
+
- `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
|
|
342
|
+
- `keepMounted?` (`boolean`): Whether the card stays in the page, hidden, while closed. For animation libraries that drive the exit from state.
|
|
343
|
+
|
|
344
|
+
### HoverCardArrow
|
|
345
|
+
|
|
346
|
+
Points at the link from the side the card landed on. `<ui-hover-card-arrow>` is positioned on the content's edge.
|
|
347
|
+
|
|
348
|
+
### State
|
|
349
|
+
|
|
350
|
+
The same state shows as data attributes on each element.
|
|
351
|
+
|
|
352
|
+
`HoverCardTrigger`:
|
|
353
|
+
|
|
354
|
+
- `open` (`boolean`): Whether the card is open from this trigger.
|
|
355
|
+
|
|
356
|
+
`HoverCardContent`:
|
|
357
|
+
|
|
358
|
+
- `open` (`boolean`): Whether the card is open. False while it animates out.
|
|
359
|
+
- `payload` (`Payload | undefined`): The payload of the last open, from the trigger that opened it or a controller, typed as the controller's `Payload`.
|
|
360
|
+
|
|
361
|
+
`HoverCardArrow`:
|
|
362
|
+
|
|
363
|
+
- `open` (`boolean`): Whether the card is open. False as soon as it starts closing, while it still animates out.
|
|
364
|
+
|
|
365
|
+
### Reasons
|
|
366
|
+
|
|
367
|
+
`event.detail.reason` says why the card opened or closed.
|
|
368
|
+
|
|
369
|
+
- `trigger-hover` (`PointerEvent`): The pointer rested on a trigger, or left it, with hover opening.
|
|
370
|
+
- `trigger-focus` (`FocusEvent`): Keyboard focus reached a trigger that opens on focus, like a tooltip's.
|
|
371
|
+
- `trigger-press` (`MouseEvent | KeyboardEvent | TouchEvent`): Click, tap, Enter or Space on the part that opens, closes or toggles. Arrow keys that open a menu or submenu count too. A tap on a combobox's input that opens a sheet reports its `touchend`.
|
|
372
|
+
- `focus-out` (`KeyboardEvent | FocusEvent`): Focus left the layer, or Tab moved it out.
|
|
373
|
+
- `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
|
|
374
|
+
- `close-press` (`MouseEvent | KeyboardEvent | SubmitEvent`): A Close part was pressed, or a form with `method="dialog"` was submitted.
|
|
375
|
+
- `outside-press` (`MouseEvent`): A press outside the layer.
|
|
376
|
+
- `window-blur` (`FocusEvent`): The window lost focus.
|
|
377
|
+
- `back` (`Event`): Going back: the Android back button or gesture, or Backspace in an empty command input, which returns to the previous page.
|
|
378
|
+
- `imperative` (`none`): A controller or `api` call, or a property set on a web component.
|
|
379
|
+
|
|
380
|
+
For a payload change, it says what opened the card or took it over.
|
|
381
|
+
|
|
382
|
+
- `trigger-hover` (`PointerEvent`): The pointer rested on a trigger, or left it, with hover opening.
|
|
383
|
+
- `trigger-focus` (`FocusEvent`): Keyboard focus reached a trigger that opens on focus, like a tooltip's.
|
|
384
|
+
- `trigger-press` (`MouseEvent | KeyboardEvent | TouchEvent`): Click, tap, Enter or Space on the part that opens, closes or toggles. Arrow keys that open a menu or submenu count too. A tap on a combobox's input that opens a sheet reports its `touchend`.
|
|
385
|
+
- `imperative` (`none`): A controller or `api` call, or a property set on a web component.
|
|
386
|
+
|
|
387
|
+
### Controller
|
|
388
|
+
|
|
389
|
+
Create one with `createHoverCardController<Payload>()` from `@ui-sdk/web/hover-card` and assign it to the root
|
|
390
|
+
element's `controller` property. The root element's `api` property has the same methods, and its `open` property reads
|
|
391
|
+
and sets whether the card is open. `Payload` is the type of the data triggers and `open()` pass.
|
|
392
|
+
|
|
393
|
+
Every write method takes an optional `{ reason, event }`, passed to `openchange`.
|
|
394
|
+
|
|
395
|
+
- `isOpen()` (`() => boolean`): Whether it's open. False as soon as it starts closing, while it still animates out.
|
|
396
|
+
- `setOpen(open, options?)` (`(open: boolean, options?: PopupChangeOptions<HoverCardOpenChangeReason> | undefined) => boolean`): Opens or closes it. Returns false when the change was canceled or it was already open or closed.
|
|
397
|
+
- `open(options?)` (`(options?: (PopupChangeOptions<HoverCardPayloadChangeReason> & { payload?: Payload | undefined; anchor?: Anchor | undefined; signal?: AbortSignal | undefined; }) | undefined) => Promise<...>`): Opens it, and resolves once it closes, with why, how and any return value. Resolves exactly once and never rejects: on the next close from any source, when `signal` aborts, or with reason `"unmount"` when the component leaves the page.
|
|
398
|
+
- `close(options?)` (`(options?: (PopupChangeOptions<HoverCardOpenChangeReason> & { returnValue?: string | undefined; }) | undefined) => boolean`): Closes it. `returnValue` is passed to the promise `open()` returned. Returns false when the close was canceled or it was already closed.
|
|
399
|
+
- `toggle(options?)` (`(options?: PopupChangeOptions<HoverCardOpenChangeReason> | undefined) => boolean`): Opens it when it's closed, and closes it when it's open. Returns false when the change was canceled.
|
|
400
|
+
- `getPayload()` (`() => Payload | undefined`): The payload of the last open, from a controller or the trigger that opened it.
|
|
401
|
+
- `focus()` (`() => void`): Moves focus to the trigger that opened it last, or the first trigger.
|
|
402
|
+
|
|
403
|
+
### Events
|
|
404
|
+
|
|
405
|
+
Events fire on their own element and don't bubble, with the new state in `event.detail.value` and the `reason` and `event` beside it. Calling `preventDefault()` on `openchange` cancels the change.
|
|
406
|
+
|
|
407
|
+
| Member | On | Description |
|
|
408
|
+
| -------------------------- | ----------------------- | ------------------------------------------------------------------------------- |
|
|
409
|
+
| `open` property, attribute | `ui-hover-card` | Whether the card is open. The attribute sets where it starts, and is live |
|
|
410
|
+
| `api` property | `ui-hover-card` | The [controller](#controller) |
|
|
411
|
+
| `controller` property | `ui-hover-card` | A controller from `createHoverCardController()`, to drive it from code |
|
|
412
|
+
| `openchange` event | `ui-hover-card` | `detail: { value: open, reason, event }` |
|
|
413
|
+
| `openchangecomplete` event | `ui-hover-card` | `detail: { value: open }`, after the animation |
|
|
414
|
+
| `payloadchange` event | `ui-hover-card` | `detail: { value: payload, reason, event }`, when the content's payload changes |
|
|
415
|
+
| `payload` property | `ui-hover-card-trigger` | Data for the content, read when the trigger connects |
|
|
416
|
+
| `for` attribute | `ui-hover-card-trigger` | The `id` of a card the trigger opens from outside it |
|
|
417
|
+
|
|
418
|
+
## Accessibility
|
|
419
|
+
|
|
420
|
+
The trigger stays a plain link, and the card is a preview beside it, not a dialog. Every line below is an automated test.
|
|
421
|
+
|
|
422
|
+
### Keyboard
|
|
423
|
+
|
|
424
|
+
| Key | Does |
|
|
425
|
+
| ------ | ---------------------------------------------------------------------------- |
|
|
426
|
+
| Tab | On the link, opens the card after `delay`; with the card open, moves into it |
|
|
427
|
+
| Enter | Follows the link |
|
|
428
|
+
| Escape | Closes the card and leaves focus on the link |
|
|
429
|
+
|
|
430
|
+
Keyboard focus opens the card after the same `delay` as the pointer, so tabbing through a page of links doesn't flash a card at every stop. Focus leaving the card closes it.
|
|
431
|
+
|
|
432
|
+
Touch screens have no hover, so a tap follows the link without opening the card. Anything in the card should be on the page the link goes to.
|
|
433
|
+
|
|
434
|
+
### Tested Behavior
|
|
435
|
+
|
|
436
|
+
**Pointer**
|
|
437
|
+
|
|
438
|
+
- Resting the pointer on the link opens the card.
|
|
439
|
+
- The card waits for its delay before opening.
|
|
440
|
+
- Moving the pointer away closes the card after its close delay.
|
|
441
|
+
- Moving the pointer into the card keeps it open.
|
|
442
|
+
- Opening on hover leaves focus where it was.
|
|
443
|
+
- Clicking the link follows it.
|
|
444
|
+
|
|
445
|
+
**Keyboard**
|
|
446
|
+
|
|
447
|
+
- Keyboard focus on the link opens the card after the delay.
|
|
448
|
+
- Escape closes the card and leaves focus on the link.
|
|
449
|
+
- Enter follows the link.
|
|
450
|
+
|
|
451
|
+
**Positioning**
|
|
452
|
+
|
|
453
|
+
- The card opens below the link.
|
|
454
|
+
- The card opens on the requested side.
|
|
455
|
+
|
|
456
|
+
**Animation**
|
|
457
|
+
|
|
458
|
+
- The card animates in from its starting style.
|
|
459
|
+
- The card stays in the page while it animates out.
|
|
460
|
+
|
|
461
|
+
**Focus, touch and reasons**
|
|
462
|
+
|
|
463
|
+
- A click that focuses the link doesn't open the card from focus.
|
|
464
|
+
- Leaving the link before the delay keeps keyboard focus from opening it later.
|
|
465
|
+
- A tap follows the link without opening the card.
|
|
466
|
+
- Changes report why the card opened and closed.
|
|
467
|
+
|
|
468
|
+
Runs in React, Vue and web components.
|
|
469
|
+
|
|
470
|
+
Also tested:
|
|
471
|
+
|
|
472
|
+
**Enhancements**
|
|
473
|
+
|
|
474
|
+
- Tab from the link moves into the open card.
|
|
475
|
+
- Shift+Tab from the card returns to the link.
|
|
476
|
+
- Tab out of the card moves on past the link and closes it.
|
|
477
|
+
- Escape inside the card closes it and returns focus to the link.
|
|
478
|
+
- The card stays open while focus is in it, even when the pointer leaves.
|
|
479
|
+
|
|
480
|
+
Runs in React, Vue and web components.
|
|
481
|
+
|
|
482
|
+
Screen readers hear the same thing in each tested framework, recorded by a virtual screen reader:
|
|
483
|
+
|
|
484
|
+
- Announcements while tabbing into the card and out.
|
|
485
|
+
|
|
486
|
+
Runs in React, Vue and web components.
|