@allxsmith/bestax-bulma 5.29.0 → 5.31.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/ContextMenu.js +244 -0
- package/dist/esm/components/ContextMenu.js.map +1 -0
- package/dist/esm/components/Dropdown.js +37 -85
- package/dist/esm/components/Dropdown.js.map +1 -1
- package/dist/esm/components/HoverCard.js +3 -10
- package/dist/esm/components/HoverCard.js.map +1 -1
- package/dist/esm/components/Tooltip.js +88 -63
- package/dist/esm/components/Tooltip.js.map +1 -1
- package/dist/esm/elements/Button.js.map +1 -1
- package/dist/esm/elements/Buttons.js +2 -0
- package/dist/esm/elements/Buttons.js.map +1 -1
- package/dist/esm/elements/ToggleButton.js +68 -0
- package/dist/esm/elements/ToggleButton.js.map +1 -0
- package/dist/esm/form/DateTimeInputBase.js.map +1 -1
- package/dist/esm/form/TimeInputBase.js.map +1 -1
- package/dist/esm/form/_pickerInternals/pickerTypes.js +14 -6
- package/dist/esm/form/_pickerInternals/pickerTypes.js.map +1 -1
- package/dist/esm/helpers/useContextMenuTrigger.js +166 -0
- package/dist/esm/helpers/useContextMenuTrigger.js.map +1 -0
- package/dist/esm/helpers/useHoverOpen.js +40 -6
- package/dist/esm/helpers/useHoverOpen.js.map +1 -1
- package/dist/esm/helpers/useMenuKeys.js +182 -0
- package/dist/esm/helpers/useMenuKeys.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +1896 -1261
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/ContextMenu.d.ts +66 -0
- package/dist/types/components/Tooltip.d.ts +63 -9
- package/dist/types/elements/Button.d.ts +1 -1
- package/dist/types/elements/Buttons.d.ts +1 -0
- package/dist/types/elements/ToggleButton.d.ts +100 -0
- package/dist/types/form/DateTimeInputBase.d.ts +4 -1
- package/dist/types/form/TimeInputBase.d.ts +5 -2
- package/dist/types/form/_pickerInternals/pickerTypes.d.ts +16 -1
- package/dist/types/helpers/useContextMenuTrigger.d.ts +67 -0
- package/dist/types/helpers/useHoverOpen.d.ts +19 -3
- package/dist/types/helpers/useMenuKeys.d.ts +57 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types-cjs/components/ContextMenu.d.ts +66 -0
- package/dist/types-cjs/components/Tooltip.d.ts +63 -9
- package/dist/types-cjs/elements/Button.d.ts +1 -1
- package/dist/types-cjs/elements/Buttons.d.ts +1 -0
- package/dist/types-cjs/elements/ToggleButton.d.ts +100 -0
- package/dist/types-cjs/form/DateTimeInputBase.d.ts +4 -1
- package/dist/types-cjs/form/TimeInputBase.d.ts +5 -2
- package/dist/types-cjs/form/_pickerInternals/pickerTypes.d.ts +16 -1
- package/dist/types-cjs/helpers/useContextMenuTrigger.d.ts +67 -0
- package/dist/types-cjs/helpers/useHoverOpen.d.ts +19 -3
- package/dist/types-cjs/helpers/useMenuKeys.d.ts +57 -0
- package/dist/types-cjs/index.d.ts +2 -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 +1 -1
- package/src/scss/components/_contextmenu.scss +50 -0
- package/src/scss/components/_index.scss +1 -0
- package/src/scss/components/_tooltip.scss +76 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BulmaClassesProps } from '../helpers/useBulmaClasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Props for the ContextMenu component. `className`, `id`, `aria-label`, the
|
|
5
|
+
* other HTML attributes and the helper props land on the menu
|
|
6
|
+
* (`role="menu"`). The trigger keeps its own.
|
|
7
|
+
* @extraProp {string} [aria-label] - The menu's accessible name, such as "Actions for report.pdf". There's no button to borrow a name from, so pass this or `aria-labelledby`, and a development build warns when the menu opens with neither.
|
|
8
|
+
* @extraProp {string} [className] - Additional classes for the menu (`role="menu"`). The trigger keeps its own.
|
|
9
|
+
*/
|
|
10
|
+
export interface ContextMenuProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'children'>, Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {
|
|
11
|
+
/**
|
|
12
|
+
* The element a right-click, Shift+F10, the context menu key or a long
|
|
13
|
+
* press opens the menu from: a table row, a card, an image. It's cloned,
|
|
14
|
+
* not wrapped, so a row stays a row, which means it has to be a single
|
|
15
|
+
* element that passes `className` and the `onContextMenu`,
|
|
16
|
+
* `onPointerDown`, `onPointerMove`, `onPointerUp`, `onPointerCancel` and
|
|
17
|
+
* `onTouchEnd` handlers to its DOM node. Its own handlers for those run
|
|
18
|
+
* first, and one that calls `preventDefault()` on `contextmenu` keeps the
|
|
19
|
+
* menu closed. A `ContextMenu` inside it opens instead of this one.
|
|
20
|
+
*
|
|
21
|
+
* It gets no ARIA and no tab stop, since it can be any element and a
|
|
22
|
+
* right-click isn't an activation. Keyboard users reach it through
|
|
23
|
+
* something focusable inside it, such as the row's own `Dropdown` button,
|
|
24
|
+
* or a `tabIndex={0}` you give it, and press Shift+F10 or the context menu
|
|
25
|
+
* key there. It gets `-webkit-touch-callout: none`, so iOS doesn't put its
|
|
26
|
+
* own callout for a link or an image over the menu. A long press still
|
|
27
|
+
* selects text the way it does anywhere, so give a region where it
|
|
28
|
+
* shouldn't `interaction="unselectable"`.
|
|
29
|
+
*/
|
|
30
|
+
trigger: React.ReactElement;
|
|
31
|
+
/**
|
|
32
|
+
* The menu's items: `ContextMenu.Item` and `ContextMenu.Divider`, the same
|
|
33
|
+
* components as `Dropdown.Item` and `Dropdown.Divider`. Every action in it
|
|
34
|
+
* needs a visible way in as well, such as a `Dropdown` on the same row:
|
|
35
|
+
* nothing tells a screen reader user the menu is there, and on macOS only
|
|
36
|
+
* VoiceOver opens it from the keyboard.
|
|
37
|
+
*/
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* Called with `true` when the menu opens and `false` when it closes,
|
|
41
|
+
* whatever closed it, such as for highlighting the row whose menu is open.
|
|
42
|
+
* Nothing fires after ContextMenu unmounts. There's no `open` prop to go
|
|
43
|
+
* with it: a menu opened from code has no point to open at.
|
|
44
|
+
*/
|
|
45
|
+
onOpenChange?: (open: boolean) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Close the menu when an item is clicked, or activated with Enter or
|
|
48
|
+
* Space. A click on a divider or between items leaves it open either way.
|
|
49
|
+
*/
|
|
50
|
+
closeOnClick?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Leave the trigger to the browser: a right-click shows the browser's own
|
|
53
|
+
* menu, a long press does what it does anywhere, and an open menu closes.
|
|
54
|
+
*/
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* ContextMenu with Item and Divider sub-components, which are `Dropdown.Item`
|
|
59
|
+
* and `Dropdown.Divider`, so items written for a Dropdown work here
|
|
60
|
+
* unchanged.
|
|
61
|
+
*/
|
|
62
|
+
export declare const ContextMenu: React.FC<ContextMenuProps> & {
|
|
63
|
+
Item: import("../index.js").ConstrainedPolymorphicComponentWithoutRef<import("./Dropdown.js").DropdownItemOwnProps, import("./Dropdown.js").DropdownItemElement, "a", never>;
|
|
64
|
+
Divider: React.FC<{}>;
|
|
65
|
+
};
|
|
66
|
+
export default ContextMenu;
|
|
@@ -8,13 +8,29 @@ export type TooltipColor = 'primary' | 'link' | 'info' | 'success' | 'warning' |
|
|
|
8
8
|
export type TooltipSize = 'small' | 'medium' | 'large';
|
|
9
9
|
/**
|
|
10
10
|
* Props for the Tooltip component.
|
|
11
|
-
* @extraProp {React.ReactNode} [children] - The element that triggers the
|
|
11
|
+
* @extraProp {React.ReactNode} [children] - The element that triggers the
|
|
12
|
+
* tooltip. Its `aria-describedby` points at the tooltip, after any ids it
|
|
13
|
+
* already had, so a screen reader reads the tooltip as its description when
|
|
14
|
+
* it takes focus, even while the tooltip is hidden. That takes a single
|
|
15
|
+
* element which passes `aria-describedby` on to its DOM node, as native
|
|
16
|
+
* elements and bestax components do, and takes focus itself, such as a
|
|
17
|
+
* button, a link or a `Span` with `tabIndex={0}`: something focusable inside
|
|
18
|
+
* it doesn't get the link, and text, a fragment or several elements get none.
|
|
19
|
+
* A development build warns when the first element Tab reaches in the
|
|
20
|
+
* trigger doesn't carry the link, or there isn't one.
|
|
12
21
|
* @extraProp {string} [className] - Additional CSS classes.
|
|
13
22
|
*/
|
|
14
23
|
export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color' | 'content'>, Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {
|
|
15
24
|
/** The tooltip text content. */
|
|
16
25
|
label?: string;
|
|
17
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Rich tooltip content (alternative to `label`), to read rather than use.
|
|
28
|
+
* Nothing in it should take focus or a click: it isn't in the Tab order
|
|
29
|
+
* while hidden, focus there isn't counted as being in the tooltip, and
|
|
30
|
+
* Escape hiding it would drop that focus. For links or buttons, use
|
|
31
|
+
* `HoverCard` or `Popover`. A screen reader reads it as plain text, since
|
|
32
|
+
* it's the trigger's description.
|
|
33
|
+
*/
|
|
18
34
|
content?: React.ReactNode;
|
|
19
35
|
/** Position of the tooltip. Default: 'top'. */
|
|
20
36
|
position?: TooltipPosition;
|
|
@@ -22,7 +38,11 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLSpanElement>
|
|
|
22
38
|
color?: TooltipColor;
|
|
23
39
|
/** Size of the tooltip. */
|
|
24
40
|
size?: TooltipSize;
|
|
25
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Force tooltip to be always visible. Hover, focus and Escape leave it
|
|
43
|
+
* shown, so Escape goes on to whatever has focus, or to a `Modal` or
|
|
44
|
+
* `Popover` around it.
|
|
45
|
+
*/
|
|
26
46
|
active?: boolean;
|
|
27
47
|
/** Allow tooltip to wrap to multiple lines. */
|
|
28
48
|
multiline?: boolean;
|
|
@@ -32,16 +52,48 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLSpanElement>
|
|
|
32
52
|
square?: boolean;
|
|
33
53
|
/** Show dashed underline on trigger. */
|
|
34
54
|
dashed?: boolean;
|
|
35
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* How long the pointer or keyboard focus waits on the trigger before the
|
|
57
|
+
* tooltip shows, in milliseconds.
|
|
58
|
+
*/
|
|
36
59
|
delay?: number;
|
|
37
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* How long the tooltip stays after the pointer and focus have left the
|
|
62
|
+
* trigger and the tooltip, in milliseconds. The pointer can move from the
|
|
63
|
+
* trigger onto a shown tooltip without one, across the default gap. A
|
|
64
|
+
* theme that raises `--bulma-tooltip-arrow-size` or
|
|
65
|
+
* `--bulma-tooltip-arrow-margin` widens the gap past what the pointer can
|
|
66
|
+
* cross on its own, so give it a `closeDelay` long enough to cross the
|
|
67
|
+
* rest.
|
|
68
|
+
*/
|
|
38
69
|
closeDelay?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Show the tooltip with a tap on a touch screen. Touch has no hover, so
|
|
72
|
+
* without this a phone or tablet never shows it. With it, a tap on the
|
|
73
|
+
* trigger shows it at once, and it stays until another tap on the trigger
|
|
74
|
+
* or the tooltip, a tap anywhere else, or Escape. The tap still does
|
|
75
|
+
* whatever the trigger does, so turn this on only for a trigger with no
|
|
76
|
+
* tap action of its own. Mouse and pen work the same either way.
|
|
77
|
+
* @defaultValue false
|
|
78
|
+
*/
|
|
79
|
+
openOnTap?: boolean;
|
|
39
80
|
/** Additional classes for the tooltip element. */
|
|
40
81
|
tooltipClassName?: string;
|
|
41
82
|
}
|
|
42
83
|
/**
|
|
43
84
|
* The `Tooltip` component displays helpful information when users hover over or focus on an element.
|
|
44
85
|
*
|
|
86
|
+
* Hovering the trigger or giving it keyboard focus shows it. Touch doesn't,
|
|
87
|
+
* unless `openOnTap` is on, and neither does focus a click or a tap brings,
|
|
88
|
+
* so tapping the trigger just does what the trigger does. The pointer can
|
|
89
|
+
* move onto a shown tooltip. Escape hides it wherever focus is, without
|
|
90
|
+
* moving the pointer or focus, and it stays hidden until one of them leaves
|
|
91
|
+
* the trigger and comes back, or, with `openOnTap`, until the next tap on
|
|
92
|
+
* the trigger. The key always goes on too, to whatever has focus or a
|
|
93
|
+
* `Modal` or `Popover` around it, since a tooltip only adds to what's
|
|
94
|
+
* there. The tooltip is its trigger's description, so a screen reader reads
|
|
95
|
+
* it as the trigger takes focus, whether it's showing yet or not.
|
|
96
|
+
*
|
|
45
97
|
* @function
|
|
46
98
|
* @param {TooltipProps} props - Props for the Tooltip component.
|
|
47
99
|
* @returns {JSX.Element} The rendered tooltip wrapper.
|
|
@@ -53,15 +105,17 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLSpanElement>
|
|
|
53
105
|
* </Tooltip>
|
|
54
106
|
*
|
|
55
107
|
* @example
|
|
56
|
-
* // Positioned tooltip with color
|
|
57
|
-
* <Tooltip label="
|
|
58
|
-
* <
|
|
108
|
+
* // Positioned tooltip with color, on an icon-only button with a name of its own
|
|
109
|
+
* <Tooltip label="Moves it to the trash" position="right" color="danger">
|
|
110
|
+
* <Button aria-label="Delete">
|
|
111
|
+
* <Icon name="fas fa-trash" />
|
|
112
|
+
* </Button>
|
|
59
113
|
* </Tooltip>
|
|
60
114
|
*
|
|
61
115
|
* @example
|
|
62
116
|
* // Multiline tooltip
|
|
63
117
|
* <Tooltip label="This is a longer tooltip that wraps to multiple lines" multiline>
|
|
64
|
-
* <
|
|
118
|
+
* <button>More info</button>
|
|
65
119
|
* </Tooltip>
|
|
66
120
|
*/
|
|
67
121
|
export declare const Tooltip: React.FC<TooltipProps>;
|
|
@@ -39,7 +39,7 @@ export interface ButtonOwnProps extends Omit<BulmaClassesProps, 'color' | 'backg
|
|
|
39
39
|
isInverted?: boolean;
|
|
40
40
|
/** Applies focused styling (visual only). */
|
|
41
41
|
isFocused?: boolean;
|
|
42
|
-
/** Applies active styling (visual only)
|
|
42
|
+
/** Applies active styling (visual only), with no `aria-pressed`. For a button that stays pressed, use `ToggleButton`. */
|
|
43
43
|
isActive?: boolean;
|
|
44
44
|
/** Applies hovered styling (visual only). */
|
|
45
45
|
isHovered?: boolean;
|
|
@@ -36,5 +36,6 @@ interface ButtonsProps extends React.HTMLAttributes<HTMLDivElement>, Omit<BulmaC
|
|
|
36
36
|
export declare const Buttons: React.FC<ButtonsProps> & {
|
|
37
37
|
Button: import("../index.js").PolymorphicComponent<import("./Button.js").ButtonOwnProps, "button", never>;
|
|
38
38
|
LinkButton: import("../index.js").PolymorphicComponent<import("./LinkButton.js").LinkButtonOwnProps, "button", never>;
|
|
39
|
+
ToggleButton: React.ForwardRefExoticComponent<import("./ToggleButton.js").ToggleButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
39
40
|
};
|
|
40
41
|
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ButtonOwnProps } from './Button.js';
|
|
3
|
+
/**
|
|
4
|
+
* The fills a pressed `ToggleButton` takes: `Button`'s colors, minus `text`
|
|
5
|
+
* and `ghost`, which don't fill, and `white`, `light`, `dark` and `black`.
|
|
6
|
+
* Bulma's color modifier fills the button and drops its border, and those four
|
|
7
|
+
* fill it with about the lightness a plain button already has in one theme or
|
|
8
|
+
* the other, so pressed would look like off without its border.
|
|
9
|
+
*/
|
|
10
|
+
export type ToggleButtonColor = 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';
|
|
11
|
+
/**
|
|
12
|
+
* Props for the ToggleButton component. The helper props, the other button
|
|
13
|
+
* attributes and the `ref` all land on the `<button>`.
|
|
14
|
+
*
|
|
15
|
+
* Some of `Button`'s props are left out on purpose. `as`, since only a button
|
|
16
|
+
* can be pressed, and `type`, which is always `button`. `isActive`, which is
|
|
17
|
+
* `pressed` here, and `isStatic`, a toggle you couldn't press. And the props
|
|
18
|
+
* that change the fill (`isLight`, `isOutlined`, `isInverted`, `textColor`,
|
|
19
|
+
* `bgColor` and their shades), since each would color the button in both
|
|
20
|
+
* states or turn "on" into a faint tint. `color` takes only the fills that
|
|
21
|
+
* stand out from a plain button: see `ToggleButtonColor`.
|
|
22
|
+
*
|
|
23
|
+
* @extraProp {React.Ref<HTMLButtonElement>} [ref] - Ref forwarded to the `<button>`.
|
|
24
|
+
*/
|
|
25
|
+
export interface ToggleButtonProps extends Omit<ButtonOwnProps, 'color' | 'isActive' | 'isStatic' | 'isLight' | 'isOutlined' | 'isInverted' | 'textColor' | 'bgColor' | 'colorShade' | 'backgroundColorShade'>, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonOwnProps | 'type' | 'aria-pressed'> {
|
|
26
|
+
/**
|
|
27
|
+
* Whether it's pressed, when you hold the state. Setting it makes the toggle
|
|
28
|
+
* controlled: a click only calls `onPressedChange`, and nothing changes until
|
|
29
|
+
* you pass the new value. Pick this or `defaultPressed` for the button's
|
|
30
|
+
* lifetime.
|
|
31
|
+
*/
|
|
32
|
+
pressed?: boolean;
|
|
33
|
+
/** Whether it starts pressed, when it holds its own state. */
|
|
34
|
+
defaultPressed?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Called with the new state each time it's toggled, whether or not
|
|
37
|
+
* `pressed` is set. An `onClick` that calls `preventDefault()` stops the
|
|
38
|
+
* toggle, and this doesn't fire.
|
|
39
|
+
*/
|
|
40
|
+
onPressedChange?: (pressed: boolean) => void;
|
|
41
|
+
/**
|
|
42
|
+
* The fill while it's pressed. Not pressed, it's a plain button, so the fill
|
|
43
|
+
* is the difference people see. `white`, `light`, `dark` and `black` aren't
|
|
44
|
+
* offered, since in one theme or the other each fills about as light or dark
|
|
45
|
+
* as a plain button already is. Of the rest, a pale one such as `warning`
|
|
46
|
+
* changes less than the default `link`.
|
|
47
|
+
*/
|
|
48
|
+
color?: ToggleButtonColor;
|
|
49
|
+
/**
|
|
50
|
+
* The label, which stays the same in both states: a screen reader announces
|
|
51
|
+
* whether it's pressed, so "Mute" stays "Mute". An icon can swap, but an
|
|
52
|
+
* icon-only toggle needs an `aria-label` that doesn't. A label that changes
|
|
53
|
+
* ("Play", then "Pause") belongs on a plain `Button`.
|
|
54
|
+
*/
|
|
55
|
+
children?: React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Shows Bulma's spinner in place of the label and holds the toggle where it
|
|
58
|
+
* is: a click, Enter or Space does nothing, so neither `onClick` nor
|
|
59
|
+
* `onPressedChange` fires, until it's cleared. Set it while a change is
|
|
60
|
+
* saving. The button carries `aria-busy` and `aria-disabled` meanwhile, and
|
|
61
|
+
* stays focusable, so focus isn't lost mid-save. Under
|
|
62
|
+
* `prefers-reduced-motion: reduce` the spinner stops and stays drawn (with
|
|
63
|
+
* bestax's CSS loaded).
|
|
64
|
+
*/
|
|
65
|
+
isLoading?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Not accepted: `aria-pressed` follows the state. Declared because JSX lets a
|
|
68
|
+
* hyphenated attribute through when the props don't name it, so leaving it
|
|
69
|
+
* out of the type alone would not reject `aria-pressed="mixed"`.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
'aria-pressed'?: never;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The `ToggleButton` component renders a button that stays pressed until it's pressed again, and says whether it's on through `aria-pressed`.
|
|
76
|
+
*
|
|
77
|
+
* It's always a `<button type="button">`, so it never submits a form and
|
|
78
|
+
* carries no form value: a setting saved with a form is a `Checkbox` or a
|
|
79
|
+
* `Switch`. A set of toggles that each turn on and off on their own goes in
|
|
80
|
+
* `Buttons hasAddons` with `role="group"` and an `aria-label`. A set where only
|
|
81
|
+
* one can be on is a radio group rather than a row of these: use `Radios`.
|
|
82
|
+
*
|
|
83
|
+
* @function
|
|
84
|
+
* @param {ToggleButtonProps} props - Props for the ToggleButton component.
|
|
85
|
+
* @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
|
|
86
|
+
* @returns {JSX.Element} The rendered toggle button.
|
|
87
|
+
* @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/button/ | APG button pattern}
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* <ToggleButton onPressedChange={setMuted}>Mute</ToggleButton>
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* <Buttons hasAddons role="group" aria-label="Text style">
|
|
94
|
+
* <ToggleButton aria-label="Bold" pressed={bold} onPressedChange={setBold}>
|
|
95
|
+
* <Icon name="bold" />
|
|
96
|
+
* </ToggleButton>
|
|
97
|
+
* </Buttons>
|
|
98
|
+
*/
|
|
99
|
+
export declare const ToggleButton: React.ForwardRefExoticComponent<ToggleButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
100
|
+
export default ToggleButton;
|
|
@@ -131,7 +131,10 @@ export interface DateTimeInputBaseProps extends Omit<React.InputHTMLAttributes<H
|
|
|
131
131
|
audioTick?: boolean;
|
|
132
132
|
/** Auto-route tactile feedback per wheel tick (vibrate on Android, audio thunk on iOS). Default `false`. */
|
|
133
133
|
haptics?: boolean;
|
|
134
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Optional translatable string overrides. In a 12-hour picker, `ampm`
|
|
136
|
+
* names the AM/PM column, `'AM/PM'` by default.
|
|
137
|
+
*/
|
|
135
138
|
labels?: PickerLabels;
|
|
136
139
|
}
|
|
137
140
|
/**
|
|
@@ -82,7 +82,7 @@ export interface TimeInputBaseProps extends Omit<React.InputHTMLAttributes<HTMLI
|
|
|
82
82
|
size?: 'small' | 'medium' | 'large';
|
|
83
83
|
/** Render the input with rounded corners. */
|
|
84
84
|
isRounded?: boolean;
|
|
85
|
-
/** Hour format. `'12'`
|
|
85
|
+
/** Hour format. `'12'` adds an AM/PM column to the wheels. */
|
|
86
86
|
hourFormat?: HourFormat;
|
|
87
87
|
/** Show a seconds column. Note: iOS Safari's native time picker UI does not include a seconds wheel; pass `mobileNative={false}` if you need one on iOS. */
|
|
88
88
|
enableSeconds?: boolean;
|
|
@@ -105,7 +105,10 @@ export interface TimeInputBaseProps extends Omit<React.InputHTMLAttributes<HTMLI
|
|
|
105
105
|
triggerIcon?: boolean;
|
|
106
106
|
/** Glyph for the right launcher button. */
|
|
107
107
|
triggerIconName?: string;
|
|
108
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Optional translatable string overrides. In a 12-hour picker, `ampm`
|
|
110
|
+
* names the AM/PM column, `'AM/PM'` by default.
|
|
111
|
+
*/
|
|
109
112
|
labels?: PickerLabels;
|
|
110
113
|
/** Play a short audible click on each wheel-item crossing. Substitute for haptic feedback on iOS Safari (which has no web haptic API as of May 2026); on Android, `navigator.vibrate(5)` fires automatically regardless. */
|
|
111
114
|
audioTick?: boolean;
|
|
@@ -49,13 +49,24 @@ export interface PickerLabels {
|
|
|
49
49
|
hours?: string;
|
|
50
50
|
minutes?: string;
|
|
51
51
|
seconds?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Time wheels: names the AM/PM column a 12-hour picker shows.
|
|
54
|
+
* @defaultValue 'AM/PM'
|
|
55
|
+
*/
|
|
52
56
|
ampm?: string;
|
|
57
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
53
58
|
increaseHours?: string;
|
|
59
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
54
60
|
decreaseHours?: string;
|
|
61
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
55
62
|
increaseMinutes?: string;
|
|
63
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
56
64
|
decreaseMinutes?: string;
|
|
65
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
57
66
|
increaseSeconds?: string;
|
|
67
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
58
68
|
decreaseSeconds?: string;
|
|
69
|
+
/** @deprecated Rendered nowhere: no picker reads it. It goes in the next major. */
|
|
59
70
|
toggleAmPm?: string;
|
|
60
71
|
chooseTime?: string;
|
|
61
72
|
chooseDateTime?: string;
|
|
@@ -72,5 +83,9 @@ export interface PickerLabels {
|
|
|
72
83
|
time?: string;
|
|
73
84
|
}
|
|
74
85
|
export declare const DEFAULT_PICKER_LABELS: Required<PickerLabels>;
|
|
75
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* Merge user-supplied label overrides with the defaults. A key set to
|
|
88
|
+
* `undefined` keeps its default, so a locale table that is missing a string
|
|
89
|
+
* still names its control instead of leaving it with no accessible name.
|
|
90
|
+
*/
|
|
76
91
|
export declare const mergeLabels: (overrides?: PickerLabels) => Required<PickerLabels>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { MouseEvent, PointerEvent, TouchEvent } from 'react';
|
|
2
|
+
/** A point in the viewport, in CSS pixels. */
|
|
3
|
+
export interface ContextMenuPoint {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Options for `useContextMenuTrigger`.
|
|
9
|
+
*/
|
|
10
|
+
export interface UseContextMenuTriggerOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Asks to open at `point`. `trigger` is the element the handlers are on,
|
|
13
|
+
* for its document.
|
|
14
|
+
*/
|
|
15
|
+
onOpen: (point: ContextMenuPoint, trigger: HTMLElement) => void;
|
|
16
|
+
/** Leave the browser's own menu alone, and start no long press. */
|
|
17
|
+
disabled: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Handlers for the trigger element. */
|
|
20
|
+
export interface ContextMenuTriggerHandlers {
|
|
21
|
+
onContextMenu: (event: MouseEvent<HTMLElement>) => void;
|
|
22
|
+
onPointerDown: (event: PointerEvent<HTMLElement>) => void;
|
|
23
|
+
onPointerMove: (event: PointerEvent<HTMLElement>) => void;
|
|
24
|
+
onPointerUp: (event: PointerEvent<HTMLElement>) => void;
|
|
25
|
+
onPointerCancel: (event: PointerEvent<HTMLElement>) => void;
|
|
26
|
+
onTouchEnd: (event: TouchEvent<HTMLElement>) => void;
|
|
27
|
+
}
|
|
28
|
+
/** How long a touch or a pen has to stay down to open the menu, in milliseconds. */
|
|
29
|
+
export declare const LONG_PRESS_DELAY = 500;
|
|
30
|
+
/** How far a long press can move before it counts as something else, in CSS pixels. */
|
|
31
|
+
export declare const LONG_PRESS_TOLERANCE = 10;
|
|
32
|
+
/**
|
|
33
|
+
* Decides when a context menu asks to open, and where. It renders nothing,
|
|
34
|
+
* and knows nothing about ARIA or the menu.
|
|
35
|
+
*
|
|
36
|
+
* - **`contextmenu`:** a right-click, and Shift+F10 or the context menu key
|
|
37
|
+
* where the browser fires the event for them, asks to open at the point
|
|
38
|
+
* `contextMenuPoint` works out, and prevents the browser's own menu. Each
|
|
39
|
+
* one asks again, so a right-click elsewhere on the trigger moves it.
|
|
40
|
+
* - **Long press:** a touch or a pen held still on the trigger for
|
|
41
|
+
* `LONG_PRESS_DELAY` fires a `contextmenu` at what it landed on, so it
|
|
42
|
+
* takes the same path, handlers on the way included. Moving more than
|
|
43
|
+
* `LONG_PRESS_TOLERANCE`, lifting, another pointer coming down anywhere in
|
|
44
|
+
* the document, or `pointercancel`, which is the browser taking the
|
|
45
|
+
* gesture for a scroll or a zoom, cancels it, and a mouse never starts
|
|
46
|
+
* one. A pointer that comes down while another is held starts no long
|
|
47
|
+
* press of its own, on this trigger or another, so two fingers on two rows
|
|
48
|
+
* open nothing. While the finger is down, and only then, a listener on the
|
|
49
|
+
* document hears other pointers coming down. Where the
|
|
50
|
+
* browser fires `contextmenu` for a long press itself, the first of the two
|
|
51
|
+
* opens it, and the end of a touch that opened it is prevented, so lifting
|
|
52
|
+
* doesn't click what is under the finger.
|
|
53
|
+
* - **Who opens:** a handler that calls `preventDefault()` on the
|
|
54
|
+
* `contextmenu` before this one keeps it from asking, which is how a
|
|
55
|
+
* trigger's own handler opts out and how the innermost of nested triggers
|
|
56
|
+
* wins. A long press goes to the innermost trigger that takes it. Events
|
|
57
|
+
* from content portaled out of the trigger, which React brings here
|
|
58
|
+
* anyway, are ignored.
|
|
59
|
+
* - **`disabled`:** nothing asks, and the browser's menu shows.
|
|
60
|
+
*
|
|
61
|
+
* Nothing it scheduled runs after the component unmounts.
|
|
62
|
+
*
|
|
63
|
+
* @function useContextMenuTrigger
|
|
64
|
+
* @param options - How to ask to open, and whether to.
|
|
65
|
+
* @returns Handlers for the trigger element.
|
|
66
|
+
*/
|
|
67
|
+
export declare function useContextMenuTrigger({ onOpen, disabled, }: UseContextMenuTriggerOptions): ContextMenuTriggerHandlers;
|
|
@@ -38,6 +38,14 @@ export interface UseHoverOpenOptions {
|
|
|
38
38
|
* @defaultValue false
|
|
39
39
|
*/
|
|
40
40
|
openOnTap?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether an Escape that closes it stops there when focus is on the
|
|
43
|
+
* trigger, in the floating element or nowhere, so a `Popover` or `Modal`
|
|
44
|
+
* around it keeps its own. Off, Escape still closes it and always goes on
|
|
45
|
+
* to whatever has focus, as suits content that only adds to the trigger.
|
|
46
|
+
* @defaultValue true
|
|
47
|
+
*/
|
|
48
|
+
consumeEscape?: boolean;
|
|
41
49
|
}
|
|
42
50
|
/**
|
|
43
51
|
* Pointer and focus handlers for the element that holds the trigger. The
|
|
@@ -48,12 +56,18 @@ export interface UseHoverOpenOptions {
|
|
|
48
56
|
*/
|
|
49
57
|
export interface HoverOpenHandlers {
|
|
50
58
|
onPointerEnter: (event: PointerEvent<HTMLElement>) => void;
|
|
59
|
+
onPointerOver: (event: PointerEvent<HTMLElement>) => void;
|
|
51
60
|
onPointerLeave: (event: PointerEvent<HTMLElement>) => void;
|
|
52
61
|
onFocus: (event: FocusEvent<HTMLElement>) => void;
|
|
53
62
|
onBlur: (event: FocusEvent<HTMLElement>) => void;
|
|
54
63
|
onPointerDown: (event: PointerEvent<HTMLElement>) => void;
|
|
55
64
|
onPointerUp: (event: PointerEvent<HTMLElement>) => void;
|
|
56
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Runs the caller's own handler on the element that holds the trigger, then
|
|
68
|
+
* the hook's, so neither replaces the other.
|
|
69
|
+
*/
|
|
70
|
+
export declare function chain<E>(own: ((event: E) => void) | undefined, ours: (event: E) => void): (event: E) => void;
|
|
57
71
|
/**
|
|
58
72
|
* Decides when a floating element that opens on hover or keyboard focus asks
|
|
59
73
|
* to open and to close. It renders nothing, and leaves roles, ARIA and
|
|
@@ -62,7 +76,8 @@ export interface HoverOpenHandlers {
|
|
|
62
76
|
* - The pointer entering, or keyboard focus arriving on the trigger, asks to
|
|
63
77
|
* open after `openDelay`. A touch pointer doesn't count. Neither does focus
|
|
64
78
|
* that a press brings to the trigger: it counts when the browser shows it
|
|
65
|
-
* as `:focus-visible`.
|
|
79
|
+
* as `:focus-visible`. The pointer arriving from outside a shadow root the
|
|
80
|
+
* trigger renders into counts too, though React sends no enter for it.
|
|
66
81
|
* - Focus in the floating element holds it open however it got there,
|
|
67
82
|
* including focus in content it portals elsewhere, such as a nested card.
|
|
68
83
|
* Whether a click focuses what it lands on is up to the browser: Safari
|
|
@@ -73,8 +88,9 @@ export interface HoverOpenHandlers {
|
|
|
73
88
|
* else closes it on a timer.
|
|
74
89
|
* - Escape closes it at once, wherever focus is, and stops there when focus
|
|
75
90
|
* is in it, on its trigger or nowhere, so a `Popover` or `Modal` around it
|
|
76
|
-
* keeps its own. With focus somewhere else,
|
|
77
|
-
* it. Inside another one, the inner one
|
|
91
|
+
* keeps its own. With focus somewhere else, or with `consumeEscape` off,
|
|
92
|
+
* the key goes on after closing it. Inside another one, the inner one
|
|
93
|
+
* closes first. Escape before it
|
|
78
94
|
* opens takes the opening back and goes on its way. One key listener per
|
|
79
95
|
* document serves every hook on it, there only while one of them is open
|
|
80
96
|
* or on its way to open.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { KeyboardEvent } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Every menu-item role, so an item a caller gives `menuitemcheckbox` or
|
|
4
|
+
* `menuitemradio` (a filter or sort menu) stays reachable.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MENU_ITEM_SELECTOR = "[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"]";
|
|
7
|
+
/**
|
|
8
|
+
* Whether a menu item can be reached and activated: it isn't disabled, as a
|
|
9
|
+
* native control or through `aria-disabled="true"`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isEnabledMenuItem(item: Element): boolean;
|
|
12
|
+
/** The items in `menu` the keys reach, in document order. */
|
|
13
|
+
export declare function enabledMenuItems(menu: Element): HTMLElement[];
|
|
14
|
+
/** How long typed characters keep adding up to one search, in milliseconds. */
|
|
15
|
+
export declare const TYPEAHEAD_TIMEOUT = 500;
|
|
16
|
+
/** What `useMenuKeys` returns. */
|
|
17
|
+
export interface MenuKeys {
|
|
18
|
+
/** The `keydown` handler for the `role="menu"` element. */
|
|
19
|
+
onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Forgets what has been typed, so the next character starts a new search.
|
|
22
|
+
* Call it when the menu opens, so a search typed just before it last
|
|
23
|
+
* closed doesn't carry over.
|
|
24
|
+
*/
|
|
25
|
+
reset: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Moves through and activates the items of a `role="menu"` element from the
|
|
29
|
+
* keyboard. Put the `onKeyDown` it returns on that element. It reads the
|
|
30
|
+
* items from the element each time, so items that come and go are found,
|
|
31
|
+
* and it renders nothing.
|
|
32
|
+
*
|
|
33
|
+
* It acts only while focus is on the menu element itself or on one of its
|
|
34
|
+
* items, so anything else focusable inside the menu, such as a filter
|
|
35
|
+
* field, keeps its own keys.
|
|
36
|
+
*
|
|
37
|
+
* - Down and Up move to the next and previous enabled item, wrapping, and
|
|
38
|
+
* Home and End go to the first and last. From no item, Down goes to the
|
|
39
|
+
* first and Up to the last.
|
|
40
|
+
* - Enter and Space activate the focused item. A `<button>`, and a link with
|
|
41
|
+
* an `href` for Enter, get the browser's own click, and anything else gets
|
|
42
|
+
* one from here, so its `onClick` runs either way. A key held down
|
|
43
|
+
* activates it once. A key handler on the item that called
|
|
44
|
+
* `preventDefault()` has claimed the key, and nothing else runs it.
|
|
45
|
+
* - A printable character moves to the next enabled item whose text starts
|
|
46
|
+
* with what has been typed. Characters typed within `TYPEAHEAD_TIMEOUT` of
|
|
47
|
+
* each other add up to one search, until `reset` starts a new one.
|
|
48
|
+
*
|
|
49
|
+
* Items are `MENU_ITEM_SELECTOR` matches, and disabled ones are skipped by
|
|
50
|
+
* all of the above. Escape and Tab are left to the menu's owner, since what
|
|
51
|
+
* closing means is up to it, and so is any other key.
|
|
52
|
+
*
|
|
53
|
+
* @function useMenuKeys
|
|
54
|
+
* @returns The `keydown` handler for the menu element, and a way to forget
|
|
55
|
+
* what has been typed.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useMenuKeys(): MenuKeys;
|
|
@@ -19,6 +19,7 @@ export * from './components/Collapses.js';
|
|
|
19
19
|
export * from './components/Tooltip.js';
|
|
20
20
|
export * from './components/Popover.js';
|
|
21
21
|
export * from './components/HoverCard.js';
|
|
22
|
+
export * from './components/ContextMenu.js';
|
|
22
23
|
export * from './components/Steps.js';
|
|
23
24
|
export * from './components/Sidebar.js';
|
|
24
25
|
export * from './components/Toast.js';
|
|
@@ -30,6 +31,7 @@ export * from './elements/Box.js';
|
|
|
30
31
|
export * from './elements/Button.js';
|
|
31
32
|
export * from './elements/Buttons.js';
|
|
32
33
|
export * from './elements/LinkButton.js';
|
|
34
|
+
export * from './elements/ToggleButton.js';
|
|
33
35
|
export * from './elements/Code.js';
|
|
34
36
|
export * from './elements/Content.js';
|
|
35
37
|
export * from './elements/Delete.js';
|