@astryxdesign/core 0.7.7-canary.ae97fa8 → 0.7.7-canary.b377b21
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/AlertDialog/AlertDialog.d.ts +4 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +36 -6
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +22 -3
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +3 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +17 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +13 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts +4 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +14 -4
- package/dist/ContextMenu/ContextMenu.js +2 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +7 -31
- package/dist/Field/Field.js +2 -2
- package/dist/HoverCard/HoverCard.d.ts +4 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.d.ts +5 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +17 -31
- package/dist/Icon/Icon.d.ts +5 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +5 -2
- package/dist/Layer/usePressPin.d.ts +17 -5
- package/dist/Layer/usePressPin.d.ts.map +1 -1
- package/dist/Layer/usePressPin.js +62 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +18 -0
- package/dist/PowerSearch/PowerSearch.d.ts +36 -3
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +433 -127
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +100 -0
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -0
- package/dist/PowerSearch/PowerSearchBottomSheet.js +1913 -0
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts +32 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +17 -6
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts +38 -3
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +170 -61
- package/dist/PowerSearch/formatFilterValue.d.ts +7 -0
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +11 -1
- package/dist/PowerSearch/formatTokenValue.d.ts +28 -0
- package/dist/PowerSearch/formatTokenValue.d.ts.map +1 -0
- package/dist/PowerSearch/formatTokenValue.js +160 -0
- package/dist/PowerSearch/powerSearchSheetUtils.d.ts +65 -0
- package/dist/PowerSearch/powerSearchSheetUtils.d.ts.map +1 -0
- package/dist/PowerSearch/powerSearchSheetUtils.js +168 -0
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +3 -2
- package/dist/RadioList/RadioListItem.d.ts +1 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -3
- package/dist/Resizable/ResizeHandle.d.ts +2 -1
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +99 -77
- package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts.map +1 -1
- package/dist/SegmentedControl/useSegmentedSelectionMotion.js +3 -3
- package/dist/Slider/sliderTouchController.js +2 -2
- package/dist/Spinner/Spinner.d.ts +1 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +60 -58
- package/dist/Switch/useSwitchTouch.js +4 -4
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +29 -8
- package/dist/TextInput/TextInput.d.ts +2 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +10 -7
- package/dist/Toast/Toast.d.ts +11 -1
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +25 -15
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +94 -34
- package/dist/Toast/types.d.ts +9 -3
- package/dist/Toast/types.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +19 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +34 -53
- package/dist/Typeahead/TypeaheadItem.d.ts +2 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/animator/createAnimator.d.ts +98 -0
- package/dist/animator/createAnimator.d.ts.map +1 -0
- package/dist/animator/createAnimator.js +259 -0
- package/dist/astryx.css +35 -6
- package/dist/gestures/PressTracker.d.ts.map +1 -1
- package/dist/gestures/PressTracker.js +4 -3
- package/dist/hooks/actionGroupTracker.d.ts +4 -1
- package/dist/hooks/actionGroupTracker.d.ts.map +1 -1
- package/dist/hooks/actionGroupTracker.js +13 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/pressGroupContext.d.ts +6 -0
- package/dist/hooks/pressGroupContext.d.ts.map +1 -0
- package/dist/hooks/pressGroupContext.js +20 -0
- package/dist/hooks/useActionGroupTracking.d.ts +53 -0
- package/dist/hooks/useActionGroupTracking.d.ts.map +1 -0
- package/dist/hooks/useActionGroupTracking.js +174 -0
- package/dist/hooks/useAnimator.d.ts +41 -0
- package/dist/hooks/useAnimator.d.ts.map +1 -0
- package/dist/hooks/useAnimator.js +70 -0
- package/dist/hooks/useAttachment.d.ts +1 -1
- package/dist/hooks/useAttachment.js +1 -1
- package/dist/hooks/useInputStatusIcon.d.ts +1 -1
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +2 -2
- package/dist/hooks/useLongPress.d.ts +6 -2
- package/dist/hooks/useLongPress.d.ts.map +1 -1
- package/dist/hooks/useLongPress.js +95 -15
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts +8 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +42 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.d.ts.map +1 -1
- package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.js +6 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts +8 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.js +14 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +30 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +30 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/internal/indicatorPress.stylex.d.ts +20 -0
- package/dist/internal/indicatorPress.stylex.d.ts.map +1 -0
- package/dist/internal/indicatorPress.stylex.js +26 -0
- package/dist/motion/animator.d.ts +14 -14
- package/dist/motion/animator.d.ts.map +1 -1
- package/dist/motion/animator.js +41 -18
- package/dist/motion/uikit/alert.d.ts +41 -0
- package/dist/motion/uikit/alert.d.ts.map +1 -0
- package/dist/motion/uikit/alert.js +43 -0
- package/dist/privateAttributes/pressGroupItem.stylex.d.ts +15 -0
- package/dist/privateAttributes/pressGroupItem.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/pressGroupItem.stylex.js +23 -0
- package/dist/utils/focusReturn.d.ts +15 -0
- package/dist/utils/focusReturn.d.ts.map +1 -1
- package/dist/utils/focusReturn.js +28 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +3 -2
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +3 -2
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +19 -6
- package/dist/utils/triggerFocus.d.ts +36 -0
- package/dist/utils/triggerFocus.d.ts.map +1 -0
- package/dist/utils/triggerFocus.js +65 -0
- package/locales/en.json +120 -0
- package/locales/pseudo.json +90 -0
- package/package.json +9 -4
- package/src/AlertDialog/AlertDialog.doc.mjs +2 -2
- package/src/AlertDialog/AlertDialog.tsx +37 -5
- package/src/BottomSheet/BottomSheetPanel.tsx +33 -3
- package/src/BottomSheet/useSheetGestures.ts +3 -1
- package/src/Button/Button.tsx +26 -4
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.tsx +36 -9
- package/src/ComplexSelector/ComplexSelector.tsx +20 -5
- package/src/ContextMenu/ContextMenu.tsx +2 -2
- package/src/Dialog/Dialog.tsx +10 -31
- package/src/Field/Field.tsx +2 -2
- package/src/HoverCard/HoverCard.doc.mjs +4 -2
- package/src/HoverCard/HoverCard.tsx +4 -3
- package/src/HoverCard/useHoverCard.doc.mjs +178 -36
- package/src/HoverCard/useHoverCard.tsx +46 -52
- package/src/Icon/Icon.doc.mjs +49 -8
- package/src/Icon/Icon.tsx +15 -7
- package/src/Layer/usePressPin.ts +81 -15
- package/src/Lightbox/Lightbox.tsx +18 -0
- package/src/PowerSearch/PowerSearch.doc.mjs +54 -5
- package/src/PowerSearch/PowerSearch.tsx +609 -155
- package/src/PowerSearch/PowerSearchBottomSheet.tsx +2515 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +28 -6
- package/src/PowerSearch/PowerSearchValueEditor.tsx +203 -38
- package/src/PowerSearch/formatFilterValue.ts +18 -1
- package/src/PowerSearch/formatTokenValue.ts +215 -0
- package/src/PowerSearch/powerSearchSheetUtils.ts +224 -0
- package/src/RadioList/RadioList.tsx +3 -2
- package/src/RadioList/RadioListItem.tsx +5 -3
- package/src/Resizable/Resizable.doc.mjs +5 -4
- package/src/Resizable/ResizeHandle.tsx +167 -109
- package/src/SegmentedControl/useSegmentedSelectionMotion.ts +6 -3
- package/src/Slider/sliderTouchController.ts +2 -2
- package/src/Spinner/Spinner.tsx +77 -63
- package/src/Switch/useSwitchTouch.ts +4 -4
- package/src/Table/BaseTable.tsx +46 -12
- package/src/TextInput/TextInput.tsx +11 -10
- package/src/Toast/Toast.doc.mjs +4 -3
- package/src/Toast/Toast.tsx +52 -32
- package/src/Toast/ToastViewport.tsx +121 -35
- package/src/Toast/types.ts +9 -3
- package/src/Tooltip/useTooltip.doc.mjs +24 -0
- package/src/Tooltip/useTooltip.tsx +61 -56
- package/src/Typeahead/TypeaheadItem.doc.mjs +6 -3
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/animator/createAnimator.doc.mjs +153 -0
- package/src/animator/createAnimator.ts +324 -0
- package/src/gestures/PressTracker.ts +4 -3
- package/src/gestures/README.md +7 -1
- package/src/hooks/actionGroupTracker.ts +20 -5
- package/src/hooks/index.ts +2 -0
- package/src/hooks/pressGroupContext.ts +21 -0
- package/src/hooks/useActionGroupTracking.ts +224 -0
- package/src/hooks/useAnimator.doc.mjs +109 -0
- package/src/hooks/useAnimator.ts +67 -0
- package/src/hooks/useAttachment.ts +1 -1
- package/src/hooks/useInputStatusIcon.tsx +3 -2
- package/src/hooks/useLongPress.doc.mjs +2 -2
- package/src/hooks/useLongPress.ts +136 -15
- package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +43 -0
- package/src/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.ts +6 -0
- package/src/i18n/generated-english/PowerSearch/formatTokenValue.generated.ts +15 -0
- package/src/i18n/generated-locales/en.generated.ts +41 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +42 -0
- package/src/index.ts +13 -0
- package/src/internal/indicatorPress.stylex.ts +24 -0
- package/src/motion/README.md +8 -5
- package/src/motion/animator.ts +61 -29
- package/src/motion/uikit/alert.ts +43 -0
- package/src/privateAttributes/pressGroupItem.stylex.ts +23 -0
- package/src/utils/focusReturn.ts +30 -0
- package/src/utils/interactionOverlay.stylex.ts +3 -2
- package/src/utils/pressFeedback.ts +19 -6
- package/src/utils/triggerFocus.ts +80 -0
package/dist/Table/BaseTable.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - /packages/core/src/Table/index.ts (exports if types change)
|
|
15
15
|
* - /packages/cli/assets/templates/blocks/components/Table/ (showcase blocks)
|
|
16
16
|
*/
|
|
17
|
-
import { memo, useRef } from 'react';
|
|
17
|
+
import { memo, useId, useRef } from 'react';
|
|
18
18
|
import { isRenderable } from "../utils/isRenderable.js";
|
|
19
19
|
import * as stylex from '@stylexjs/stylex';
|
|
20
20
|
import "../theme/tokens.stylex.js";
|
|
@@ -317,6 +317,7 @@ function BaseTableInner({
|
|
|
317
317
|
});
|
|
318
318
|
|
|
319
319
|
// --- Plugin pipeline: header cells ---
|
|
320
|
+
const headerLabelIdBase = useId();
|
|
320
321
|
const headerCells = resolvedColumns.map((col, columnIndex) => {
|
|
321
322
|
const headerContent = col.header ?? col.key;
|
|
322
323
|
|
|
@@ -367,16 +368,36 @@ function BaseTableInner({
|
|
|
367
368
|
below
|
|
368
369
|
} = cellRenderProps;
|
|
369
370
|
const hasSlots = before != null || after != null || overlay != null || below != null;
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
children: [resolvedContent, after]
|
|
376
|
-
}) : resolvedContent, overlay, below]
|
|
371
|
+
const labelRow = isRenderable(after) ? /*#__PURE__*/_jsxs("div", {
|
|
372
|
+
...{
|
|
373
|
+
className: "x3nfvp2 x6s0dn4 xzye2dw xeuugli"
|
|
374
|
+
},
|
|
375
|
+
children: [resolvedContent, after]
|
|
377
376
|
}) : resolvedContent;
|
|
377
|
+
|
|
378
|
+
// The overlay is a control of its own. Keep its name and value out of the
|
|
379
|
+
// header's name.
|
|
380
|
+
const namesOwnHeader = isRenderable(overlay) && mergedHtmlProps['aria-label'] == null && mergedHtmlProps['aria-labelledby'] == null;
|
|
381
|
+
const labelId = `${headerLabelIdBase}-label-${columnIndex}`;
|
|
382
|
+
const belowId = `${headerLabelIdBase}-below-${columnIndex}`;
|
|
383
|
+
const hasBelow = isRenderable(below);
|
|
384
|
+
const headerInner = !hasSlots ? resolvedContent : namesOwnHeader ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
385
|
+
children: [/*#__PURE__*/_jsxs("span", {
|
|
386
|
+
id: labelId,
|
|
387
|
+
children: [before, labelRow]
|
|
388
|
+
}), overlay, hasBelow && /*#__PURE__*/_jsx("div", {
|
|
389
|
+
id: belowId,
|
|
390
|
+
children: below
|
|
391
|
+
})]
|
|
392
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
393
|
+
children: [before, labelRow, overlay, below]
|
|
394
|
+
});
|
|
395
|
+
const headerNameProps = namesOwnHeader ? {
|
|
396
|
+
'aria-labelledby': hasBelow ? `${labelId} ${belowId}` : labelId
|
|
397
|
+
} : {};
|
|
378
398
|
return /*#__PURE__*/_jsx(HeaderCellComponent, {
|
|
379
399
|
...mergedHtmlProps,
|
|
400
|
+
...headerNameProps,
|
|
380
401
|
...headerTitleProp,
|
|
381
402
|
contextMenuActions: cellRenderProps.contextMenuActions,
|
|
382
403
|
xstyle: cellRenderProps.xstyle,
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react';
|
|
16
16
|
import * as stylex from '@stylexjs/stylex';
|
|
17
|
-
import {
|
|
18
|
-
import { type IconType } from '../Icon/
|
|
17
|
+
import type { InputStatus } from '../Field/types.js';
|
|
18
|
+
import { type IconType } from '../Icon/Icon.js';
|
|
19
19
|
import { type TextEntryTraitProps } from '../Field/textEntryTraits.js';
|
|
20
20
|
declare const sizeStyles: Readonly<{
|
|
21
21
|
readonly sm: Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../src/TextInput/TextInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAOL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../src/TextInput/TextInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -20,13 +20,16 @@ import { use, useId, useOptimistic, useTransition, useCallback, useRef } from 'r
|
|
|
20
20
|
import * as stylex from '@stylexjs/stylex';
|
|
21
21
|
import "../theme/tokens.stylex.js";
|
|
22
22
|
import { colorVars, sizeVars, typographyVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
23
|
-
import { Field
|
|
24
|
-
import {
|
|
23
|
+
import { Field } from "../Field/Field.js";
|
|
24
|
+
import { InputClearButton } from "../Field/InputClearButton.js";
|
|
25
|
+
import { inputWrapperStyles, inputStatusBorderStyles, inputStatusHoverShadowStyles, inputStatusFocusWithinStyles } from "../Field/inputStyles.stylex.js";
|
|
26
|
+
import { renderIconSlot } from "../Icon/Icon.js";
|
|
25
27
|
import { isRenderable } from "../utils/isRenderable.js";
|
|
26
|
-
import { Spinner } from "../Spinner/
|
|
27
|
-
import { useTooltip } from "../Tooltip/
|
|
28
|
-
import { VisuallyHidden } from "../VisuallyHidden/
|
|
29
|
-
import { getInputARIA
|
|
28
|
+
import { Spinner } from "../Spinner/Spinner.js";
|
|
29
|
+
import { useTooltip } from "../Tooltip/useTooltip.js";
|
|
30
|
+
import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
|
|
31
|
+
import { getInputARIA } from "../utils/inputAria.js";
|
|
32
|
+
import { isImeKeyEvent } from "../utils/ime.js";
|
|
30
33
|
import { textEntryTraitAttributes } from "../Field/textEntryTraits.js";
|
|
31
34
|
import { joinAriaIDs } from "../utils/inputAria.js";
|
|
32
35
|
const sizeStyles = {
|
|
@@ -47,7 +50,7 @@ import { groupStyles, inputGroupItemProps } from "../InputGroup/groupStyles.js";
|
|
|
47
50
|
|
|
48
51
|
// Re-export shared types for convenience
|
|
49
52
|
|
|
50
|
-
import { mergeProps } from "../utils/
|
|
53
|
+
import { mergeProps } from "../utils/mergeProps.js";
|
|
51
54
|
import { useSize } from "../SizeContext/SizeContext.js";
|
|
52
55
|
import { useInputContainer } from "../hooks/useInputContainer.js";
|
|
53
56
|
import { useInputStatusIcon } from "../hooks/useInputStatusIcon.js";
|
package/dist/Toast/Toast.d.ts
CHANGED
|
@@ -18,6 +18,16 @@ export interface ToastProps {
|
|
|
18
18
|
}
|
|
19
19
|
interface ToastSurfaceProps extends ToastProps {
|
|
20
20
|
gestureDirection: ToastGestureDirection;
|
|
21
|
+
/**
|
|
22
|
+
* Changes when a uniqueID overwrite updates this card in place: the new
|
|
23
|
+
* toast's auto-hide timer starts over.
|
|
24
|
+
*/
|
|
25
|
+
timerKey?: string;
|
|
26
|
+
/**
|
|
27
|
+
* False when the viewport announces the toast: the card then carries no
|
|
28
|
+
* live region of its own, so an update in place is announced once.
|
|
29
|
+
*/
|
|
30
|
+
isLiveRegion?: boolean;
|
|
21
31
|
}
|
|
22
32
|
/**
|
|
23
33
|
* Individual toast notification.
|
|
@@ -43,7 +53,7 @@ export declare function Toast(props: ToastProps): import("react").JSX.Element;
|
|
|
43
53
|
export declare namespace Toast {
|
|
44
54
|
var displayName: string;
|
|
45
55
|
}
|
|
46
|
-
export declare function ToastSurface({ type, body, endContent, isAutoHide, autoHideDuration, isExiting, onDismiss, renderContent, gestureDirection, }: ToastSurfaceProps): import("react").JSX.Element;
|
|
56
|
+
export declare function ToastSurface({ type, body, endContent, isAutoHide, autoHideDuration, isExiting, onDismiss, renderContent, gestureDirection, timerKey, isLiveRegion, }: ToastSurfaceProps): import("react").JSX.Element;
|
|
47
57
|
export declare namespace ToastSurface {
|
|
48
58
|
var displayName: string;
|
|
49
59
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../src/Toast/Toast.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAa,SAAS,EAAY,MAAM,OAAO,CAAC;AAkB5D,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAkB,KAAK,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AA8F9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,UAAU,iBAAkB,SAAQ,UAAU;IAC5C,gBAAgB,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../src/Toast/Toast.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAa,SAAS,EAAY,MAAM,OAAO,CAAC;AAkB5D,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAkB,KAAK,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AA8F9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,UAAU,iBAAkB,SAAQ,UAAU;IAC5C,gBAAgB,EAAE,qBAAqB,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,+BAEtC;yBAFe,KAAK;;;AAOrB,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,SAAiB,EACjB,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,YAAmB,GACpB,EAAE,iBAAiB,+BAqOnB;yBAjPe,YAAY"}
|
package/dist/Toast/Toast.js
CHANGED
|
@@ -85,7 +85,9 @@ export function ToastSurface({
|
|
|
85
85
|
isExiting = false,
|
|
86
86
|
onDismiss,
|
|
87
87
|
renderContent,
|
|
88
|
-
gestureDirection
|
|
88
|
+
gestureDirection,
|
|
89
|
+
timerKey,
|
|
90
|
+
isLiveRegion = true
|
|
89
91
|
}) {
|
|
90
92
|
const t = useComponentTranslator();
|
|
91
93
|
const timerRef = useRef(null);
|
|
@@ -117,10 +119,11 @@ export function ToastSurface({
|
|
|
117
119
|
onDismissRef.current('auto');
|
|
118
120
|
}, remainingRef.current);
|
|
119
121
|
}, [isAutoHide]);
|
|
122
|
+
|
|
123
|
+
// Pointer, focus and gesture holds are tracked whatever isAutoHide is: an
|
|
124
|
+
// overwrite can turn a toast that does not auto-hide into one that does
|
|
125
|
+
// while a hold is in place. The window hold leaves with its listeners.
|
|
120
126
|
const pauseTimer = useCallback(source => {
|
|
121
|
-
if (!isAutoHide) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
127
|
const sources = pauseSourcesRef.current;
|
|
125
128
|
const wasRunning = sources.size === 0;
|
|
126
129
|
sources.add(source);
|
|
@@ -135,11 +138,8 @@ export function ToastSurface({
|
|
|
135
138
|
const elapsed = Date.now() - startTimeRef.current;
|
|
136
139
|
remainingRef.current = Math.max(remainingRef.current - elapsed, 1000);
|
|
137
140
|
}
|
|
138
|
-
}, [
|
|
141
|
+
}, []);
|
|
139
142
|
const resumeTimer = useCallback(source => {
|
|
140
|
-
if (!isAutoHide) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
143
|
const sources = pauseSourcesRef.current;
|
|
144
144
|
if (!sources.delete(source)) {
|
|
145
145
|
return;
|
|
@@ -152,18 +152,25 @@ export function ToastSurface({
|
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
154
|
startTimer();
|
|
155
|
-
}, [
|
|
155
|
+
}, [startTimer]);
|
|
156
156
|
useEffect(() => {
|
|
157
157
|
remainingRef.current = autoHideDuration;
|
|
158
|
+
// An update in place can remove the focused control, which fires no blur:
|
|
159
|
+
// a focus hold whose focus has left the card is stale.
|
|
160
|
+
const root = cardRootRef.current?.current;
|
|
161
|
+
if (pauseSourcesRef.current.has('focus') && root != null && !root.contains(root.ownerDocument.activeElement)) {
|
|
162
|
+
pauseSourcesRef.current.delete('focus');
|
|
163
|
+
}
|
|
158
164
|
startTimer();
|
|
159
165
|
return () => {
|
|
160
166
|
if (timerRef.current) {
|
|
161
167
|
clearTimeout(timerRef.current);
|
|
162
168
|
}
|
|
163
169
|
};
|
|
164
|
-
// startTimer's identity is stable per isAutoHide, so this runs on mount
|
|
165
|
-
//
|
|
166
|
-
|
|
170
|
+
// startTimer's identity is stable per isAutoHide, so this runs on mount,
|
|
171
|
+
// on a genuine duration change and on an overwrite (timerKey), not on
|
|
172
|
+
// unrelated viewport renders.
|
|
173
|
+
}, [autoHideDuration, startTimer, timerKey]);
|
|
167
174
|
|
|
168
175
|
// Pause the auto-hide timer while the window is not focused, so a toast
|
|
169
176
|
// doesn't silently expire while the user is in another window or tab.
|
|
@@ -171,6 +178,7 @@ export function ToastSurface({
|
|
|
171
178
|
if (!isAutoHide) {
|
|
172
179
|
return;
|
|
173
180
|
}
|
|
181
|
+
const pauseSources = pauseSourcesRef.current;
|
|
174
182
|
const pauseForWindow = () => pauseTimer('window');
|
|
175
183
|
const resumeForWindow = () => resumeTimer('window');
|
|
176
184
|
window.addEventListener('blur', pauseForWindow);
|
|
@@ -183,6 +191,8 @@ export function ToastSurface({
|
|
|
183
191
|
return () => {
|
|
184
192
|
window.removeEventListener('blur', pauseForWindow);
|
|
185
193
|
window.removeEventListener('focus', resumeForWindow);
|
|
194
|
+
// With the listeners gone, no focus event would clear the window hold.
|
|
195
|
+
pauseSources.delete('window');
|
|
186
196
|
};
|
|
187
197
|
}, [isAutoHide, pauseTimer, resumeTimer]);
|
|
188
198
|
const isGesturePausing = useCallback(() => pauseSourcesRef.current.has('gesture'), []);
|
|
@@ -229,9 +239,9 @@ export function ToastSurface({
|
|
|
229
239
|
const fallbackMediaMode = isError || mode === 'light' ? 'dark' : 'light';
|
|
230
240
|
return /*#__PURE__*/_jsx("div", {
|
|
231
241
|
ref: rootRef,
|
|
232
|
-
role: isError ? 'alert' : 'status',
|
|
233
|
-
"aria-live": isError ? 'assertive' : 'polite',
|
|
234
|
-
"aria-atomic":
|
|
242
|
+
role: isLiveRegion ? isError ? 'alert' : 'status' : undefined,
|
|
243
|
+
"aria-live": isLiveRegion ? isError ? 'assertive' : 'polite' : undefined,
|
|
244
|
+
"aria-atomic": isLiveRegion ? 'true' : undefined,
|
|
235
245
|
onMouseEnter: pauseForPointer,
|
|
236
246
|
onMouseLeave: resumeForPointer,
|
|
237
247
|
onFocusCapture: pauseForFocus,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastViewport.d.ts","sourceRoot":"","sources":["../../src/Toast/ToastViewport.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToastViewport.d.ts","sourceRoot":"","sources":["../../src/Toast/ToastViewport.tsx"],"names":[],"mappings":"AAiDA,OAAO,KAAK,EAAa,aAAa,EAAqB,MAAM,SAAS,CAAC;AAE3E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAwItD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACtE;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAiHD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAsB,EACtB,UAAc,EACd,KAAK,EACL,UAAU,EACV,UAAiB,EACjB,QAAQ,GACT,EAAE,kBAAkB,+BA6lBpB;yBApmBe,aAAa"}
|
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
* SYNC: When placement, stacking, hosting, focus, announcement, or safe-area
|
|
14
14
|
* behavior changes, update ToastViewport.test.tsx, Toast.doc.mjs, and Toast.stories.tsx.
|
|
15
15
|
*/
|
|
16
|
-
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
|
|
17
17
|
import { createPortal } from 'react-dom';
|
|
18
18
|
import * as stylex from '@stylexjs/stylex';
|
|
19
19
|
import "../theme/tokens.stylex.js";
|
|
20
20
|
import { spacingVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
|
|
21
21
|
import { mergeProps } from "../utils/index.js";
|
|
22
22
|
import { getNodeText } from "../utils/getNodeText.js";
|
|
23
|
+
import { moveFocusLeftBehind, noteFocusWithin } from "../utils/focusReturn.js";
|
|
23
24
|
import { INTERACTIVE_SELECTORS } from "../hooks/useClickableContainer.js";
|
|
24
25
|
import { useAnnounce } from "../hooks/useAnnounce.js";
|
|
25
26
|
import { layerTextReset } from "../Layer/layerTextReset.stylex.js";
|
|
@@ -122,7 +123,8 @@ function ToastRow({
|
|
|
122
123
|
isExiting,
|
|
123
124
|
isReversed,
|
|
124
125
|
onExited,
|
|
125
|
-
onDismiss
|
|
126
|
+
onDismiss,
|
|
127
|
+
isLiveRegion
|
|
126
128
|
}) {
|
|
127
129
|
const o = entry.options;
|
|
128
130
|
const type = o.type ?? 'info';
|
|
@@ -194,12 +196,16 @@ function ToastRow({
|
|
|
194
196
|
isExiting: isExiting,
|
|
195
197
|
gestureDirection: isReversed ? -1 : 1,
|
|
196
198
|
onDismiss: reason => onDismiss(entry.id, reason),
|
|
197
|
-
renderContent: o.renderContent
|
|
199
|
+
renderContent: o.renderContent,
|
|
200
|
+
timerKey: entry.id,
|
|
201
|
+
isLiveRegion: isLiveRegion
|
|
198
202
|
})
|
|
199
203
|
})
|
|
200
204
|
});
|
|
201
205
|
}
|
|
202
206
|
ToastRow.displayName = 'ToastRow';
|
|
207
|
+
const hasActiveModalOutlet = () => getActiveModalOutlet() != null;
|
|
208
|
+
const hasNoModalOutlet = () => false;
|
|
203
209
|
|
|
204
210
|
/**
|
|
205
211
|
* Container that renders and manages toast notifications. Place at the root
|
|
@@ -260,6 +266,11 @@ export function ToastViewport({
|
|
|
260
266
|
// The next toast id that should receive focus once the dismissed toast has
|
|
261
267
|
// unmounted, or 'restore' to fall back to the previously-focused element.
|
|
262
268
|
const pendingFocusRef = useRef(null);
|
|
269
|
+
// The id of a toast whose overwrite updated a row that held focus. If the
|
|
270
|
+
// update removed the focused control, the commit hands focus off.
|
|
271
|
+
const overwriteFocusRef = useRef(null);
|
|
272
|
+
// Where focus was inside a toast whose dismissal hands focus off.
|
|
273
|
+
const dismissFocusNoteRef = useRef(null);
|
|
263
274
|
|
|
264
275
|
// Collect a focusable control within a toast node, if any.
|
|
265
276
|
// Reuses the canonical INTERACTIVE_SELECTORS list (native controls plus
|
|
@@ -280,13 +291,9 @@ export function ToastViewport({
|
|
|
280
291
|
return null;
|
|
281
292
|
}, []);
|
|
282
293
|
|
|
283
|
-
// Announce toasts through the persistent singleton live regions.
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
// screen readers do not announce (see useAnnounce.ts); the singleton regions
|
|
287
|
-
// are mounted empty and only mutated afterwards, so they are what actually
|
|
288
|
-
// guarantees the announcement (the per-toast markup is kept for browse-mode
|
|
289
|
-
// discoverability). The announcement happens in addToast — the imperative
|
|
294
|
+
// Announce toasts through the persistent singleton live regions. They are
|
|
295
|
+
// mounted empty and only mutated afterwards, which screen readers announce
|
|
296
|
+
// (see useAnnounce.ts). The announcement happens in addToast — the imperative
|
|
290
297
|
// dispatch path invoked once per useToast() call from an event handler,
|
|
291
298
|
// never from render — so each toast is announced exactly once by
|
|
292
299
|
// construction, independent of the React render lifecycle (StrictMode
|
|
@@ -294,6 +301,12 @@ export function ToastViewport({
|
|
|
294
301
|
// re-renders never re-announce). It is client-only (addToast never runs
|
|
295
302
|
// during SSR), so it is SSR-safe.
|
|
296
303
|
const announce = useAnnounce();
|
|
304
|
+
// An open native modal hides the body-level channel above from assistive
|
|
305
|
+
// technology, so while the viewport is hosted in one, each card announces
|
|
306
|
+
// itself through its own live region instead. Outside a modal the cards
|
|
307
|
+
// carry none, so a card updated in place is announced once.
|
|
308
|
+
const hasModalOutlet = useSyncExternalStore(subscribeModalOutlets, hasActiveModalOutlet, hasNoModalOutlet);
|
|
309
|
+
const isModalHosted = isTopLayer && hasModalOutlet;
|
|
297
310
|
const addToast = useCallback(entry => {
|
|
298
311
|
const {
|
|
299
312
|
uniqueID,
|
|
@@ -326,7 +339,26 @@ export function ToastViewport({
|
|
|
326
339
|
if (overwritten && renderedToastsRef.current.includes(overwritten)) {
|
|
327
340
|
replacedRef.current.set(overwritten.id, overwritten);
|
|
328
341
|
}
|
|
329
|
-
|
|
342
|
+
// An overwrite of a toast that is not leaving keeps its row, so the card
|
|
343
|
+
// updates in place and focus inside it stays. A leaving namesake
|
|
344
|
+
// is replaced by a new row, which enters again.
|
|
345
|
+
const keepsRow = overwritten != null && !exitingIdsRef.current.has(overwritten.id);
|
|
346
|
+
const placed = keepsRow ? {
|
|
347
|
+
...entry,
|
|
348
|
+
rowKey: overwritten.rowKey ?? overwritten.id
|
|
349
|
+
} : entry;
|
|
350
|
+
if (keepsRow) {
|
|
351
|
+
// If the update removes the focused control, the commit hands focus
|
|
352
|
+
// off as a dismissal does.
|
|
353
|
+
const note = noteFocusWithin(viewportRef.current?.querySelector(`[data-toast-id="${overwritten.id}"]`));
|
|
354
|
+
if (note != null) {
|
|
355
|
+
overwriteFocusRef.current = {
|
|
356
|
+
id: placed.id,
|
|
357
|
+
note
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const projected = overwritten ? committed.map(t => t === overwritten ? placed : t) : [...committed, placed];
|
|
330
362
|
// `maxVisible={0}` shows every toast (FR7): nothing leaves the window.
|
|
331
363
|
const firstVisible = maxVisible > 0 ? projected.length - maxVisible : 0;
|
|
332
364
|
const cutIds = new Set(projected.filter((t, i) => i < firstVisible && exitingIdsRef.current.has(t.id)).map(t => t.id));
|
|
@@ -349,7 +381,7 @@ export function ToastViewport({
|
|
|
349
381
|
}
|
|
350
382
|
}
|
|
351
383
|
}
|
|
352
|
-
pending.set(entry.id,
|
|
384
|
+
pending.set(entry.id, placed);
|
|
353
385
|
// An overwrite swaps a new entry, with a new id, into the replaced
|
|
354
386
|
// toast's place, so the old row leaves the DOM without ever being
|
|
355
387
|
// dismissed. Its settled id is dropped by the prune below, which covers
|
|
@@ -360,7 +392,7 @@ export function ToastViewport({
|
|
|
360
392
|
// replaced namesake as leaving since, which must not turn the
|
|
361
393
|
// overwrite into an append. An ignored collision already returned.
|
|
362
394
|
const kept = prev.filter(t => !cutIds.has(t.id));
|
|
363
|
-
return overwritten && kept.includes(overwritten) ? kept.map(t => t === overwritten ?
|
|
395
|
+
return overwritten && kept.includes(overwritten) ? kept.map(t => t === overwritten ? placed : t) : [...kept, placed];
|
|
364
396
|
});
|
|
365
397
|
}, [announce, maxVisible]);
|
|
366
398
|
const removeToast = useCallback((id, reason) => {
|
|
@@ -383,9 +415,15 @@ export function ToastViewport({
|
|
|
383
415
|
// focused before the user entered the viewport) rather than <body>.
|
|
384
416
|
const el = viewportRef.current;
|
|
385
417
|
const active = document.activeElement;
|
|
386
|
-
|
|
418
|
+
// A toast an overwrite replaced in place no longer owns its row: the
|
|
419
|
+
// replacement does, so dismissing the replaced toast leaves the row, and
|
|
420
|
+
// focus in it, to the replacement.
|
|
421
|
+
const rowKey = entry.rowKey ?? entry.id;
|
|
422
|
+
const isReplacedInPlace = !toastsRef.current.some(t => t.id === id) && toastsRef.current.some(t => t.rowKey === rowKey);
|
|
423
|
+
const dismissedNode = isReplacedInPlace ? null : el?.querySelector(`[data-toast-id="${id}"]`) ?? null;
|
|
387
424
|
if (dismissedNode && active instanceof Node && dismissedNode.contains(active)) {
|
|
388
425
|
focusHandoffIdRef.current = id;
|
|
426
|
+
dismissFocusNoteRef.current = noteFocusWithin(dismissedNode);
|
|
389
427
|
// Pick the toast to receive focus while the DOM is still intact: the
|
|
390
428
|
// nearest one after it, then before it, that shows once it is gone
|
|
391
429
|
// (FR10), else restore. The list may already run ahead of the render
|
|
@@ -441,6 +479,31 @@ export function ToastViewport({
|
|
|
441
479
|
setToasts(prev => prev.filter(t => t.id !== id));
|
|
442
480
|
}, []);
|
|
443
481
|
|
|
482
|
+
// Moves focus to a control in the target toast, else in another toast that
|
|
483
|
+
// shows (newest first), else back to the element focused before focus
|
|
484
|
+
// entered the viewport, so a handoff never drops focus to <body>.
|
|
485
|
+
const handOffFocus = useCallback((note, targetId) => {
|
|
486
|
+
const el = viewportRef.current;
|
|
487
|
+
const rowFor = id => el?.querySelector(`[data-toast-id="${id}"]`) ?? null;
|
|
488
|
+
const shownIds = toastsRef.current.slice(maxVisibleRef.current > 0 ? -maxVisibleRef.current : 0).map(t => t.id).reverse();
|
|
489
|
+
const candidates = targetId == null ? [] : [targetId, ...shownIds.filter(id => id !== targetId)];
|
|
490
|
+
let target = null;
|
|
491
|
+
for (const id of candidates) {
|
|
492
|
+
target = getFocusable(rowFor(id));
|
|
493
|
+
if (target != null) {
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const prev = prevFocusRef.current;
|
|
498
|
+
const isReturning = target == null && prev != null && prev.isConnected;
|
|
499
|
+
if (target == null) {
|
|
500
|
+
target = isReturning ? prev : el;
|
|
501
|
+
}
|
|
502
|
+
if (moveFocusLeftBehind(note, target) && isReturning) {
|
|
503
|
+
prevFocusRef.current = null;
|
|
504
|
+
}
|
|
505
|
+
}, [getFocusable]);
|
|
506
|
+
|
|
444
507
|
// After a dismissed toast unmounts, hand focus off so it never falls to
|
|
445
508
|
// <body>. Runs in a layout effect once the toast list no longer contains
|
|
446
509
|
// the dismissed toast.
|
|
@@ -456,25 +519,21 @@ export function ToastViewport({
|
|
|
456
519
|
}
|
|
457
520
|
focusHandoffIdRef.current = null;
|
|
458
521
|
pendingFocusRef.current = null;
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
const prev = prevFocusRef.current;
|
|
471
|
-
prevFocusRef.current = null;
|
|
472
|
-
if (prev && prev.isConnected) {
|
|
473
|
-
prev.focus();
|
|
474
|
-
} else if (el) {
|
|
475
|
-
el.focus();
|
|
522
|
+
const note = dismissFocusNoteRef.current;
|
|
523
|
+
dismissFocusNoteRef.current = null;
|
|
524
|
+
handOffFocus(note, target === 'restore' ? null : target);
|
|
525
|
+
}, [toasts, handOffFocus]);
|
|
526
|
+
|
|
527
|
+
// After an overwrite updated a row that held focus: focus stays on the same
|
|
528
|
+
// control, or, if the update removed it, moves as a dismissal hands it off.
|
|
529
|
+
useLayoutEffect(() => {
|
|
530
|
+
const overwrite = overwriteFocusRef.current;
|
|
531
|
+
if (overwrite == null) {
|
|
532
|
+
return;
|
|
476
533
|
}
|
|
477
|
-
|
|
534
|
+
overwriteFocusRef.current = null;
|
|
535
|
+
handOffFocus(overwrite.note, overwrite.id);
|
|
536
|
+
}, [toasts, handOffFocus]);
|
|
478
537
|
const findByUniqueID = useCallback(uid => {
|
|
479
538
|
return toastsRef.current.find(t => t.options.uniqueID === uid);
|
|
480
539
|
}, []);
|
|
@@ -663,8 +722,9 @@ export function ToastViewport({
|
|
|
663
722
|
isExiting: exitingIds.has(entry.id),
|
|
664
723
|
isReversed: isReversed,
|
|
665
724
|
onExited: handleExited,
|
|
666
|
-
onDismiss: removeToast
|
|
667
|
-
|
|
725
|
+
onDismiss: removeToast,
|
|
726
|
+
isLiveRegion: isModalHosted
|
|
727
|
+
}, entry.rowKey ?? entry.id))
|
|
668
728
|
})
|
|
669
729
|
});
|
|
670
730
|
return /*#__PURE__*/_jsxs(ToastContext, {
|
package/dist/Toast/types.d.ts
CHANGED
|
@@ -31,9 +31,10 @@ export interface ToastOptions {
|
|
|
31
31
|
/**
|
|
32
32
|
* Replaces the content of this toast's card with your own layout.
|
|
33
33
|
*
|
|
34
|
-
* Astryx keeps the card
|
|
35
|
-
* the
|
|
36
|
-
*
|
|
34
|
+
* Astryx keeps the card and its auto-hide behavior (inside a
|
|
35
|
+
* `ToastViewport` the viewport announces the toast, and while a modal hosts
|
|
36
|
+
* the viewport the card announces itself), then hands the
|
|
37
|
+
* renderer this toast's content, resolved settings and `dismiss` callback. The renderer owns every control inside its layout; call
|
|
37
38
|
* `dismiss` from the control that should close the toast. Astryx does not
|
|
38
39
|
* inject a fallback control into custom content.
|
|
39
40
|
*
|
|
@@ -85,5 +86,10 @@ export interface ToastEntry {
|
|
|
85
86
|
id: string;
|
|
86
87
|
options: ToastOptions;
|
|
87
88
|
createdAt: number;
|
|
89
|
+
/**
|
|
90
|
+
* The row's identity in the stack. A uniqueID overwrite keeps the replaced
|
|
91
|
+
* toast's, so the card updates in place and focus inside it stays.
|
|
92
|
+
*/
|
|
93
|
+
rowKey?: string;
|
|
88
94
|
}
|
|
89
95
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/Toast/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,gDAAgD;AAChD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzC,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAEhF,mEAAmE;AACnE,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5D,wCAAwC;AACxC,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/Toast/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,gDAAgD;AAChD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzC,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAEhF,mEAAmE;AACnE,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5D,wCAAwC;AACxC,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAErC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,gDAAgD;IAChD,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C;AAED,oDAAoD;AACpD,MAAM,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC;AAExC,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,IAAI,EAAE,SAAS,CAAC;IAChB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,uBAAuB,KAC3B,SAAS,CAAC;AAEf,oDAAoD;AACpD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,cAAc,CAAC;AAEpE,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file useTooltip.tsx
|
|
3
3
|
* @input Uses useLayer, usePressPin, React hooks
|
|
4
|
-
* @output Exports useTooltip hook with stable trigger refs for hover/focus/tap tooltips
|
|
4
|
+
* @output Exports useTooltip hook with stable trigger refs for hover/focus/tap tooltips
|
|
5
|
+
* and imperative show() and hide() for an app-built toggle trigger,
|
|
5
6
|
* and the module-only useTooltipWithTriggerBehavior that InfoTip's press-to-pin uses
|
|
6
7
|
* @position Layer hook; builds on useLayer for tooltip behavior
|
|
7
8
|
*
|
|
@@ -133,6 +134,23 @@ export interface TooltipReturn {
|
|
|
133
134
|
* silent no-op.
|
|
134
135
|
*/
|
|
135
136
|
renderTooltip: (children: ReactNode, props?: Omit<ContextRenderProps, 'positioning'>) => ReactNode;
|
|
137
|
+
/**
|
|
138
|
+
* Opens the tooltip now and keeps it open until `hide()`, Escape, a press
|
|
139
|
+
* outside, or focus leaving its trigger, as a pinned tooltip does. Its text
|
|
140
|
+
* is announced once. Reports through `onShow`. Under a controlled `isOpen`,
|
|
141
|
+
* it calls `onShow` and does not change `isOpen`. Does nothing while
|
|
142
|
+
* `isEnabled` is false.
|
|
143
|
+
*
|
|
144
|
+
* Use `show()` and `hide()` to build a toggle-style trigger: your own button
|
|
145
|
+
* calls them, sets `aria-describedby` and `aria-controls` to `describedBy`
|
|
146
|
+
* and `aria-expanded` (true while shown), and keeps its own accessible name.
|
|
147
|
+
*/
|
|
148
|
+
show: () => void;
|
|
149
|
+
/**
|
|
150
|
+
* Closes the tooltip now. Reports through `onHide`. Under a controlled
|
|
151
|
+
* `isOpen`, it calls `onHide` and does not change `isOpen`.
|
|
152
|
+
*/
|
|
153
|
+
hide: () => void;
|
|
136
154
|
}
|
|
137
155
|
/**
|
|
138
156
|
* Hook for tooltip behavior with hover/focus triggers.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../src/Tooltip/useTooltip.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../src/Tooltip/useTooltip.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAGf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAKhE,OAAO,EAAc,KAAK,oBAAoB,EAAC,MAAM,sBAAsB,CAAC;AA0C5E;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,aAAa,EAAE,CACb,QAAQ,EAAE,SAAS,EACnB,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,KAC5C,SAAS,CAAC;IAEf;;;;;;;;;;OAUG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB;;;OAGG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAOtE;AAED;;;GAGG;AACH,MAAM,WAAW,iCAAkC,SAAQ,cAAc;IACvE;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,iCAAsC,GAC9C,aAAa,CA2df"}
|