@tensor_1/react 2.47.0 → 2.49.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/README.md +540 -2
- package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
- package/dist/announce.d.ts +10 -0
- package/dist/announce.js +30 -0
- package/dist/chart-analytic.cjs +33 -25
- package/dist/chart-preset.cjs +23 -15
- package/dist/chart.cjs +23 -15
- package/dist/combobox-model.d.ts +10 -1
- package/dist/combobox-model.js +15 -0
- package/dist/command-palette-model.d.ts +44 -0
- package/dist/command-palette-model.js +36 -0
- package/dist/components/AccountMenu.d.ts +44 -0
- package/dist/components/AccountMenu.js +43 -0
- package/dist/components/AppShell.d.ts +45 -2
- package/dist/components/AppShell.js +116 -5
- package/dist/components/AuditLog.d.ts +128 -0
- package/dist/components/AuditLog.js +196 -0
- package/dist/components/BrandProfiles.js +4 -3
- package/dist/components/Breadcrumbs.d.ts +9 -2
- package/dist/components/Breadcrumbs.js +3 -2
- package/dist/components/Button.d.ts +12 -5
- package/dist/components/Button.js +7 -3
- package/dist/components/Card.d.ts +18 -1
- package/dist/components/Card.js +5 -1
- package/dist/components/ChangeHighlight.d.ts +30 -0
- package/dist/components/ChangeHighlight.js +21 -0
- package/dist/components/ChartCore.js +2 -1
- package/dist/components/Checkbox.d.ts +27 -1
- package/dist/components/Checkbox.js +31 -2
- package/dist/components/Chip.d.ts +7 -3
- package/dist/components/Chip.js +2 -2
- package/dist/components/CodeDisplay.d.ts +65 -0
- package/dist/components/CodeDisplay.js +124 -0
- package/dist/components/Combobox.d.ts +27 -6
- package/dist/components/Combobox.js +195 -58
- package/dist/components/CommandPalette.d.ts +36 -1
- package/dist/components/CommandPalette.js +254 -2
- package/dist/components/ContactCard.d.ts +66 -0
- package/dist/components/ContactCard.js +74 -0
- package/dist/components/Count.d.ts +24 -0
- package/dist/components/Count.js +32 -0
- package/dist/components/DashboardCanvas.js +14 -0
- package/dist/components/DataWorkspace.d.ts +167 -0
- package/dist/components/DataWorkspace.js +380 -0
- package/dist/components/DateFieldParts.d.ts +2 -1
- package/dist/components/DateFieldParts.js +7 -0
- package/dist/components/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker.js +67 -28
- package/dist/components/DateRangePicker.d.ts +12 -2
- package/dist/components/DateRangePicker.js +13 -12
- package/dist/components/DetailPage.d.ts +7 -1
- package/dist/components/DetailPage.js +2 -1
- package/dist/components/Dialogs.d.ts +71 -10
- package/dist/components/Dialogs.js +130 -30
- package/dist/components/DiffViewer.d.ts +23 -3
- package/dist/components/DiffViewer.js +26 -12
- package/dist/components/DiscardPrompt.js +16 -0
- package/dist/components/DisplayPreferences.d.ts +83 -0
- package/dist/components/DisplayPreferences.js +185 -0
- package/dist/components/EditorialHome.d.ts +23 -3
- package/dist/components/EditorialHome.js +16 -11
- package/dist/components/EntityPicker.d.ts +20 -3
- package/dist/components/EntityPicker.js +32 -13
- package/dist/components/FilterEditor.d.ts +18 -4
- package/dist/components/FilterEditor.js +141 -19
- package/dist/components/FocusOnMount.d.ts +282 -0
- package/dist/components/FocusOnMount.js +12 -0
- package/dist/components/InfoTip.js +11 -12
- package/dist/components/InlineEdit.d.ts +87 -20
- package/dist/components/InlineEdit.js +197 -54
- package/dist/components/Input.d.ts +12 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Kanban.d.ts +14 -3
- package/dist/components/Kanban.js +9 -4
- package/dist/components/Kbd.d.ts +6 -1
- package/dist/components/Kbd.js +6 -6
- package/dist/components/Lightbox.d.ts +41 -5
- package/dist/components/Lightbox.js +95 -9
- package/dist/components/MatchReview.d.ts +40 -1
- package/dist/components/MatchReview.js +130 -4
- package/dist/components/MetricInput.js +3 -2
- package/dist/components/Modal.d.ts +2 -1
- package/dist/components/Modal.js +13 -4
- package/dist/components/MotionList.d.ts +303 -0
- package/dist/components/MotionList.js +175 -0
- package/dist/components/NavFavourites.d.ts +5 -0
- package/dist/components/NavFavourites.js +7 -7
- package/dist/components/OtpInput.d.ts +33 -0
- package/dist/components/OtpInput.js +123 -0
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Pagination.js +6 -5
- package/dist/components/PasswordInput.d.ts +34 -0
- package/dist/components/PasswordInput.js +101 -0
- package/dist/components/Peek.js +3 -3
- package/dist/components/Popover.js +11 -0
- package/dist/components/PrintLayout.d.ts +63 -0
- package/dist/components/PrintLayout.js +114 -0
- package/dist/components/QrCode.d.ts +47 -0
- package/dist/components/QrCode.js +55 -0
- package/dist/components/QrScanner.d.ts +95 -0
- package/dist/components/QrScanner.js +266 -0
- package/dist/components/RelationshipGraph.d.ts +32 -1
- package/dist/components/RelationshipGraph.js +22 -6
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +268 -118
- package/dist/components/RelationshipGraphList.js +33 -6
- package/dist/components/RuleBuilder.js +39 -7
- package/dist/components/SchedulingAgenda.d.ts +3 -1
- package/dist/components/SchedulingCalendar.d.ts +3 -1
- package/dist/components/SchedulingCalendar.js +43 -4
- package/dist/components/SchedulingResourceDay.d.ts +57 -0
- package/dist/components/SchedulingResourceDay.js +287 -0
- package/dist/components/SchedulingTimeGrid.d.ts +3 -1
- package/dist/components/SchedulingTimeline.d.ts +3 -1
- package/dist/components/SearchSuggest.d.ts +23 -3
- package/dist/components/SearchSuggest.js +56 -18
- package/dist/components/Segmented.d.ts +39 -4
- package/dist/components/Segmented.js +39 -5
- package/dist/components/Select.d.ts +3 -2
- package/dist/components/Select.js +7 -1
- package/dist/components/ShortcutHint.d.ts +11 -10
- package/dist/components/ShortcutHint.js +44 -38
- package/dist/components/Sidebar.d.ts +36 -4
- package/dist/components/Sidebar.js +37 -12
- package/dist/components/SortableList.d.ts +45 -0
- package/dist/components/SortableList.js +147 -0
- package/dist/components/Stat.d.ts +28 -3
- package/dist/components/Stat.js +13 -3
- package/dist/components/States.d.ts +33 -1
- package/dist/components/States.js +43 -1
- package/dist/components/StatusPill.d.ts +14 -3
- package/dist/components/StatusPill.js +11 -3
- package/dist/components/Steps.js +2 -1
- package/dist/components/Table.d.ts +9 -2
- package/dist/components/Table.js +4 -2
- package/dist/components/TableControls.js +18 -58
- package/dist/components/TableOverflowProbe.d.ts +12 -0
- package/dist/components/TableOverflowProbe.js +27 -0
- package/dist/components/Tabs.d.ts +2 -1
- package/dist/components/Tabs.js +10 -2
- package/dist/components/TagInput.d.ts +67 -0
- package/dist/components/TagInput.js +342 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.js +2 -2
- package/dist/components/TimePicker.d.ts +80 -0
- package/dist/components/TimePicker.js +347 -0
- package/dist/components/Toast.d.ts +1 -1
- package/dist/components/Toast.js +109 -4
- package/dist/components/Tooltip.d.ts +8 -4
- package/dist/components/Tooltip.js +86 -28
- package/dist/components/Tree.d.ts +8 -0
- package/dist/components/Tree.js +11 -5
- package/dist/display-preferences-model.d.ts +53 -0
- package/dist/display-preferences-model.js +64 -0
- package/dist/emoji.cjs +143 -49
- package/dist/filter-model.d.ts +59 -3
- package/dist/filter-model.js +67 -2
- package/dist/hooks/useAnchoredPosition.js +14 -2
- package/dist/hooks/useChangeHighlight.d.ts +33 -0
- package/dist/hooks/useChangeHighlight.js +44 -0
- package/dist/hooks/useDeferredReorder.d.ts +32 -0
- package/dist/hooks/useDeferredReorder.js +47 -0
- package/dist/hooks/useDialog.d.ts +5 -0
- package/dist/hooks/useDialog.js +17 -3
- package/dist/hooks/useKeyboardGrab.d.ts +58 -0
- package/dist/hooks/useKeyboardGrab.js +118 -0
- package/dist/hooks/useOptimisticValue.d.ts +51 -0
- package/dist/hooks/useOptimisticValue.js +61 -0
- package/dist/hooks/useReducedMotion.d.ts +4 -1
- package/dist/hooks/useReducedMotion.js +7 -1
- package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
- package/dist/hooks/useResolvedFilterLabels.js +34 -0
- package/dist/hooks/useSlidingIndicator.d.ts +18 -0
- package/dist/hooks/useSlidingIndicator.js +80 -0
- package/dist/hooks/useVirtualRows.d.ts +21 -2
- package/dist/hooks/useVirtualRows.js +30 -3
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/index.cjs +19687 -13423
- package/dist/index.d.cts +3419 -651
- package/dist/index.d.ts +48 -18
- package/dist/index.js +153 -9
- package/dist/labels-context.d.ts +93 -3
- package/dist/motion.d.ts +11 -0
- package/dist/motion.js +35 -0
- package/dist/overlay-stack.d.ts +6 -0
- package/dist/overlay-stack.js +13 -0
- package/dist/qr-model.d.ts +65 -0
- package/dist/qr-model.js +323 -0
- package/dist/relationship-graph-model.d.ts +92 -3
- package/dist/relationship-graph-model.js +134 -15
- package/dist/reorder.d.ts +30 -0
- package/dist/reorder.js +74 -0
- package/dist/rich-text.cjs +46 -4
- package/dist/scheduling-resource-model.d.ts +76 -0
- package/dist/scheduling-resource-model.js +74 -0
- package/dist/search-suggest-model.js +3 -1
- package/dist/shell-context.d.ts +11 -0
- package/dist/shell-context.js +7 -0
- package/dist/time-field-model.d.ts +46 -0
- package/dist/time-field-model.js +152 -0
- package/dist/toast-store.d.ts +22 -3
- package/dist/toast-store.js +26 -9
- package/package.json +2 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { AriaAttributes, CSSProperties } from 'react';
|
|
3
|
+
import { Placement } from '../overlay-position.js';
|
|
4
|
+
|
|
5
|
+
/** Every word `TimePicker` renders or announces. */
|
|
6
|
+
interface TimePickerLabels {
|
|
7
|
+
/** The list button's name while no time is set. */
|
|
8
|
+
open: string;
|
|
9
|
+
/** The list button's name with a time set; `{time}` is the time as the field shows it. */
|
|
10
|
+
openSelected: string;
|
|
11
|
+
/** The list of times (the popover's and the listbox's name). */
|
|
12
|
+
list: string;
|
|
13
|
+
/** Shown when the typed text is not a time; `{example}` is a time in the field's own shape. */
|
|
14
|
+
invalidTime: string;
|
|
15
|
+
/** Shown when the typed time is before `min`; `{min}`. */
|
|
16
|
+
tooEarly: string;
|
|
17
|
+
/** Shown when the typed time is after `max`; `{max}`. */
|
|
18
|
+
tooLate: string;
|
|
19
|
+
/** Shown when the typed time is outside an overnight range (`min` after `max`); `{min}`, `{max}`. */
|
|
20
|
+
outside: string;
|
|
21
|
+
}
|
|
22
|
+
declare const DEFAULT_TIME_PICKER_LABELS: TimePickerLabels;
|
|
23
|
+
/** Why typed text was refused: not a time, or a time before `min` / after `max`. */
|
|
24
|
+
type TimeInputProblem = 'format' | 'early' | 'late' | 'outside';
|
|
25
|
+
interface TimePickerProps {
|
|
26
|
+
/** The time as `HH:mm` (24-hour), or `null` for none. */
|
|
27
|
+
value: string | null;
|
|
28
|
+
onValueChange: (value: string | null) => void;
|
|
29
|
+
/** Minutes the arrow keys step the minutes by, and between the times in the list. Default 15. */
|
|
30
|
+
minuteStep?: number;
|
|
31
|
+
/**
|
|
32
|
+
* First and last time that can be chosen (`HH:mm`, inclusive). A `min` after `max` (22:00 to
|
|
33
|
+
* 06:00) is an overnight range: it wraps round midnight, in the keys, the list and the check.
|
|
34
|
+
*/
|
|
35
|
+
min?: string;
|
|
36
|
+
max?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The locale that writes the time: 14:30 in `de`, 2:30 PM in `en-US`. Default: `UixLabelsProvider`
|
|
39
|
+
* `dateFormat.locale`, then the viewer's.
|
|
40
|
+
*/
|
|
41
|
+
locale?: string;
|
|
42
|
+
/** `true` writes 2:30 PM, `false` 14:30, whatever the locale. */
|
|
43
|
+
hour12?: boolean;
|
|
44
|
+
placeholder?: string;
|
|
45
|
+
size?: 'sm' | 'md';
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
readOnly?: boolean;
|
|
48
|
+
required?: boolean;
|
|
49
|
+
invalid?: boolean;
|
|
50
|
+
/** Submits the `HH:mm` value under this name (a hidden input), whatever the field shows. */
|
|
51
|
+
name?: string;
|
|
52
|
+
/** Lands on the text input, so a `<label htmlFor>` or `<Field>` names it. */
|
|
53
|
+
id?: string;
|
|
54
|
+
'aria-label'?: string;
|
|
55
|
+
'aria-labelledby'?: string;
|
|
56
|
+
'aria-describedby'?: string;
|
|
57
|
+
'aria-invalid'?: AriaAttributes['aria-invalid'];
|
|
58
|
+
'aria-required'?: AriaAttributes['aria-required'];
|
|
59
|
+
/** Where the list opens. Default `'bottom-start'`; it flips and shifts to stay on screen. */
|
|
60
|
+
placement?: Placement;
|
|
61
|
+
/** Told when typed text is refused, and `null` once the field is fine again. */
|
|
62
|
+
onInputProblem?: (problem: TimeInputProblem | null) => void;
|
|
63
|
+
onOpenChange?: (open: boolean) => void;
|
|
64
|
+
/** Translatable words; English defaults in {@link DEFAULT_TIME_PICKER_LABELS}. */
|
|
65
|
+
labels?: Partial<TimePickerLabels>;
|
|
66
|
+
className?: string;
|
|
67
|
+
style?: CSSProperties;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A time of day as a form field (HAR-1835), beside `DatePicker`: a text input that shows the time
|
|
71
|
+
* in the locale's shape (14:30 in German, 2:30 PM in en-US) and reads a typed one (`1430`, `9`,
|
|
72
|
+
* `2:30 pm`) on Enter and when focus leaves it; a clock button opens the times at `minuteStep` in a
|
|
73
|
+
* list. ArrowUp / ArrowDown step the part the caret is in (the hour, or the minutes by
|
|
74
|
+
* `minuteStep`), PageUp / PageDown step the hour, Alt+ArrowDown opens the list. Text that is not a
|
|
75
|
+
* time, or a time outside `min` / `max`, marks the field invalid, says why and leaves `value` alone.
|
|
76
|
+
* The value is `HH:mm`, what `<input type="time">` holds.
|
|
77
|
+
*/
|
|
78
|
+
declare const TimePicker: react.ForwardRefExoticComponent<TimePickerProps & react.RefAttributes<HTMLInputElement>>;
|
|
79
|
+
|
|
80
|
+
export { DEFAULT_TIME_PICKER_LABELS, type TimeInputProblem, TimePicker, type TimePickerLabels, type TimePickerProps };
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "../cx.js";
|
|
5
|
+
import { fillLabel } from "../fill-label.js";
|
|
6
|
+
import { ClockIcon } from "../icons/components.js";
|
|
7
|
+
import { useUixLabels } from "../labels-context.js";
|
|
8
|
+
import {
|
|
9
|
+
formatTimeKey,
|
|
10
|
+
isOvernightRange,
|
|
11
|
+
isTimeOutOfRange,
|
|
12
|
+
isValidTimeKey,
|
|
13
|
+
parseTimeInput,
|
|
14
|
+
stepTime,
|
|
15
|
+
timePartEnds,
|
|
16
|
+
timeSlots,
|
|
17
|
+
timeToMinutes
|
|
18
|
+
} from "../time-field-model.js";
|
|
19
|
+
import { useFieldPopover } from "./DateFieldParts.js";
|
|
20
|
+
import { Popover } from "./Popover.js";
|
|
21
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
22
|
+
const DEFAULT_TIME_PICKER_LABELS = {
|
|
23
|
+
open: "Choose time",
|
|
24
|
+
openSelected: "Change time, {time}",
|
|
25
|
+
list: "Times",
|
|
26
|
+
invalidTime: "Enter a time like {example}.",
|
|
27
|
+
tooEarly: "Choose {min} or later.",
|
|
28
|
+
tooLate: "Choose {max} or earlier.",
|
|
29
|
+
outside: "Choose a time from {min} to {max}."
|
|
30
|
+
};
|
|
31
|
+
const TimePicker = forwardRef(function TimePicker2({
|
|
32
|
+
value,
|
|
33
|
+
onValueChange,
|
|
34
|
+
minuteStep = 15,
|
|
35
|
+
min,
|
|
36
|
+
max,
|
|
37
|
+
locale: localeProp,
|
|
38
|
+
hour12,
|
|
39
|
+
placeholder,
|
|
40
|
+
size = "md",
|
|
41
|
+
disabled,
|
|
42
|
+
readOnly,
|
|
43
|
+
required,
|
|
44
|
+
invalid,
|
|
45
|
+
name,
|
|
46
|
+
id: idProp,
|
|
47
|
+
"aria-label": ariaLabel,
|
|
48
|
+
"aria-labelledby": ariaLabelledBy,
|
|
49
|
+
"aria-describedby": ariaDescribedBy,
|
|
50
|
+
"aria-invalid": ariaInvalid,
|
|
51
|
+
"aria-required": ariaRequired,
|
|
52
|
+
placement = "bottom-start",
|
|
53
|
+
onInputProblem,
|
|
54
|
+
onOpenChange,
|
|
55
|
+
labels: labelOverrides,
|
|
56
|
+
className,
|
|
57
|
+
style
|
|
58
|
+
}, forwardedRef) {
|
|
59
|
+
const uid = useId();
|
|
60
|
+
const id = idProp ?? `${uid}-input`;
|
|
61
|
+
const popoverId = `${uid}-times`;
|
|
62
|
+
const listId = `${uid}-list`;
|
|
63
|
+
const errorId = `${uid}-error`;
|
|
64
|
+
const uixLabels = useUixLabels();
|
|
65
|
+
const labels = { ...DEFAULT_TIME_PICKER_LABELS, ...uixLabels.timePicker, ...labelOverrides };
|
|
66
|
+
const locale = localeProp ?? uixLabels.dateFormat?.locale;
|
|
67
|
+
const anchorRef = useRef(null);
|
|
68
|
+
const inputRef = useRef(null);
|
|
69
|
+
const listRef = useRef(null);
|
|
70
|
+
useImperativeHandle(forwardedRef, () => inputRef.current);
|
|
71
|
+
const step = Math.max(1, Math.round(minuteStep));
|
|
72
|
+
const current = isValidTimeKey(value) ? value : null;
|
|
73
|
+
const [mounted, setMounted] = useState(false);
|
|
74
|
+
useEffect(() => setMounted(true), []);
|
|
75
|
+
const shownLocale = locale ?? (mounted ? void 0 : "en-GB");
|
|
76
|
+
const shownHour12 = hour12 ?? (locale || mounted ? void 0 : false);
|
|
77
|
+
const format = (time) => formatTimeKey(time, shownLocale, shownHour12);
|
|
78
|
+
const [text, setText] = useState(() => current ? format(current) : "");
|
|
79
|
+
const [problem, setProblemState] = useState(null);
|
|
80
|
+
const reported = useRef(null);
|
|
81
|
+
const setProblem = (next) => {
|
|
82
|
+
if (next !== reported.current) {
|
|
83
|
+
reported.current = next;
|
|
84
|
+
onInputProblem?.(next);
|
|
85
|
+
}
|
|
86
|
+
setProblemState(next);
|
|
87
|
+
};
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setText(current ? format(current) : "");
|
|
90
|
+
setProblem(null);
|
|
91
|
+
}, [current, locale, hour12, mounted]);
|
|
92
|
+
const { open, show, hide, triggerProps } = useFieldPopover(popoverId, () => inputRef.current?.focus({ preventScroll: true }), onOpenChange);
|
|
93
|
+
const locked = !!disabled || !!readOnly;
|
|
94
|
+
const commit = () => {
|
|
95
|
+
const typed = text.trim();
|
|
96
|
+
if (!typed) {
|
|
97
|
+
setProblem(null);
|
|
98
|
+
if (text) setText("");
|
|
99
|
+
if (value !== null) onValueChange(null);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (current && typed === format(current)) {
|
|
103
|
+
setProblem(null);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const parsed = parseTimeInput(typed, locale);
|
|
107
|
+
if (!parsed) {
|
|
108
|
+
setProblem("format");
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (isTimeOutOfRange(parsed, min, max)) {
|
|
112
|
+
setProblem(isOvernightRange(min, max) ? "outside" : min && isValidTimeKey(min) && parsed < min ? "early" : "late");
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
setProblem(null);
|
|
116
|
+
setText(format(parsed));
|
|
117
|
+
if (parsed !== value) onValueChange(parsed);
|
|
118
|
+
return true;
|
|
119
|
+
};
|
|
120
|
+
const choose = (time) => {
|
|
121
|
+
setProblem(null);
|
|
122
|
+
setText(format(time));
|
|
123
|
+
if (time !== value) onValueChange(time);
|
|
124
|
+
};
|
|
125
|
+
const onInputKeyDown = (event) => {
|
|
126
|
+
if (locked || event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
127
|
+
const { key, altKey } = event;
|
|
128
|
+
if (key === "ArrowDown" && altKey) {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
show();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (key === "ArrowUp" || key === "ArrowDown" || key === "PageUp" || key === "PageDown") {
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
const base = parseTimeInput(text, locale) ?? current;
|
|
136
|
+
const input = event.currentTarget;
|
|
137
|
+
const caret = input.selectionStart ?? 0;
|
|
138
|
+
const ends = base && input.value === format(base) ? timePartEnds(base, shownLocale, shownHour12) : null;
|
|
139
|
+
const hourEnd = ends?.hour ?? /^\s*\d{1,2}/.exec(input.value)?.[0].length ?? 0;
|
|
140
|
+
const onHour = key === "PageUp" || key === "PageDown" || !!base && caret <= hourEnd;
|
|
141
|
+
const sign = key === "ArrowUp" || key === "PageUp" ? 1 : -1;
|
|
142
|
+
let next;
|
|
143
|
+
if (!base) next = stepTime(null, 0, min, max);
|
|
144
|
+
else if (onHour) next = stepTime(base, sign * 60, min, max);
|
|
145
|
+
else {
|
|
146
|
+
const minutes = timeToMinutes(base);
|
|
147
|
+
const snapped = sign > 0 ? Math.floor(minutes / step) * step + step : Math.ceil(minutes / step) * step - step;
|
|
148
|
+
next = stepTime(base, snapped - minutes, min, max);
|
|
149
|
+
}
|
|
150
|
+
choose(next);
|
|
151
|
+
requestAnimationFrame(() => {
|
|
152
|
+
const el = inputRef.current;
|
|
153
|
+
if (!el || el.ownerDocument.activeElement !== el) return;
|
|
154
|
+
const moved = timePartEnds(next, shownLocale, shownHour12);
|
|
155
|
+
const at = moved ? onHour ? moved.hour : moved.minute : el.value.length;
|
|
156
|
+
try {
|
|
157
|
+
el.setSelectionRange(at, at);
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (key === "Enter" && text.trim() !== (current ? format(current) : "")) {
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
commit();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const pick = (time) => {
|
|
169
|
+
choose(time);
|
|
170
|
+
hide(false);
|
|
171
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
172
|
+
};
|
|
173
|
+
const describedBy = [ariaDescribedBy, problem ? errorId : void 0].filter(Boolean).join(" ") || void 0;
|
|
174
|
+
const isInvalid = !!invalid || !!problem || ariaInvalid === true || ariaInvalid === "true";
|
|
175
|
+
const example = format(min && isValidTimeKey(min) && min > "14:30" ? min : "14:30");
|
|
176
|
+
return /* @__PURE__ */ jsxs(
|
|
177
|
+
"div",
|
|
178
|
+
{
|
|
179
|
+
ref: anchorRef,
|
|
180
|
+
className: cx("uix-date-picker", "uix-time-picker", size === "sm" && "uix-date-picker--sm", className),
|
|
181
|
+
style,
|
|
182
|
+
onKeyDown: (event) => {
|
|
183
|
+
if (event.key !== "Escape" || !open) return;
|
|
184
|
+
event.stopPropagation();
|
|
185
|
+
event.preventDefault();
|
|
186
|
+
hide(false);
|
|
187
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
188
|
+
},
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-date-picker__control", children: [
|
|
191
|
+
/* @__PURE__ */ jsx(
|
|
192
|
+
"input",
|
|
193
|
+
{
|
|
194
|
+
ref: inputRef,
|
|
195
|
+
id,
|
|
196
|
+
type: "text",
|
|
197
|
+
autoComplete: "off",
|
|
198
|
+
spellCheck: false,
|
|
199
|
+
className: cx("uix-input", size === "sm" && "uix-input--sm", "uix-date-picker__input", "uix-time-picker__input"),
|
|
200
|
+
value: text,
|
|
201
|
+
placeholder: placeholder ?? example,
|
|
202
|
+
disabled,
|
|
203
|
+
readOnly,
|
|
204
|
+
required,
|
|
205
|
+
"aria-label": ariaLabel,
|
|
206
|
+
"aria-labelledby": ariaLabelledBy,
|
|
207
|
+
"aria-describedby": describedBy,
|
|
208
|
+
"aria-invalid": isInvalid || void 0,
|
|
209
|
+
"aria-required": ariaRequired,
|
|
210
|
+
onChange: (event) => {
|
|
211
|
+
setText(event.target.value);
|
|
212
|
+
if (problem) setProblem(null);
|
|
213
|
+
},
|
|
214
|
+
onBlur: () => {
|
|
215
|
+
if (!locked) commit();
|
|
216
|
+
},
|
|
217
|
+
onKeyDown: onInputKeyDown
|
|
218
|
+
}
|
|
219
|
+
),
|
|
220
|
+
/* @__PURE__ */ jsx(
|
|
221
|
+
"button",
|
|
222
|
+
{
|
|
223
|
+
type: "button",
|
|
224
|
+
className: "uix-date-picker__toggle",
|
|
225
|
+
disabled: locked,
|
|
226
|
+
"aria-label": current ? fillLabel(labels.openSelected, { time: format(current) }) : labels.open,
|
|
227
|
+
...triggerProps,
|
|
228
|
+
children: /* @__PURE__ */ jsx(ClockIcon, { size: "sm" })
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
] }),
|
|
232
|
+
name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: current ?? "", disabled }),
|
|
233
|
+
problem && /* @__PURE__ */ jsx("span", { id: errorId, className: "uix-field__error uix-date-picker__error", role: "alert", children: problem === "format" ? fillLabel(labels.invalidTime, { example }) : problem === "outside" ? fillLabel(labels.outside, { min: format(min ?? ""), max: format(max ?? "") }) : problem === "early" ? fillLabel(labels.tooEarly, { min: format(min ?? "") }) : fillLabel(labels.tooLate, { max: format(max ?? "") }) }),
|
|
234
|
+
/* @__PURE__ */ jsx(
|
|
235
|
+
Popover,
|
|
236
|
+
{
|
|
237
|
+
id: popoverId,
|
|
238
|
+
anchor: anchorRef,
|
|
239
|
+
placement,
|
|
240
|
+
className: "uix-time-picker__popover",
|
|
241
|
+
role: "dialog",
|
|
242
|
+
"aria-label": labels.list,
|
|
243
|
+
capHeight: true,
|
|
244
|
+
closeWhenAnchorHidden: true,
|
|
245
|
+
children: open && /* @__PURE__ */ jsx(
|
|
246
|
+
TimeList,
|
|
247
|
+
{
|
|
248
|
+
ref: listRef,
|
|
249
|
+
id: listId,
|
|
250
|
+
value: current,
|
|
251
|
+
step,
|
|
252
|
+
min,
|
|
253
|
+
max,
|
|
254
|
+
label: labels.list,
|
|
255
|
+
format,
|
|
256
|
+
onPick: pick
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
TimePicker.displayName = "TimePicker";
|
|
266
|
+
const TimeList = forwardRef(function TimeList2({ id, value, step, min, max, label, format, onPick }, ref) {
|
|
267
|
+
const slots = useMemo(() => timeSlots(step, min, max), [step, min, max]);
|
|
268
|
+
const nearest = () => {
|
|
269
|
+
if (!slots.length) return -1;
|
|
270
|
+
if (!value) return 0;
|
|
271
|
+
const exact = slots.indexOf(value);
|
|
272
|
+
if (exact >= 0) return exact;
|
|
273
|
+
const at = slots.findIndex((slot) => slot > value);
|
|
274
|
+
return at < 0 ? slots.length - 1 : Math.max(0, at - 1);
|
|
275
|
+
};
|
|
276
|
+
const [active, setActive] = useState(nearest);
|
|
277
|
+
const listRef = useRef(null);
|
|
278
|
+
useImperativeHandle(ref, () => listRef.current);
|
|
279
|
+
const optionId = (index) => `${id}-${index}`;
|
|
280
|
+
useEffect(() => {
|
|
281
|
+
listRef.current?.focus({ preventScroll: true });
|
|
282
|
+
}, []);
|
|
283
|
+
const placed = useRef(false);
|
|
284
|
+
useIsomorphicLayoutEffect(() => {
|
|
285
|
+
const list = listRef.current;
|
|
286
|
+
const el = list?.ownerDocument.getElementById(optionId(active));
|
|
287
|
+
if (!list || !el) return;
|
|
288
|
+
const top = el.offsetTop;
|
|
289
|
+
const bottom = top + el.offsetHeight;
|
|
290
|
+
if (!placed.current) {
|
|
291
|
+
placed.current = true;
|
|
292
|
+
list.scrollTop = top - (list.clientHeight - el.offsetHeight) / 2;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (top < list.scrollTop) list.scrollTop = top;
|
|
296
|
+
else if (bottom > list.scrollTop + list.clientHeight) list.scrollTop = bottom - list.clientHeight;
|
|
297
|
+
}, [active]);
|
|
298
|
+
const perHour = Math.max(1, Math.round(60 / step));
|
|
299
|
+
const onKeyDown = (event) => {
|
|
300
|
+
const last = slots.length - 1;
|
|
301
|
+
const moves = { ArrowDown: 1, ArrowUp: -1, PageDown: perHour, PageUp: -perHour };
|
|
302
|
+
if (event.key in moves) {
|
|
303
|
+
event.preventDefault();
|
|
304
|
+
setActive((index) => Math.max(0, Math.min(last, index + moves[event.key])));
|
|
305
|
+
} else if (event.key === "Home" || event.key === "End") {
|
|
306
|
+
event.preventDefault();
|
|
307
|
+
setActive(event.key === "Home" ? 0 : last);
|
|
308
|
+
} else if (event.key === "Enter" || event.key === " ") {
|
|
309
|
+
event.preventDefault();
|
|
310
|
+
const slot = slots[active];
|
|
311
|
+
if (slot) onPick(slot);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
return /* @__PURE__ */ jsx(
|
|
315
|
+
"div",
|
|
316
|
+
{
|
|
317
|
+
ref: listRef,
|
|
318
|
+
id,
|
|
319
|
+
role: "listbox",
|
|
320
|
+
tabIndex: 0,
|
|
321
|
+
"aria-label": label,
|
|
322
|
+
className: "uix-listbox uix-time-picker__list",
|
|
323
|
+
"aria-activedescendant": active >= 0 ? optionId(active) : void 0,
|
|
324
|
+
onKeyDown,
|
|
325
|
+
children: slots.map((slot, index) => /* @__PURE__ */ jsx(
|
|
326
|
+
"div",
|
|
327
|
+
{
|
|
328
|
+
id: optionId(index),
|
|
329
|
+
role: "option",
|
|
330
|
+
className: "uix-listbox__option",
|
|
331
|
+
"aria-selected": slot === value,
|
|
332
|
+
"data-active": index === active || void 0,
|
|
333
|
+
onPointerMove: () => {
|
|
334
|
+
if (index !== active) setActive(index);
|
|
335
|
+
},
|
|
336
|
+
onClick: () => onPick(slot),
|
|
337
|
+
children: /* @__PURE__ */ jsx("span", { className: "uix-listbox__label", children: format(slot) })
|
|
338
|
+
},
|
|
339
|
+
slot
|
|
340
|
+
))
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
export {
|
|
345
|
+
DEFAULT_TIME_PICKER_LABELS,
|
|
346
|
+
TimePicker
|
|
347
|
+
};
|
|
@@ -15,7 +15,7 @@ interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
|
15
15
|
onClose?: () => void;
|
|
16
16
|
leaving?: boolean;
|
|
17
17
|
}
|
|
18
|
-
declare function Toast({ title, message, tone, icon, action, onClose, leaving, dismissLabel: dismissLabelProp, className, ...props }: ToastProps): react.JSX.Element;
|
|
18
|
+
declare function Toast({ title, message, tone, icon, action, onClose, leaving, dismissLabel: dismissLabelProp, className, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, ...props }: ToastProps): react.JSX.Element;
|
|
19
19
|
interface ToasterProps extends HTMLAttributes<HTMLDivElement> {
|
|
20
20
|
/** TENSOR RX-125 (UIX-04): translatable; English default. */
|
|
21
21
|
regionLabel?: string;
|
package/dist/components/Toast.js
CHANGED
|
@@ -1,11 +1,91 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { useUixLabels } from "../labels-context.js";
|
|
6
|
+
import { prefersReducedMotion } from "../hooks/useReducedMotion.js";
|
|
7
|
+
import { tokenMs } from "../motion.js";
|
|
8
|
+
import { XIcon } from "../icons/components.js";
|
|
6
9
|
import { toast as defaultToast } from "../toast-store.js";
|
|
7
10
|
const ToasterContext = createContext(null);
|
|
8
|
-
|
|
11
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
12
|
+
const SWIPE_VELOCITY = 0.11;
|
|
13
|
+
const SWIPE_SLOP = 6;
|
|
14
|
+
const SWIPE_WINDOW = 100;
|
|
15
|
+
function releaseVelocity(samples, x, t) {
|
|
16
|
+
const recent = samples.filter((s) => t - s.t <= SWIPE_WINDOW);
|
|
17
|
+
if (recent.length === 0) return 0;
|
|
18
|
+
return (x - recent[0].x) / Math.max(1, t - recent[0].t);
|
|
19
|
+
}
|
|
20
|
+
function useSwipeToDismiss(onClose, own) {
|
|
21
|
+
const drag = useRef(null);
|
|
22
|
+
const end = (e) => {
|
|
23
|
+
const d = drag.current;
|
|
24
|
+
drag.current = null;
|
|
25
|
+
if (!d?.active || !onClose) return;
|
|
26
|
+
const el = e.currentTarget;
|
|
27
|
+
el.removeAttribute("data-swiping");
|
|
28
|
+
const v = releaseVelocity(d.samples, e.clientX, e.timeStamp);
|
|
29
|
+
const fling = Math.abs(v) > SWIPE_VELOCITY && Math.sign(v) === Math.sign(d.dx);
|
|
30
|
+
if (e.type === "pointerup" && (fling || Math.abs(d.dx) > el.offsetWidth / 3)) {
|
|
31
|
+
if (!prefersReducedMotion()) el.style.translate = `${Math.sign(d.dx) * (el.offsetWidth + 32)}px 0`;
|
|
32
|
+
onClose();
|
|
33
|
+
} else {
|
|
34
|
+
el.style.translate = "";
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
onPointerDown: (e) => {
|
|
39
|
+
own.onPointerDown?.(e);
|
|
40
|
+
if (!onClose || e.defaultPrevented || e.button !== 0) return;
|
|
41
|
+
if (e.target.closest('button, a, input, textarea, select, [role="button"]')) return;
|
|
42
|
+
drag.current = { id: e.pointerId, x0: e.clientX, y0: e.clientY, dx: 0, samples: [{ x: e.clientX, t: e.timeStamp }], active: false };
|
|
43
|
+
},
|
|
44
|
+
onPointerMove: (e) => {
|
|
45
|
+
own.onPointerMove?.(e);
|
|
46
|
+
const d = drag.current;
|
|
47
|
+
if (!d || d.id !== e.pointerId) return;
|
|
48
|
+
const dx = e.clientX - d.x0;
|
|
49
|
+
if (!d.active) {
|
|
50
|
+
if (Math.abs(dx) < SWIPE_SLOP) return;
|
|
51
|
+
if (Math.abs(e.clientY - d.y0) > Math.abs(dx)) {
|
|
52
|
+
drag.current = null;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
d.active = true;
|
|
56
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
57
|
+
e.currentTarget.setAttribute("data-swiping", "");
|
|
58
|
+
}
|
|
59
|
+
d.samples = [...d.samples.filter((s) => e.timeStamp - s.t <= SWIPE_WINDOW), { x: e.clientX, t: e.timeStamp }];
|
|
60
|
+
d.dx = dx;
|
|
61
|
+
e.currentTarget.style.translate = `${dx}px 0`;
|
|
62
|
+
},
|
|
63
|
+
onPointerUp: (e) => {
|
|
64
|
+
own.onPointerUp?.(e);
|
|
65
|
+
end(e);
|
|
66
|
+
},
|
|
67
|
+
onPointerCancel: (e) => {
|
|
68
|
+
own.onPointerCancel?.(e);
|
|
69
|
+
end(e);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function Toast({
|
|
74
|
+
title,
|
|
75
|
+
message,
|
|
76
|
+
tone,
|
|
77
|
+
icon,
|
|
78
|
+
action,
|
|
79
|
+
onClose,
|
|
80
|
+
leaving,
|
|
81
|
+
dismissLabel: dismissLabelProp,
|
|
82
|
+
className,
|
|
83
|
+
onPointerDown,
|
|
84
|
+
onPointerMove,
|
|
85
|
+
onPointerUp,
|
|
86
|
+
onPointerCancel,
|
|
87
|
+
...props
|
|
88
|
+
}) {
|
|
9
89
|
const uixLabels = useUixLabels();
|
|
10
90
|
const dismissLabel = dismissLabelProp ?? uixLabels.toast?.dismiss ?? "Dismiss";
|
|
11
91
|
const assertive = tone === "danger";
|
|
@@ -28,6 +108,7 @@ function Toast({ title, message, tone, icon, action, onClose, leaving, dismissLa
|
|
|
28
108
|
}
|
|
29
109
|
onClose?.();
|
|
30
110
|
};
|
|
111
|
+
const swipe = useSwipeToDismiss(onClose, { onPointerDown, onPointerMove, onPointerUp, onPointerCancel });
|
|
31
112
|
const ownLiveRegion = assertive || !toaster;
|
|
32
113
|
return /* @__PURE__ */ jsxs(
|
|
33
114
|
"div",
|
|
@@ -37,6 +118,7 @@ function Toast({ title, message, tone, icon, action, onClose, leaving, dismissLa
|
|
|
37
118
|
role: ownLiveRegion ? assertive ? "alert" : "status" : void 0,
|
|
38
119
|
"aria-live": ownLiveRegion ? assertive ? "assertive" : "polite" : void 0,
|
|
39
120
|
...props,
|
|
121
|
+
...swipe,
|
|
40
122
|
children: [
|
|
41
123
|
icon && /* @__PURE__ */ jsx("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
|
|
42
124
|
/* @__PURE__ */ jsxs("div", { className: "uix-toast__body", ref: bodyRef, children: [
|
|
@@ -44,7 +126,7 @@ function Toast({ title, message, tone, icon, action, onClose, leaving, dismissLa
|
|
|
44
126
|
message && /* @__PURE__ */ jsx("div", { className: "uix-toast__msg", children: message })
|
|
45
127
|
] }),
|
|
46
128
|
action != null && /* @__PURE__ */ jsx("div", { className: "uix-toast__action-slot", children: action }),
|
|
47
|
-
onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-toast__close", onClick: handleClose, "aria-label": dismissLabel, children:
|
|
129
|
+
onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-toast__close", onClick: handleClose, "aria-label": dismissLabel, children: /* @__PURE__ */ jsx(XIcon, {}) })
|
|
48
130
|
]
|
|
49
131
|
}
|
|
50
132
|
);
|
|
@@ -124,7 +206,7 @@ function useToastTimers(store, visible, paused) {
|
|
|
124
206
|
timer = { version: record.version, remaining: record.duration, start: now };
|
|
125
207
|
map.set(record.id, timer);
|
|
126
208
|
}
|
|
127
|
-
if (paused) {
|
|
209
|
+
if (paused && record.pauseOnHover !== false) {
|
|
128
210
|
if (timer.handle != null) {
|
|
129
211
|
clearTimeout(timer.handle);
|
|
130
212
|
timer.handle = void 0;
|
|
@@ -168,6 +250,28 @@ function Toaster({ children, regionLabel: regionLabelProp, store = defaultToast.
|
|
|
168
250
|
return () => document.removeEventListener("visibilitychange", sync);
|
|
169
251
|
}, []);
|
|
170
252
|
useToastTimers(store, visible, hovered || focused || hidden);
|
|
253
|
+
const regionRef = useRef(null);
|
|
254
|
+
const tops = useRef(/* @__PURE__ */ new Map());
|
|
255
|
+
useIsomorphicLayoutEffect(() => {
|
|
256
|
+
const region = regionRef.current;
|
|
257
|
+
if (!region) return;
|
|
258
|
+
const base = region.getBoundingClientRect().top;
|
|
259
|
+
const next = /* @__PURE__ */ new Map();
|
|
260
|
+
const glide = !prefersReducedMotion();
|
|
261
|
+
for (const el of Array.from(region.querySelectorAll(":scope > [data-toast-id]"))) {
|
|
262
|
+
const id = el.dataset.toastId;
|
|
263
|
+
const top = base + el.offsetTop;
|
|
264
|
+
next.set(id, top);
|
|
265
|
+
const before = tops.current.get(id);
|
|
266
|
+
if (!glide || before === void 0 || Math.abs(before - top) < 1 || typeof el.animate !== "function") continue;
|
|
267
|
+
el.animate([{ transform: `translateY(${before - top}px)` }, { transform: "translateY(0)" }], {
|
|
268
|
+
duration: tokenMs("--uix-dur", 160, el),
|
|
269
|
+
easing: getComputedStyle(el).getPropertyValue("--uix-ease-out").trim() || "ease-out",
|
|
270
|
+
composite: "add"
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
tops.current = next;
|
|
274
|
+
});
|
|
171
275
|
const handleKeyDown = (event) => {
|
|
172
276
|
onKeyDown?.(event);
|
|
173
277
|
if (event.defaultPrevented || event.key !== "Escape") return;
|
|
@@ -180,6 +284,7 @@ function Toaster({ children, regionLabel: regionLabelProp, store = defaultToast.
|
|
|
180
284
|
return /* @__PURE__ */ jsx(ToasterContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxs(
|
|
181
285
|
"div",
|
|
182
286
|
{
|
|
287
|
+
ref: regionRef,
|
|
183
288
|
className: cx("uix-toaster", className),
|
|
184
289
|
role: "region",
|
|
185
290
|
"aria-label": regionLabel,
|
|
@@ -16,10 +16,11 @@ interface TooltipProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'content'>
|
|
|
16
16
|
placement?: Placement;
|
|
17
17
|
/**
|
|
18
18
|
* The trigger's keyboard shortcut, in `KbdCombo` key names, e.g. `['Mod', 'K']` (HAR-2031):
|
|
19
|
-
* shown with `Kbd` after the text
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* shown with `Kbd` after the text. Screen readers hear it once, in the trigger's description
|
|
20
|
+
* after the text ("Keyboard shortcuts, Shift+?"), the same rule as a `Button` with `shortcut`
|
|
21
|
+
* (HAR-2416). Default: the `shortcut` of a `Button` child, so a Tooltip around a Button with a
|
|
22
|
+
* shortcut shows one bubble with the label and the keys. The kit only shows it: the product
|
|
23
|
+
* binds the key.
|
|
23
24
|
*/
|
|
24
25
|
shortcut?: KeyShortcut;
|
|
25
26
|
children?: ReactNode;
|
|
@@ -31,6 +32,9 @@ interface TooltipProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'content'>
|
|
|
31
32
|
* (flip/shift), shown on hover and keyboard focus, dismissed on blur or Escape
|
|
32
33
|
* (document-level, per WCAG 1.4.13), and hoverable: the bubble stays open while
|
|
33
34
|
* the pointer is over it (UIX-A11Y-1).
|
|
35
|
+
*
|
|
36
|
+
* While the bubble is open it takes the first Escape (HAR-2415), also on a combobox-style trigger
|
|
37
|
+
* whose list is open (a Select, a date field): one Escape closes the bubble, the next one the list.
|
|
34
38
|
*/
|
|
35
39
|
declare function Tooltip({ label, content, placement, shortcut, className, children, ...props }: TooltipProps): react.JSX.Element;
|
|
36
40
|
|