@allxsmith/bestax-bulma 5.27.8 → 5.29.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/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/Dialog.js +8 -4
- package/dist/esm/components/Dialog.js.map +1 -1
- package/dist/esm/components/HoverCard.js +127 -0
- package/dist/esm/components/HoverCard.js.map +1 -0
- package/dist/esm/components/Modal.js +19 -11
- package/dist/esm/components/Modal.js.map +1 -1
- package/dist/esm/components/Popover.js.map +1 -1
- package/dist/esm/components/Sidebar.js +12 -3
- package/dist/esm/components/Sidebar.js.map +1 -1
- package/dist/esm/components/Toast.js +5 -3
- package/dist/esm/components/Toast.js.map +1 -1
- package/dist/esm/elements/Notification.js +3 -1
- package/dist/esm/elements/Notification.js.map +1 -1
- package/dist/esm/form/DateInput.js.map +1 -1
- package/dist/esm/form/DateInputBase.js.map +1 -1
- package/dist/esm/form/DateRangeInputBase.js.map +1 -1
- package/dist/esm/form/DateTimeInput.js.map +1 -1
- package/dist/esm/form/DateTimeInputBase.js.map +1 -1
- package/dist/esm/form/Field.js.map +1 -1
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/Input.js.map +1 -1
- package/dist/esm/form/Numberinput.js.map +1 -1
- package/dist/esm/form/Select.js.map +1 -1
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/TextArea.js.map +1 -1
- package/dist/esm/form/TimeInput.js.map +1 -1
- package/dist/esm/form/TimeInputBase.js.map +1 -1
- package/dist/esm/form/_pickerInternals/PickerPopover.js +3 -1
- package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -1
- package/dist/esm/helpers/Config.js +5 -2
- package/dist/esm/helpers/Config.js.map +1 -1
- package/dist/esm/helpers/portal.js +30 -5
- package/dist/esm/helpers/portal.js.map +1 -1
- package/dist/esm/helpers/useFocusTrap.js +2 -1
- package/dist/esm/helpers/useFocusTrap.js.map +1 -1
- package/dist/esm/helpers/useHoverOpen.js +390 -0
- package/dist/esm/helpers/useHoverOpen.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +574 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/HoverCard.d.ts +138 -0
- package/dist/types/components/Modal.d.ts +2 -1
- package/dist/types/components/Popover.d.ts +8 -7
- package/dist/types/form/DateInput.d.ts +1 -1
- package/dist/types/form/DateInputBase.d.ts +4 -1
- package/dist/types/form/DateRangeInputBase.d.ts +4 -1
- package/dist/types/form/DateTimeInput.d.ts +1 -1
- package/dist/types/form/DateTimeInputBase.d.ts +4 -1
- package/dist/types/form/Field.d.ts +1 -1
- package/dist/types/form/File.d.ts +1 -1
- package/dist/types/form/Input.d.ts +1 -1
- package/dist/types/form/Numberinput.d.ts +1 -1
- package/dist/types/form/Select.d.ts +1 -1
- package/dist/types/form/Slider.d.ts +1 -1
- package/dist/types/form/Taginput.d.ts +1 -1
- package/dist/types/form/TextArea.d.ts +1 -1
- package/dist/types/form/TimeInput.d.ts +1 -1
- package/dist/types/form/TimeInputBase.d.ts +2 -1
- package/dist/types/helpers/Config.d.ts +34 -3
- package/dist/types/helpers/portal.d.ts +27 -5
- package/dist/types/helpers/useFocusTrap.d.ts +9 -0
- package/dist/types/helpers/useHoverOpen.d.ts +98 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types-cjs/components/HoverCard.d.ts +138 -0
- package/dist/types-cjs/components/Modal.d.ts +2 -1
- package/dist/types-cjs/components/Popover.d.ts +8 -7
- package/dist/types-cjs/form/DateInput.d.ts +1 -1
- package/dist/types-cjs/form/DateInputBase.d.ts +4 -1
- package/dist/types-cjs/form/DateRangeInputBase.d.ts +4 -1
- package/dist/types-cjs/form/DateTimeInput.d.ts +1 -1
- package/dist/types-cjs/form/DateTimeInputBase.d.ts +4 -1
- package/dist/types-cjs/form/Field.d.ts +1 -1
- package/dist/types-cjs/form/File.d.ts +1 -1
- package/dist/types-cjs/form/Input.d.ts +1 -1
- package/dist/types-cjs/form/Numberinput.d.ts +1 -1
- package/dist/types-cjs/form/Select.d.ts +1 -1
- package/dist/types-cjs/form/Slider.d.ts +1 -1
- package/dist/types-cjs/form/Taginput.d.ts +1 -1
- package/dist/types-cjs/form/TextArea.d.ts +1 -1
- package/dist/types-cjs/form/TimeInput.d.ts +1 -1
- package/dist/types-cjs/form/TimeInputBase.d.ts +2 -1
- package/dist/types-cjs/helpers/Config.d.ts +34 -3
- package/dist/types-cjs/helpers/portal.d.ts +27 -5
- package/dist/types-cjs/helpers/useFocusTrap.d.ts +9 -0
- package/dist/types-cjs/helpers/useHoverOpen.d.ts +98 -0
- package/dist/types-cjs/index.d.ts +1 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +2 -2
- package/src/scss/components/_hovercard.scss +118 -0
- package/src/scss/components/_index.scss +1 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BulmaClassesProps } from '../helpers/useBulmaClasses.js';
|
|
3
|
+
import type { PickerPosition } from '../form/_pickerInternals/pickerTypes.js';
|
|
4
|
+
/**
|
|
5
|
+
* Where the card opens against its trigger: below (`bottom-*`) or above
|
|
6
|
+
* (`top-*`), lined up with the trigger's left or right edge. `auto` picks the
|
|
7
|
+
* one that keeps the card in the viewport, preferring below and lined up on
|
|
8
|
+
* the left. The same union `Popover` and the date and time pickers take.
|
|
9
|
+
*/
|
|
10
|
+
export type HoverCardPosition = PickerPosition;
|
|
11
|
+
/**
|
|
12
|
+
* Props for the HoverCard component. `className`, `id`, the other HTML
|
|
13
|
+
* attributes and the helper props land on the `span` around the trigger, not
|
|
14
|
+
* on the card; `contentClassName` reaches the card.
|
|
15
|
+
* @extraProp {string} [className] - Additional classes for the `span` around the trigger. The card takes `contentClassName`.
|
|
16
|
+
*/
|
|
17
|
+
export interface HoverCardProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color' | 'children'>, Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {
|
|
18
|
+
/**
|
|
19
|
+
* The element the card previews, such as a link or a `Button`. The element
|
|
20
|
+
* itself has to take focus, so keyboard users can open the card too: a
|
|
21
|
+
* link inside a `<span>` doesn't do, since focus comes back to the trigger
|
|
22
|
+
* and its ARIA is on it. HoverCard gives it no role and no tab stop, since
|
|
23
|
+
* it can't know what the element is, and a development build warns when
|
|
24
|
+
* it can't take focus: use a link or a button, or give the element
|
|
25
|
+
* `tabIndex={0}`. A disabled button can't take focus either. HoverCard adds
|
|
26
|
+
* `aria-expanded` and `aria-controls`, both naming the card only while it
|
|
27
|
+
* is on the page, so it has to be a single element that passes those to
|
|
28
|
+
* its DOM node. Its own click and keys stay its own, and the card doesn't
|
|
29
|
+
* toggle on them, except Escape while the card is open, which closes the
|
|
30
|
+
* card before the trigger sees it.
|
|
31
|
+
*/
|
|
32
|
+
trigger: React.ReactElement;
|
|
33
|
+
/**
|
|
34
|
+
* The card's content: a preview whose links and buttons are fine, but not a
|
|
35
|
+
* form, which belongs in a `Popover`. The card pads itself, so content goes
|
|
36
|
+
* straight in.
|
|
37
|
+
*/
|
|
38
|
+
children?: React.ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* Controlled open state. When set, hover, focus and Escape only report
|
|
41
|
+
* through `onOpenChange`, so an action inside the card can close it. While
|
|
42
|
+
* the card is open, Escape is reported, and when focus is in the card, on
|
|
43
|
+
* its trigger or nowhere, the key stops there even if you keep the card
|
|
44
|
+
* open, so a `Modal` around it doesn't close from the keyboard until the
|
|
45
|
+
* card does.
|
|
46
|
+
*/
|
|
47
|
+
open?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Initial open state when uncontrolled. A card that starts open stays open
|
|
50
|
+
* until the pointer or focus has been and gone, or Escape closes it.
|
|
51
|
+
* @defaultValue false
|
|
52
|
+
*/
|
|
53
|
+
defaultOpen?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Called with the state asked for: when `openDelay` or `closeDelay` runs
|
|
56
|
+
* out, and right away on Escape. Fires in both controlled and uncontrolled
|
|
57
|
+
* use. An Escape it reports stops at the card when focus is in the card,
|
|
58
|
+
* on its trigger or nowhere, so nothing around it sees that key. With
|
|
59
|
+
* focus anywhere else, the card still closes and the key goes on to
|
|
60
|
+
* whatever has focus.
|
|
61
|
+
*/
|
|
62
|
+
onOpenChange?: (open: boolean) => void;
|
|
63
|
+
/**
|
|
64
|
+
* How long the pointer or keyboard focus waits on the trigger before the
|
|
65
|
+
* card opens, in milliseconds.
|
|
66
|
+
* @defaultValue 600
|
|
67
|
+
*/
|
|
68
|
+
openDelay?: number;
|
|
69
|
+
/**
|
|
70
|
+
* How long the card stays after the pointer and focus have left the trigger
|
|
71
|
+
* and the card, in milliseconds. It is the time the pointer has to cross
|
|
72
|
+
* the gap between the trigger and the card: with `0` the card closes as the
|
|
73
|
+
* pointer leaves the trigger, before the pointer can reach it.
|
|
74
|
+
* @defaultValue 300
|
|
75
|
+
*/
|
|
76
|
+
closeDelay?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Where the card opens against the trigger.
|
|
79
|
+
* @defaultValue 'bottom-left'
|
|
80
|
+
*/
|
|
81
|
+
position?: HoverCardPosition;
|
|
82
|
+
/**
|
|
83
|
+
* Render the card through `Portal`, into the `portalContainer` a
|
|
84
|
+
* `ConfigProvider` sets, `document.body` by default, fixed to the viewport,
|
|
85
|
+
* so an ancestor's `overflow`, `transform` or stacking context can't clip
|
|
86
|
+
* it. A trigger in running text needs it too, since the card's block
|
|
87
|
+
* content can't sit inside a `<p>`. The card then shows from the commit
|
|
88
|
+
* after hydration, never in server markup, and it sits in the Tab order
|
|
89
|
+
* where its container is. At the end of `<body>`, the default, Tab reaches
|
|
90
|
+
* it only after the rest of the page, and focus leaving the trigger on the
|
|
91
|
+
* way closes it, so keyboard users can open it, read it and close it with
|
|
92
|
+
* Escape, and whatever it links to has to be reachable from the page as
|
|
93
|
+
* well. It is measured against the trigger when it opens and on resize and
|
|
94
|
+
* scroll, so it doesn't follow content that changes size while it is open.
|
|
95
|
+
* Theming variables set on an ancestor of the trigger reach it only when its
|
|
96
|
+
* container is inside that ancestor.
|
|
97
|
+
* @defaultValue false
|
|
98
|
+
*/
|
|
99
|
+
appendToBody?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Open the card with a tap on a touch screen. Touch has no hover, so
|
|
102
|
+
* without this a phone or tablet never opens the card. With it, a tap on
|
|
103
|
+
* the trigger opens the card at once, and it stays until a second tap on
|
|
104
|
+
* the trigger, a tap outside the trigger and the card, or Escape. The tap
|
|
105
|
+
* still does whatever the trigger does, so turn this on only for a trigger
|
|
106
|
+
* with no tap action of its own, such as a `Button` with no `onClick`: on
|
|
107
|
+
* a link, the first tap would follow the link rather than show the card.
|
|
108
|
+
* Mouse and pen work the same either way.
|
|
109
|
+
* @defaultValue false
|
|
110
|
+
*/
|
|
111
|
+
openOnTap?: boolean;
|
|
112
|
+
/** Additional classes for the card (`.hover-card-content`). */
|
|
113
|
+
contentClassName?: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it.
|
|
117
|
+
*
|
|
118
|
+
* Nothing moves focus when the card opens, and nothing traps it. In place,
|
|
119
|
+
* the card comes right after the trigger, so Tab goes from the trigger into
|
|
120
|
+
* its links and tabbing past them closes it. The pointer can move onto the
|
|
121
|
+
* card, Escape closes it from anywhere, and by default touch doesn't open it,
|
|
122
|
+
* so tapping the trigger just does what the trigger does. `openOnTap` opens
|
|
123
|
+
* it with a tap, for a trigger with no tap action of its own. For hints with nothing to
|
|
124
|
+
* click use `Tooltip`, and for content opened on purpose, such as a form,
|
|
125
|
+
* use `Popover`.
|
|
126
|
+
*
|
|
127
|
+
* @function
|
|
128
|
+
* @param {HoverCardProps} props - Props for the HoverCard component.
|
|
129
|
+
* @returns {JSX.Element} The trigger in its wrapper, and the card while open.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* <HoverCard trigger={<a href="/people/ada">Ada Lovelace</a>}>
|
|
133
|
+
* <Title as="p" size="6">Ada Lovelace</Title>
|
|
134
|
+
* <SubTitle as="p" size="6">Analytical Engine team</SubTitle>
|
|
135
|
+
* </HoverCard>
|
|
136
|
+
*/
|
|
137
|
+
export declare const HoverCard: React.FC<HoverCardProps>;
|
|
138
|
+
export default HoverCard;
|
|
@@ -44,7 +44,8 @@ export interface ModalProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
|
|
|
44
44
|
/**
|
|
45
45
|
* Renders the modal into a portal target instead of inline, so it isn't
|
|
46
46
|
* clipped by an ancestor with `overflow: hidden`, `filter` or `transform`.
|
|
47
|
-
* `true` portals to `
|
|
47
|
+
* `true` portals to the `portalContainer` a `ConfigProvider` sets,
|
|
48
|
+
* `document.body` by default; a string is used as a
|
|
48
49
|
* `document.querySelector` selector; an element is used directly. Renders
|
|
49
50
|
* inline on the server and while hydrating, moving into the portal once the
|
|
50
51
|
* client takes over, so hydration matches.
|
|
@@ -53,13 +53,14 @@ export interface PopoverProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
53
53
|
*/
|
|
54
54
|
position?: PopoverPosition;
|
|
55
55
|
/**
|
|
56
|
-
* Render the panel
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
56
|
+
* Render the panel through `Portal`, into the `portalContainer` a
|
|
57
|
+
* `ConfigProvider` sets, `document.body` by default, fixed to the viewport,
|
|
58
|
+
* so an ancestor's `overflow`, `transform` or stacking context can't clip
|
|
59
|
+
* it. The panel then shows from the commit after hydration, never in server
|
|
60
|
+
* markup. It is measured against the trigger when it opens and on resize
|
|
61
|
+
* and scroll, so it doesn't follow content that changes size while it is
|
|
62
|
+
* open. Theming variables set on an ancestor of the trigger reach it only
|
|
63
|
+
* when its container is inside that ancestor.
|
|
63
64
|
* @defaultValue false
|
|
64
65
|
*/
|
|
65
66
|
appendToBody?: boolean;
|
|
@@ -22,7 +22,7 @@ import { DateInputBaseProps } from './DateInputBase.js';
|
|
|
22
22
|
* @extraProp {React.Ref<HTMLInputElement>} [ref] - Forwarded to the underlying `<input>`.
|
|
23
23
|
*/
|
|
24
24
|
export interface DateInputProps extends DateInputBaseProps {
|
|
25
|
-
/** Field label (component auto-wraps in a `Field` if not already inside). Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
25
|
+
/** Field label (component auto-wraps in a `Field` if not already inside). Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
26
26
|
label?: React.ReactNode;
|
|
27
27
|
/** Size for the label. */
|
|
28
28
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -97,7 +97,10 @@ export interface DateInputBaseProps extends Omit<React.InputHTMLAttributes<HTMLI
|
|
|
97
97
|
closeOnSelect?: boolean;
|
|
98
98
|
/** Popover anchor position relative to the input. */
|
|
99
99
|
position?: PickerPosition;
|
|
100
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Render the popover through a portal, into the `portalContainer` a
|
|
102
|
+
* `ConfigProvider` sets, `document.body` by default.
|
|
103
|
+
*/
|
|
101
104
|
appendToBody?: boolean;
|
|
102
105
|
/**
|
|
103
106
|
* Bulma color modifier for the input, also carried by the calendar, where it
|
|
@@ -84,7 +84,10 @@ export interface DateRangeInputBaseProps extends Omit<React.HTMLAttributes<HTMLD
|
|
|
84
84
|
closeOnSelect?: boolean;
|
|
85
85
|
/** Popover anchor position relative to the field. */
|
|
86
86
|
position?: PickerPosition;
|
|
87
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Render the popover through a portal, into the `portalContainer` a
|
|
89
|
+
* `ConfigProvider` sets, `document.body` by default.
|
|
90
|
+
*/
|
|
88
91
|
appendToBody?: boolean;
|
|
89
92
|
/**
|
|
90
93
|
* Bulma color modifier for the field, also carried by the calendar, where it
|
|
@@ -20,7 +20,7 @@ import { DateTimeInputBaseProps } from './DateTimeInputBase.js';
|
|
|
20
20
|
* @extraProp {boolean} [required=false] - Marks the field as required for native HTML form validation.
|
|
21
21
|
*/
|
|
22
22
|
export interface DateTimeInputProps extends DateTimeInputBaseProps {
|
|
23
|
-
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
23
|
+
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
24
24
|
label?: React.ReactNode;
|
|
25
25
|
/** Size for the label. */
|
|
26
26
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -70,7 +70,10 @@ export interface DateTimeInputBaseProps extends Omit<React.InputHTMLAttributes<H
|
|
|
70
70
|
closeOnSelect?: boolean;
|
|
71
71
|
/** Popover anchor position. */
|
|
72
72
|
position?: PickerPosition;
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Render the popover through a portal, into the `portalContainer` a
|
|
75
|
+
* `ConfigProvider` sets, `document.body` by default.
|
|
76
|
+
*/
|
|
74
77
|
appendToBody?: boolean;
|
|
75
78
|
/**
|
|
76
79
|
* Bulma color modifier for the input, also carried by the calendar and the
|
|
@@ -12,7 +12,7 @@ export interface FieldProps extends React.HTMLAttributes<HTMLDivElement>, Omit<B
|
|
|
12
12
|
hasAddons?: boolean | 'centered' | 'right';
|
|
13
13
|
/** Constrains the field to its content's width (used inside horizontal field bodies). */
|
|
14
14
|
narrow?: boolean;
|
|
15
|
-
/** Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children
|
|
15
|
+
/** Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own. */
|
|
16
16
|
label?: React.ReactNode;
|
|
17
17
|
/** Size for the label. */
|
|
18
18
|
labelSize?: 'small' | 'normal' | 'medium' | 'large';
|
|
@@ -11,7 +11,7 @@ import { FormFieldProps } from './fieldProps.js';
|
|
|
11
11
|
* name on that `Field`.
|
|
12
12
|
*/
|
|
13
13
|
export interface FileProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'color' | 'type'>, Omit<BulmaClassesProps, 'color'>, FormFieldProps {
|
|
14
|
-
/** Field label. Automatically associated with the file input via `htmlFor` — uses your `id` when provided, otherwise a generated one. The input then has two labels (this one plus the wrapping `file-label`); assistive tech reads both. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
14
|
+
/** Field label. Automatically associated with the file input via `htmlFor` — uses your `id` when provided, otherwise a generated one. The input then has two labels (this one plus the wrapping `file-label`); assistive tech reads both. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
15
15
|
label?: React.ReactNode;
|
|
16
16
|
/** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). */
|
|
17
17
|
labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
@@ -18,7 +18,7 @@ import { InputBaseProps } from './InputBase.js';
|
|
|
18
18
|
* `label`, `horizontal` and class name on that `Field`.
|
|
19
19
|
*/
|
|
20
20
|
export interface InputProps extends InputBaseProps {
|
|
21
|
-
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
21
|
+
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
22
22
|
label?: React.ReactNode;
|
|
23
23
|
/** Size for the label. */
|
|
24
24
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -17,7 +17,7 @@ export type NumberinputVariant = 'plusminus' | 'stepper';
|
|
|
17
17
|
* @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the input element.
|
|
18
18
|
*/
|
|
19
19
|
export interface NumberinputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'color' | 'size' | 'onChange' | 'value' | 'defaultValue' | 'type'>, Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'>, FormFieldProps {
|
|
20
|
-
/** Field label. Automatically associated with the number input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). Not rendered either by a plusminus `bare` Numberinput outside a `Field`. */
|
|
20
|
+
/** Field label. Automatically associated with the number input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. Not rendered either by a plusminus `bare` Numberinput outside a `Field`. */
|
|
21
21
|
label?: React.ReactNode;
|
|
22
22
|
/** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). */
|
|
23
23
|
labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
@@ -18,7 +18,7 @@ import { SelectBaseProps } from './SelectBase.js';
|
|
|
18
18
|
* `label`, `horizontal` and class name on that `Field`.
|
|
19
19
|
*/
|
|
20
20
|
export interface SelectProps extends SelectBaseProps {
|
|
21
|
-
/** Field label. Automatically associated with the select via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
21
|
+
/** Field label. Automatically associated with the select via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
22
22
|
label?: React.ReactNode;
|
|
23
23
|
/** Size for the label. */
|
|
24
24
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -22,7 +22,7 @@ export interface SliderMark {
|
|
|
22
22
|
* Shared base props for single and range Slider modes.
|
|
23
23
|
*/
|
|
24
24
|
interface SliderBaseProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'color' | 'size' | 'onChange' | 'value' | 'defaultValue'>, Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'>, FormFieldProps {
|
|
25
|
-
/** Field label. Automatically associated with the slider input via `htmlFor` — uses your `id` when provided, otherwise a generated one. In range mode the `htmlFor` targets the low (minimum) thumb, and the label also starts each thumb's name through `aria-labelledby`, as in "Price Minimum value" and "Price Maximum value", unless an `aria-label` or `aria-labelledby` on the Slider takes its place there. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`), naming a range Slider's thumbs the same way. A `Field` label you wire by hand to the low thumb with `labelProps.htmlFor` names the thumbs too when you also give it an `id` there, since the `Field` generates none for it. */
|
|
25
|
+
/** Field label. Automatically associated with the slider input via `htmlFor` — uses your `id` when provided, otherwise a generated one. In range mode the `htmlFor` targets the low (minimum) thumb, and the label also starts each thumb's name through `aria-labelledby`, as in "Price Minimum value" and "Price Maximum value", unless an `aria-label` or `aria-labelledby` on the Slider takes its place there. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here, naming a range Slider's thumbs the same way. A `Field` label you wire by hand to the low thumb with `labelProps.htmlFor` names the thumbs too when you also give it an `id` there, since the `Field` generates none for it. */
|
|
26
26
|
label?: React.ReactNode;
|
|
27
27
|
/** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). In range mode an `id` here is the one the thumbs' `aria-labelledby` points at, in place of a generated one. */
|
|
28
28
|
labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
@@ -26,7 +26,7 @@ type IconLibrary = 'fa' | 'mdi' | 'ion' | 'material-icons' | 'material-symbols';
|
|
|
26
26
|
* @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.
|
|
27
27
|
*/
|
|
28
28
|
export interface TaginputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>, Omit<BulmaClassesProps, 'color'>, FormFieldProps {
|
|
29
|
-
/** Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`); it then replaces the `aria-label="Add tag"` fallback too. */
|
|
29
|
+
/** Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here; it then replaces the `aria-label="Add tag"` fallback too. */
|
|
30
30
|
label?: React.ReactNode;
|
|
31
31
|
/** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). */
|
|
32
32
|
labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
@@ -18,7 +18,7 @@ import { TextAreaBaseProps } from './TextAreaBase.js';
|
|
|
18
18
|
* `label`, `horizontal` and class name on that `Field`.
|
|
19
19
|
*/
|
|
20
20
|
export interface TextAreaProps extends TextAreaBaseProps {
|
|
21
|
-
/** Field label. Automatically associated with the textarea via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
21
|
+
/** Field label. Automatically associated with the textarea via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
22
22
|
label?: React.ReactNode;
|
|
23
23
|
/** Size for the label. */
|
|
24
24
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -22,7 +22,7 @@ import { TimeInputBaseProps } from './TimeInputBase.js';
|
|
|
22
22
|
* @extraProp {React.Ref<HTMLInputElement>} [ref] - Forwarded to the underlying `<input>`.
|
|
23
23
|
*/
|
|
24
24
|
export interface TimeInputProps extends TimeInputBaseProps {
|
|
25
|
-
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). */
|
|
25
|
+
/** Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. */
|
|
26
26
|
label?: React.ReactNode;
|
|
27
27
|
/** Size for the label. */
|
|
28
28
|
labelSize?: FieldProps['labelSize'];
|
|
@@ -64,7 +64,8 @@ export interface TimeInputBaseProps extends Omit<React.InputHTMLAttributes<HTMLI
|
|
|
64
64
|
/** Popover anchor position relative to the input. */
|
|
65
65
|
position?: PickerPosition;
|
|
66
66
|
/**
|
|
67
|
-
* Render the popover
|
|
67
|
+
* Render the popover through a portal, into the `portalContainer` a
|
|
68
|
+
* `ConfigProvider` sets, `document.body` by default. On a narrow screen
|
|
68
69
|
* an in-place popover spans the bottom of the viewport, while a portaled
|
|
69
70
|
* one stays on its `position` corner.
|
|
70
71
|
*/
|
|
@@ -3,13 +3,14 @@ import React, { ReactNode } from 'react';
|
|
|
3
3
|
type IconLibrary = 'fa' | 'mdi' | 'ion' | 'material-icons' | 'material-symbols';
|
|
4
4
|
/**
|
|
5
5
|
* Shape of the configuration context value.
|
|
6
|
-
*
|
|
7
|
-
* @property {string} [classPrefix] - Prefix applied to all Bulma class names.
|
|
8
|
-
* @property {IconLibrary} [iconLibrary] - Default icon library for Icon components.
|
|
9
6
|
*/
|
|
10
7
|
export interface ConfigContextProps {
|
|
8
|
+
/** Prefix applied to all Bulma class names. */
|
|
11
9
|
classPrefix?: string;
|
|
10
|
+
/** Default icon library for Icon components. */
|
|
12
11
|
iconLibrary?: IconLibrary;
|
|
12
|
+
/** Where portaled content goes when it has no target of its own. */
|
|
13
|
+
portalContainer?: string | HTMLElement;
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* Hook to access the bulma-ui configuration context.
|
|
@@ -28,10 +29,40 @@ export interface ConfigProviderProps {
|
|
|
28
29
|
classPrefix?: string;
|
|
29
30
|
/** Default icon library for Icon components. */
|
|
30
31
|
iconLibrary?: IconLibrary;
|
|
32
|
+
/**
|
|
33
|
+
* Where portaled content goes when it has no target of its own: what a
|
|
34
|
+
* `Portal` without a `container` renders, and what the library's components
|
|
35
|
+
* portal, such as Popover's `appendToBody` panel, a `Modal` with `portal`
|
|
36
|
+
* set to `true`, or a `Toast`. An element, or a `document.querySelector`
|
|
37
|
+
* selector. Unset, or a selector that matches nothing, that content goes to
|
|
38
|
+
* `document.body`. A target a component is given, such as a `Toast`'s
|
|
39
|
+
* `container`, still wins, and nothing portals that would otherwise render
|
|
40
|
+
* in place.
|
|
41
|
+
*
|
|
42
|
+
* The overlays and panels this moves are `position: fixed`, so pick an
|
|
43
|
+
* element with no ancestor that has a `transform`, `filter`,
|
|
44
|
+
* `backdrop-filter`, `perspective`, `will-change: transform`, or a
|
|
45
|
+
* `contain` that includes `paint` or `layout`. That ancestor becomes their
|
|
46
|
+
* containing block, and they cover or line up against it instead of the
|
|
47
|
+
* viewport. An ancestor that starts a stacking context, with a `z-index` or
|
|
48
|
+
* `isolation: isolate`, keeps them inside it, under anything the page
|
|
49
|
+
* stacks above it. `NotificationContainer`'s status region moves too, so
|
|
50
|
+
* this also decides where its announcements come from, and an `aria-hidden`
|
|
51
|
+
* ancestor silences them.
|
|
52
|
+
*
|
|
53
|
+
* A selector can't find an element inside a shadow root, so pass the
|
|
54
|
+
* element itself there, held in state from a ref callback. Content that
|
|
55
|
+
* portals before the element is set goes to `document.body` and moves when
|
|
56
|
+
* it is, which remounts it, as `Portal`'s `container` describes.
|
|
57
|
+
*/
|
|
58
|
+
portalContainer?: string | HTMLElement;
|
|
31
59
|
}
|
|
32
60
|
/**
|
|
33
61
|
* ConfigProvider injects configuration into all child components via React context.
|
|
34
62
|
*
|
|
63
|
+
* A nested provider replaces the outer one's settings rather than adding to
|
|
64
|
+
* them, so inside it any setting it leaves out is back to its default.
|
|
65
|
+
*
|
|
35
66
|
* @function
|
|
36
67
|
* @param {ConfigProviderProps} props - Provider props.
|
|
37
68
|
* @returns {JSX.Element} The context provider wrapping children.
|
|
@@ -14,6 +14,22 @@ import React from 'react';
|
|
|
14
14
|
* @returns The resolved DOM node to portal into.
|
|
15
15
|
*/
|
|
16
16
|
export declare function resolvePortalContainer(container?: string | HTMLElement): HTMLElement;
|
|
17
|
+
/**
|
|
18
|
+
* Where a component's portal goes, as a function to call when the portal is
|
|
19
|
+
* created: the target the component was given, else the `portalContainer` a
|
|
20
|
+
* `ConfigProvider` sets, else `document.body`, each read as
|
|
21
|
+
* `resolvePortalContainer` reads it. A component that portals resolves its
|
|
22
|
+
* target through this, so the provider's default reaches it.
|
|
23
|
+
*
|
|
24
|
+
* The hook only reads context, so it is safe to call on the server, ahead of
|
|
25
|
+
* any early return. The function it returns reads the DOM, so call it only
|
|
26
|
+
* where the portal is created, which the server never reaches.
|
|
27
|
+
*
|
|
28
|
+
* @function usePortalContainer
|
|
29
|
+
* @returns A function that takes the component's own target, if any, and
|
|
30
|
+
* returns the DOM node to portal into.
|
|
31
|
+
*/
|
|
32
|
+
export declare function usePortalContainer(): (container?: string | HTMLElement) => HTMLElement;
|
|
17
33
|
/**
|
|
18
34
|
* Props for the Portal component.
|
|
19
35
|
*/
|
|
@@ -22,8 +38,10 @@ export interface PortalProps {
|
|
|
22
38
|
children?: React.ReactNode;
|
|
23
39
|
/**
|
|
24
40
|
* Where the content goes: an element, or a `document.querySelector`
|
|
25
|
-
* selector. Omitted
|
|
26
|
-
* `document.body
|
|
41
|
+
* selector. Omitted or empty, it goes to the `portalContainer` a
|
|
42
|
+
* `ConfigProvider` sets, and to `document.body` when none is set. A
|
|
43
|
+
* selector that matches nothing means `document.body` too. A selector is
|
|
44
|
+
* looked up again on each render, so the
|
|
27
45
|
* content follows the target when it changes. Moving to another target
|
|
28
46
|
* remounts the children and resets their state, which includes a selector
|
|
29
47
|
* that only starts matching after the content has shown in `document.body`.
|
|
@@ -39,7 +57,7 @@ export interface PortalProps {
|
|
|
39
57
|
disabled?: boolean;
|
|
40
58
|
}
|
|
41
59
|
/**
|
|
42
|
-
* Renders its children into another part of the page, `document.body` unless `container` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.
|
|
60
|
+
* Renders its children into another part of the page, `document.body` unless `container` or a `ConfigProvider` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.
|
|
43
61
|
*
|
|
44
62
|
* React's server renderer can't render a portal, so `Portal` renders nothing
|
|
45
63
|
* on the server and during hydration, and mounts its children in the commit
|
|
@@ -50,8 +68,12 @@ export interface PortalProps {
|
|
|
50
68
|
* portaled children, and their React events bubble through the React tree.
|
|
51
69
|
* CSS inheritance follows the DOM instead: a scoped (non-`isRoot`) `Theme`
|
|
52
70
|
* sets its variables on a wrapper element the portaled content has left, so
|
|
53
|
-
* that content sees the page-level theme
|
|
54
|
-
*
|
|
71
|
+
* that content sees the page-level theme, and styles scoped to a shadow root
|
|
72
|
+
* don't reach `document.body` at all. To keep them, portal into an element
|
|
73
|
+
* inside the themed area or the shadow root: pass it as `container`, or as
|
|
74
|
+
* the `portalContainer` of a `ConfigProvider` around that area. The second
|
|
75
|
+
* also reaches what the library's components portal, such as Popover's
|
|
76
|
+
* `appendToBody` panel or a `Modal` with `portal`.
|
|
55
77
|
*
|
|
56
78
|
* Tab order and focus follow the DOM too. Content portaled from inside a
|
|
57
79
|
* focus trap is no longer inside the trapped element, so the trap neither
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Whether the browser puts `el` in the tab order, before anything that hides
|
|
4
|
+
* or disables it. The `tabIndex` property can't answer this on its own: it
|
|
5
|
+
* can read `-1` for an editable region or an `<embed>` that Tab still visits,
|
|
6
|
+
* and `0` for a `<video>` without controls that it doesn't. So a valid
|
|
7
|
+
* `tabindex` attribute decides, and otherwise the element's kind does.
|
|
8
|
+
* Internal like `firstTabStop`: `src/index.ts` names what it takes from here.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isTabbableKind(el: Element): boolean;
|
|
2
11
|
/**
|
|
3
12
|
* The first tab stop inside `container`, found the way the trap finds it, or
|
|
4
13
|
* `null` when there is none. For a component that moves focus into a panel
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { FocusEvent, PointerEvent, RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Options for `useHoverOpen`.
|
|
4
|
+
*/
|
|
5
|
+
export interface UseHoverOpenOptions {
|
|
6
|
+
/** Whether the floating element is open now, controlled or not. */
|
|
7
|
+
open: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Asks for the floating element to open or close: when a delay runs out,
|
|
10
|
+
* and at once on Escape. It isn't asked for the state it is already in,
|
|
11
|
+
* except that an Escape between asking to open and the open showing takes
|
|
12
|
+
* the ask back by asking to close.
|
|
13
|
+
*/
|
|
14
|
+
onOpenChange: (open: boolean) => void;
|
|
15
|
+
/** How long hover or keyboard focus waits before asking to open, in milliseconds. */
|
|
16
|
+
openDelay: number;
|
|
17
|
+
/**
|
|
18
|
+
* How long it waits once the pointer and focus have both left before
|
|
19
|
+
* asking to close, in milliseconds. Coming back in that time keeps it open,
|
|
20
|
+
* which is how the pointer crosses a gap to the floating element.
|
|
21
|
+
*/
|
|
22
|
+
closeDelay: number;
|
|
23
|
+
/**
|
|
24
|
+
* The element that opens it, which has to take focus itself. The Escape
|
|
25
|
+
* listener goes on its document, an iframe's when it renders into one, and
|
|
26
|
+
* focus left in the floating element comes back here when the floating
|
|
27
|
+
* element closes.
|
|
28
|
+
*/
|
|
29
|
+
triggerRef: RefObject<HTMLElement | null>;
|
|
30
|
+
/** The floating element, while it is open. */
|
|
31
|
+
floatingRef: RefObject<HTMLElement | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Whether a tap on the trigger opens it at once, with the next tap closing
|
|
34
|
+
* it. Without it, a touch pointer never opens it. While a tap holds it
|
|
35
|
+
* open, no hover timer closes it, and a press outside the trigger and the
|
|
36
|
+
* floating element does, as Escape does. The trigger's own tap action
|
|
37
|
+
* still runs.
|
|
38
|
+
* @defaultValue false
|
|
39
|
+
*/
|
|
40
|
+
openOnTap?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pointer and focus handlers for the element that holds the trigger. The
|
|
44
|
+
* floating element has to be inside it in React's tree, in place or through
|
|
45
|
+
* a portal, since React's events reach it from there either way, and it
|
|
46
|
+
* should hold nothing else: focus inside it that isn't on the trigger counts
|
|
47
|
+
* as focus in the floating element.
|
|
48
|
+
*/
|
|
49
|
+
export interface HoverOpenHandlers {
|
|
50
|
+
onPointerEnter: (event: PointerEvent<HTMLElement>) => void;
|
|
51
|
+
onPointerLeave: (event: PointerEvent<HTMLElement>) => void;
|
|
52
|
+
onFocus: (event: FocusEvent<HTMLElement>) => void;
|
|
53
|
+
onBlur: (event: FocusEvent<HTMLElement>) => void;
|
|
54
|
+
onPointerDown: (event: PointerEvent<HTMLElement>) => void;
|
|
55
|
+
onPointerUp: (event: PointerEvent<HTMLElement>) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Decides when a floating element that opens on hover or keyboard focus asks
|
|
59
|
+
* to open and to close. It renders nothing, and leaves roles, ARIA and
|
|
60
|
+
* placement to the component that calls it.
|
|
61
|
+
*
|
|
62
|
+
* - The pointer entering, or keyboard focus arriving on the trigger, asks to
|
|
63
|
+
* open after `openDelay`. A touch pointer doesn't count. Neither does focus
|
|
64
|
+
* that a press brings to the trigger: it counts when the browser shows it
|
|
65
|
+
* as `:focus-visible`.
|
|
66
|
+
* - Focus in the floating element holds it open however it got there,
|
|
67
|
+
* including focus in content it portals elsewhere, such as a nested card.
|
|
68
|
+
* Whether a click focuses what it lands on is up to the browser: Safari
|
|
69
|
+
* and Firefox on macOS don't focus a button on click, so there a clicked
|
|
70
|
+
* button doesn't hold it once the pointer leaves.
|
|
71
|
+
* - Once the pointer and focus have both left, it asks to close after
|
|
72
|
+
* `closeDelay`, and either coming back before then keeps it open. Nothing
|
|
73
|
+
* else closes it on a timer.
|
|
74
|
+
* - Escape closes it at once, wherever focus is, and stops there when focus
|
|
75
|
+
* is in it, on its trigger or nowhere, so a `Popover` or `Modal` around it
|
|
76
|
+
* keeps its own. With focus somewhere else, the key goes on after closing
|
|
77
|
+
* it. Inside another one, the inner one closes first. Escape before it
|
|
78
|
+
* opens takes the opening back and goes on its way. One key listener per
|
|
79
|
+
* document serves every hook on it, there only while one of them is open
|
|
80
|
+
* or on its way to open.
|
|
81
|
+
* - With `openOnTap`, a tap on the trigger opens it at once and the next tap
|
|
82
|
+
* on the trigger closes it. While a tap holds it open, a press outside the
|
|
83
|
+
* trigger and the floating element closes it, from a listener on the
|
|
84
|
+
* document that is there only then. Taps never count as hover, and mouse
|
|
85
|
+
* and pen work the same with it or without.
|
|
86
|
+
* - Once it closes, for any reason, whatever was holding it open has to
|
|
87
|
+
* leave and come back to open it again.
|
|
88
|
+
* - When the floating element closes with focus inside it, focus goes back
|
|
89
|
+
* to the trigger, unless the same update put it somewhere else. Handing it
|
|
90
|
+
* back doesn't count as focus arriving.
|
|
91
|
+
*
|
|
92
|
+
* Nothing it scheduled runs after the component unmounts.
|
|
93
|
+
*
|
|
94
|
+
* @function useHoverOpen
|
|
95
|
+
* @param options - The open state, how to ask for another, the delays, and the two elements.
|
|
96
|
+
* @returns Handlers for the element that holds the trigger.
|
|
97
|
+
*/
|
|
98
|
+
export declare function useHoverOpen(options: UseHoverOpenOptions): HoverOpenHandlers;
|
|
@@ -18,6 +18,7 @@ export * from './components/Collapse.js';
|
|
|
18
18
|
export * from './components/Collapses.js';
|
|
19
19
|
export * from './components/Tooltip.js';
|
|
20
20
|
export * from './components/Popover.js';
|
|
21
|
+
export * from './components/HoverCard.js';
|
|
21
22
|
export * from './components/Steps.js';
|
|
22
23
|
export * from './components/Sidebar.js';
|
|
23
24
|
export * from './components/Toast.js';
|