@ahrowe/ui 0.32.0 → 0.34.0
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/dist/esm/common/actionIcon/actionIcon.module.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.module.mjs.map +1 -1
- package/dist/esm/common/card/Card.mjs +1 -1
- package/dist/esm/common/card/Card.mjs.map +1 -1
- package/dist/esm/common/card/card.types.mjs.map +1 -1
- package/dist/esm/common/chip/chip.mjs +1 -1
- package/dist/esm/common/chip/chip.mjs.map +1 -1
- package/dist/esm/common/chip/chip.types.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
- package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
- package/dist/esm/common/configProvider/presentation.types.mjs +2 -0
- package/dist/esm/common/configProvider/presentation.types.mjs.map +1 -0
- package/dist/esm/common/configProvider/usePresentationDefault.mjs.map +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs.map +1 -1
- package/dist/esm/common/datePicker/datePicker.mjs +1 -1
- package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
- package/dist/esm/common/drawer/drawer.mjs +1 -1
- package/dist/esm/common/drawer/drawer.mjs.map +1 -1
- package/dist/esm/common/dropdown/dropdown.mjs +1 -1
- package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
- package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
- package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
- package/dist/esm/common/fab/fab.mjs +1 -1
- package/dist/esm/common/fab/fab.mjs.map +1 -1
- package/dist/esm/common/hooks/useAnchorTracking.mjs.map +1 -1
- package/dist/esm/common/hooks/useFocusBoundary.mjs +1 -1
- package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -1
- package/dist/esm/common/hooks/useSheet.mjs +1 -1
- package/dist/esm/common/hooks/useSheet.mjs.map +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -1
- package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
- package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
- package/dist/esm/common/menu/menu.mjs +2 -0
- package/dist/esm/common/menu/menu.mjs.map +1 -0
- package/dist/esm/common/menu/menu.module.mjs +2 -0
- package/dist/esm/common/menu/menu.module.mjs.map +1 -0
- package/dist/esm/common/menu/menu.types.mjs +2 -0
- package/dist/esm/common/menu/menu.types.mjs.map +1 -0
- package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
- package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
- package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
- package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
- package/dist/esm/common/numberInput/numberInput.mjs +1 -1
- package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
- package/dist/esm/common/popover/popover.mjs +1 -1
- package/dist/esm/common/popover/popover.mjs.map +1 -1
- package/dist/esm/common/popover/popover.module.mjs +1 -1
- package/dist/esm/common/popover/popover.module.mjs.map +1 -1
- package/dist/esm/common/popover/popover.types.mjs.map +1 -1
- package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
- package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
- package/dist/esm/common/progressBar/progressBar.mjs +1 -1
- package/dist/esm/common/progressBar/progressBar.mjs.map +1 -1
- package/dist/esm/common/searchInput/searchInput.mjs +1 -1
- package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.module.mjs +1 -1
- package/dist/esm/common/splitButton/splitButton.module.mjs.map +1 -1
- package/dist/esm/common/timeInput/timeInput.mjs +1 -1
- package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
- package/dist/esm/common/toast/toast.module.mjs.map +1 -1
- package/dist/esm/common/tooltip/tooltip.mjs +1 -1
- package/dist/esm/common/tooltip/tooltip.mjs.map +1 -1
- package/dist/esm/common/tooltip/tooltip.module.mjs +1 -1
- package/dist/esm/common/tooltip/tooltip.module.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
- package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
- package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/common/card/card.types.d.ts +6 -1
- package/dist/types/common/chip/chip.types.d.ts +6 -1
- package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
- package/dist/types/common/colorPicker/colorPicker.types.d.ts +6 -1
- package/dist/types/common/configProvider/configProvider.d.ts +1 -1
- package/dist/types/common/configProvider/configProvider.types.d.ts +6 -3
- package/dist/types/common/configProvider/index.d.ts +1 -0
- package/dist/types/common/configProvider/presentation.types.d.ts +14 -0
- package/dist/types/common/configProvider/usePresentationDefault.d.ts +1 -1
- package/dist/types/common/confirmModal/confirmModal.types.d.ts +4 -2
- package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +1 -1
- package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +3 -0
- package/dist/types/common/datePicker/datePicker.types.d.ts +11 -2
- package/dist/types/common/drawer/drawer.d.ts +1 -1
- package/dist/types/common/drawer/drawer.types.d.ts +7 -1
- package/dist/types/common/dropdown/dropdown.types.d.ts +7 -7
- package/dist/types/common/emptyState/emptyState.d.ts +1 -1
- package/dist/types/common/emptyState/emptyState.types.d.ts +6 -1
- package/dist/types/common/fab/components/fabBase/fabBase.d.ts +1 -1
- package/dist/types/common/fab/components/fabBase/fabBase.types.d.ts +3 -1
- package/dist/types/common/fab/fab.d.ts +1 -1
- package/dist/types/common/fab/fab.types.d.ts +6 -1
- package/dist/types/common/hooks/useAnchorTracking.d.ts +1 -1
- package/dist/types/common/hooks/useFocusBoundary.d.ts +3 -3
- package/dist/types/common/hooks/useSheet.d.ts +1 -1
- package/dist/types/common/infiniteBlock/infiniteBlock.d.ts +1 -1
- package/dist/types/common/infiniteBlock/infiniteBlock.types.d.ts +2 -0
- package/dist/types/common/menu/index.d.ts +2 -0
- package/dist/types/common/menu/menu.d.ts +14 -0
- package/dist/types/common/menu/menu.types.d.ts +55 -0
- package/dist/types/common/modal/modal.types.d.ts +1 -1
- package/dist/types/common/multiSelect/multiSelect.types.d.ts +1 -1
- package/dist/types/common/numberInput/numberInput.types.d.ts +6 -0
- package/dist/types/common/popover/popover.types.d.ts +34 -3
- package/dist/types/common/popover/usePopoverPosition.d.ts +20 -1
- package/dist/types/common/progressBar/progressBar.d.ts +1 -1
- package/dist/types/common/progressBar/progressBar.types.d.ts +6 -1
- package/dist/types/common/searchInput/searchInput.d.ts +1 -1
- package/dist/types/common/searchInput/searchInput.types.d.ts +13 -1
- package/dist/types/common/splitButton/splitButton.types.d.ts +3 -3
- package/dist/types/index.d.ts +2 -2
- package/docs/Breadcrumb.md +2 -2
- package/docs/ButtonGroup.md +1 -1
- package/docs/CLAUDE.md +1 -1
- package/docs/Card.md +3 -1
- package/docs/Chip.md +2 -0
- package/docs/ColorPicker.md +4 -0
- package/docs/ConfigProvider.md +2 -2
- package/docs/DatePicker.md +4 -0
- package/docs/Drawer.md +2 -0
- package/docs/Dropdown.md +3 -1
- package/docs/EmptyState.md +2 -0
- package/docs/Fab.md +2 -0
- package/docs/InputDropdown.md +1 -1
- package/docs/InteractableDiv.md +2 -0
- package/docs/Menu.md +107 -0
- package/docs/Modal.md +1 -1
- package/docs/NumberInput.md +4 -0
- package/docs/Popover.md +11 -5
- package/docs/ProgressBar.md +2 -0
- package/docs/SearchInput.md +4 -0
- package/docs/SplitButton.md +8 -4
- package/docs/ThemeProvider.md +1 -1
- package/docs/VirtualList.md +2 -2
- package/package.json +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.mjs +0 -2
- package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +0 -1
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs +0 -2
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +0 -1
- package/dist/esm/common/floatingMenu/floatingMenu.types.mjs +0 -2
- package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +0 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +0 -2
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +0 -1
- package/dist/types/common/floatingMenu/floatingMenu.d.ts +0 -3
- package/dist/types/common/floatingMenu/floatingMenu.types.d.ts +0 -32
- package/dist/types/common/floatingMenu/index.d.ts +0 -2
- package/dist/types/common/floatingMenu/useFloatingPosition.d.ts +0 -27
- package/docs/FloatingMenu.md +0 -90
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { type RefObject } from 'react';\nimport { isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\nimport { useAnchorTracking } from '../hooks/useAnchorTracking';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: flips above the\n * trigger when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * `useAnchorTracking` supplies the lifecycle around this: mount wait, ancestor resolution, and\n * re-running on scroll, viewport resize and panel size changes.\n */\nexport function useFloatingPosition({\n isOpen,\n triggerRef,\n anchorRef,\n panelRef,\n flipClassName,\n placement = 'bottom',\n}: UseFloatingPositionArgs) {\n useAnchorTracking({\n isOpen,\n triggerRef,\n elementRefs: [anchorRef],\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown) but not for\n // a zero-height wrapper whose content sits inside it (FloatingMenu).\n resizeRefs: [anchorRef, panelRef],\n deps: [anchorRef, panelRef, flipClassName, placement],\n\n update: (trigger, ancestors) => {\n const anchor = anchorRef.current;\n if (!anchor) return;\n\n const rect = trigger.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n // open, so flip/clamp react to what's actually on screen instead of the keyboard hiding\n // a panel that \"fit\" against the unshrunk layout viewport.\n const vv = getVisualViewportRect();\n const spaceBelow = vv.top + vv.height - rect.bottom;\n const spaceAbove = rect.top - vv.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor.style.top = `${renderAbove ? rect.top - anchor.offsetHeight : rect.bottom}px`;\n anchor.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (vv.left + vv.width - EDGE_MARGIN);\n const overflowLeft = vv.left + EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n },\n\n teardown: () => {\n // Positioning is written as inline styles, which outrank any class the popup might switch\n // to while it stays mounted — a popup turning into a bottom sheet (`useSheet`) would keep\n // the coordinates computed for its anchored self. Hand the element back as we found it.\n const anchor = anchorRef.current;\n if (!anchor) return;\n anchor.style.top = '';\n anchor.style.left = '';\n anchor.style.visibility = '';\n anchor.classList.remove(flipClassName);\n },\n });\n}\n"],"mappings":"4MAoBA,IAAM,EAAc,EAcpB,SAAgB,EAAoB,CAClC,SACA,aACA,YACA,WACA,gBACA,YAAY,UACc,CAC1B,EAAkB,CAChB,SACA,aACA,YAAa,CAAC,CAAS,EAGvB,WAAY,CAAC,EAAW,CAAQ,EAChC,KAAM,CAAC,EAAW,EAAU,EAAe,CAAS,EAEpD,QAAS,EAAS,IAAc,CAC9B,IAAM,EAAS,EAAU,QACzB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAO,EAAQ,sBAAsB,EACrC,EAAc,EAAS,SAAS,cAAgB,EAIhD,EAAK,EAAsB,EAC3B,EAAa,EAAG,IAAM,EAAG,OAAS,EAAK,OACvC,EAAa,EAAK,IAAM,EAAG,IAC3B,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAO,UAAU,OAAO,EAAe,CAAI,EAK3C,EAAO,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAO,aAAe,EAAK,OAAO,IACjF,EAAO,MAAM,KAAO,GAAG,EAAK,KAAK,IAQjC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,EAAG,KAAO,EAAG,MAAQ,GACnD,EAAe,EAAG,KAAO,EAAc,EACzC,EAAgB,EAClB,EAAO,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACxC,EAAe,IACxB,EAAO,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAEpD,CAEA,EAAO,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,EAChF,EAEA,aAAgB,CAId,IAAM,EAAS,EAAU,QACpB,IACL,EAAO,MAAM,IAAM,GACnB,EAAO,MAAM,KAAO,GACpB,EAAO,MAAM,WAAa,GAC1B,EAAO,UAAU,OAAO,CAAa,EACvC,CACF,CAAC,CACH"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
-
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
3
|
-
/** How a surface is presented on screen. */
|
|
4
|
-
export declare enum Presentation {
|
|
5
|
-
/** Wherever the component normally puts it: anchored to its trigger, or centred for a Modal. */
|
|
6
|
-
Default = "default",
|
|
7
|
-
/** Pinned to the bottom of the screen, full width up to a maximum. */
|
|
8
|
-
Sheet = "sheet",
|
|
9
|
-
/** A sheet on touch devices with a small screen, anchored everywhere else. */
|
|
10
|
-
Auto = "auto"
|
|
11
|
-
}
|
|
12
|
-
export declare enum Align {
|
|
13
|
-
Left = "left",
|
|
14
|
-
Right = "right",
|
|
15
|
-
Center = "center"
|
|
16
|
-
}
|
|
17
|
-
export type FloatingMenuSlots = 'root' | 'trigger' | 'menu' | 'menuContainer' | 'backdrop';
|
|
18
|
-
export interface FloatingMenuProps extends Omit<HtmlProps, 'content'> {
|
|
19
|
-
align?: Align;
|
|
20
|
-
children?: ReactNode;
|
|
21
|
-
content?: ReactNode;
|
|
22
|
-
isOpen?: boolean;
|
|
23
|
-
onOpenChange?: (isOpen: boolean) => void;
|
|
24
|
-
dontCloseOnChildClick?: boolean;
|
|
25
|
-
/** Where the menu opens: anchored to the trigger (`Default`), pinned to the bottom of the
|
|
26
|
-
* screen, or the latter only on a small touch screen. */
|
|
27
|
-
presentation?: Presentation;
|
|
28
|
-
className?: string;
|
|
29
|
-
style?: CSSProperties;
|
|
30
|
-
classNames?: SlotClassNames<FloatingMenuSlots>;
|
|
31
|
-
styles?: SlotStyles<FloatingMenuSlots>;
|
|
32
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
export interface UseFloatingPositionArgs {
|
|
3
|
-
isOpen: boolean;
|
|
4
|
-
/** The element the popup is anchored to. */
|
|
5
|
-
triggerRef: RefObject<HTMLElement | null>;
|
|
6
|
-
/** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */
|
|
7
|
-
anchorRef: RefObject<HTMLElement | null>;
|
|
8
|
-
/** The visible panel whose height decides whether there's room to render on the preferred side. */
|
|
9
|
-
panelRef: RefObject<HTMLElement | null>;
|
|
10
|
-
/** Class toggled on `anchorRef` when flipped to the non-preferred side. */
|
|
11
|
-
flipClassName: string;
|
|
12
|
-
/** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */
|
|
13
|
-
placement?: 'top' | 'bottom';
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Keeps a portaled, `position: fixed` popup anchored to a trigger element: flips above the
|
|
17
|
-
* trigger when there's no room below, and hides (not closes) the popup when the trigger itself
|
|
18
|
-
* scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.
|
|
19
|
-
* It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS
|
|
20
|
-
* only positions the panel relative to the anchor's own box and has no awareness of where
|
|
21
|
-
* that box actually sits on screen, so a trigger near a screen edge would otherwise let the
|
|
22
|
-
* panel overflow it with no correction.
|
|
23
|
-
*
|
|
24
|
-
* `useAnchorTracking` supplies the lifecycle around this: mount wait, ancestor resolution, and
|
|
25
|
-
* re-running on scroll, viewport resize and panel size changes.
|
|
26
|
-
*/
|
|
27
|
-
export declare function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement, }: UseFloatingPositionArgs): void;
|
package/docs/FloatingMenu.md
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# FloatingMenu
|
|
2
|
-
|
|
3
|
-
**When to use:** Contextual popover triggered by any element — action menus, dropdowns with custom content, "more options" menus, date pickers, colour swatches.
|
|
4
|
-
|
|
5
|
-
**Keywords:** context menu, dropdown menu, bottom sheet, action sheet, mobile, touch
|
|
6
|
-
|
|
7
|
-
**Import:** `import { FloatingMenu } from '@ahrowe/ui'`
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
import { FloatingMenu, Align } from '@ahrowe/ui';
|
|
11
|
-
|
|
12
|
-
// Basic — children is the trigger, content is the popover body
|
|
13
|
-
<FloatingMenu
|
|
14
|
-
content={
|
|
15
|
-
<ul>
|
|
16
|
-
<li onClick={handleEdit}>Edit</li>
|
|
17
|
-
<li onClick={handleDelete}>Delete</li>
|
|
18
|
-
</ul>
|
|
19
|
-
}
|
|
20
|
-
>
|
|
21
|
-
<button>More ▾</button>
|
|
22
|
-
</FloatingMenu>
|
|
23
|
-
|
|
24
|
-
// Controlled open state
|
|
25
|
-
<FloatingMenu
|
|
26
|
-
isOpen={isMenuOpen}
|
|
27
|
-
onOpenChange={setIsMenuOpen}
|
|
28
|
-
align={Align.Right}
|
|
29
|
-
content={<MenuContent />}
|
|
30
|
-
>
|
|
31
|
-
<ActionIcon icon={faEllipsis} />
|
|
32
|
-
</FloatingMenu>
|
|
33
|
-
|
|
34
|
-
// Keep open through several interactions with content — a column-visibility toggle where
|
|
35
|
-
// checking one box shouldn't close the whole menu — or when re-clicking the trigger itself
|
|
36
|
-
// (e.g. DatePicker re-clicking its own input) shouldn't close it either
|
|
37
|
-
<FloatingMenu dontCloseOnChildClick content={<Form />}>
|
|
38
|
-
<button>Open form</button>
|
|
39
|
-
</FloatingMenu>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
import { FloatingMenu, Presentation } from '@ahrowe/ui';
|
|
44
|
-
|
|
45
|
-
// On a small touch screen the menu becomes a bottom sheet instead of a popover anchored to
|
|
46
|
-
// the trigger; everywhere else it stays anchored.
|
|
47
|
-
<FloatingMenu presentation={Presentation.Auto} content={<MenuContent />}>
|
|
48
|
-
<button>More ▾</button>
|
|
49
|
-
</FloatingMenu>
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Align enum:** `Align.Left` | `Align.Right` | `Align.Center`
|
|
53
|
-
|
|
54
|
-
**Presentation enum:** `Presentation.Default` (anchored to the trigger) | `Presentation.Sheet` | `Presentation.Auto`
|
|
55
|
-
|
|
56
|
-
**Key props:**
|
|
57
|
-
|
|
58
|
-
| Prop | Type | Description |
|
|
59
|
-
|------|------|-------------|
|
|
60
|
-
| `content` | `ReactNode` | Popover body |
|
|
61
|
-
| `children` | `ReactNode` | Trigger element |
|
|
62
|
-
| `align` | `Align` | Popover alignment relative to trigger |
|
|
63
|
-
| `isOpen` | `boolean` | Controlled open state |
|
|
64
|
-
| `onOpenChange` | `(isOpen: boolean) => void` | Open state change callback |
|
|
65
|
-
| `dontCloseOnChildClick` | `boolean` | Keep the menu open when its own content is clicked, and when the trigger itself is re-clicked while already open (default `false`) |
|
|
66
|
-
| `presentation` | `Presentation` | Where the menu opens: anchored to the trigger (`Default`), always a bottom sheet, or a sheet only on a small touch screen |
|
|
67
|
-
|
|
68
|
-
**Slots:** `root` `trigger` `menu` `menuContainer` `backdrop` (`backdrop` only exists while presenting as a sheet)
|
|
69
|
-
|
|
70
|
-
**Bottom sheet:** with `Presentation.Sheet` the menu leaves its trigger entirely: it pins to the bottom of the screen, spans the full width up to 560px, scrolls internally past 70% of the viewport height, and dims the page behind a backdrop. Scrolling on the page behind it is locked while it's open, Escape closes it even when focus never entered it, and it lifts itself above an open on-screen keyboard, shrinking to fit the space that leaves rather than running off the top of the screen. Tapping the backdrop closes the sheet and nothing else: the tap is consumed by the backdrop rather than falling through to whatever sits behind it. `Presentation.Auto` applies that only when the pointer is coarse *and* the screen is under 768px wide: pointer alone would catch touchscreen laptops, width alone would catch a narrow desktop window. Set it once for a whole app via `ConfigProvider`:
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
<ConfigProvider defaultProps={{ FloatingMenu: { presentation: Presentation.Auto } }}>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
To set it for every sheet-capable component at once, use `ConfigProvider`'s own `presentation` prop instead of the four component-keyed entries — see [ConfigProvider.md](ConfigProvider.md).
|
|
77
|
-
|
|
78
|
-
The default stays `Presentation.Default`, so nothing changes for an existing app until it opts in.
|
|
79
|
-
|
|
80
|
-
**What that one setting covers.** Every component whose popup *is* a `FloatingMenu` inherits the default above, with no prop of its own: `SplitButton`'s action menu, `ColorPicker`'s picker, `Breadcrumb`'s collapsed-crumb menu, `VirtualList`'s column-visibility menu, and `DatePicker`/`TimeInput`/`KlipyPicker` when they're not already using their own `isModal`. To make one instance differ, wrap it in a nested `ConfigProvider`, which overrides only the keys it sets.
|
|
81
|
-
|
|
82
|
-
`Dropdown`, `Popover` and `Modal` place their surfaces themselves rather than through `FloatingMenu`, so each takes its own `presentation` prop and its own `ConfigProvider` key (`Modal`'s covers `DatePicker`/`TimeInput`/`KlipyPicker` in their `isModal` mode). `InputDropdown` and `Tooltip` also position themselves and deliberately have no sheet mode: a typeahead's list belongs next to the text being typed, and a tooltip is a pointer hint, not a screen-owning panel.
|
|
83
|
-
|
|
84
|
-
**Positioning:** the menu is portaled and tracks the trigger across scroll and resize, flipping above it when there's no room below. It re-measures whenever `content` changes size while open, so a menu holding a list that grows or shrinks (filtering, async loading) stays anchored to the trigger and re-evaluates whether it still needs to open upward. It's also shifted horizontally to stay within the viewport — a trigger near the left or right edge of the screen no longer lets the menu overflow off-screen, regardless of `align`.
|
|
85
|
-
|
|
86
|
-
**Closing behaviour:** by default, clicking anywhere in `content` closes the menu — including inside a nested overlay that renders through its own portal (e.g. a `Dropdown` or another `FloatingMenu` used inside `content`), even though that overlay's DOM lives outside `content`'s own subtree. Re-clicking the trigger while open is a clean toggle: it closes the menu (unless `dontCloseOnChildClick` is set, in which case it's a no-op — the trigger owns its own open/close entirely, so it never fights with an outside-click check). Set `dontCloseOnChildClick` when `content` needs several interactions before the user is done (a multi-checkbox toggle, a color picker's slider, a calendar) — the consumer is then responsible for closing explicitly, e.g. calling `onOpenChange(false)` from the handler that reacts to a final selection.
|
|
87
|
-
|
|
88
|
-
**Keyboard:** the menu is portaled to the end of the DOM, so Tab can't reach it in visual order on its own. Escape closes the menu and, when focus is inside it, returns focus to the trigger — it works wherever focus currently is, including on the trigger itself. When `content` has real focusable elements, Tab past the last focusable element (or Shift+Tab past the first) closes the menu and continues focus as if it sat right after the trigger. This doesn't include auto-focusing the first element on open — content ranges from menus to live controls (e.g. `ColorPicker`'s hue slider), where grabbing focus on open would let a stray arrow-key press change a value the user never touched. A consumer that wants that (like `SplitButton` focusing its first enabled action) implements it itself.
|
|
89
|
-
|
|
90
|
-
**Nesting inside a Modal:** an open menu registers itself as the layer above whatever it was opened from, so a menu inside a `Modal` behaves the way it looks: Escape closes the menu and leaves the modal open (a second press closes the modal), and the modal's focus trap leaves focus alone while the menu has it. Both matter because the menu is portaled, so its DOM is a sibling of the modal's panel rather than a descendant, and neither DOM position nor mount order says which one is on top. The same applies to `Dropdown` and `Popover`.
|