@seed-design/lynx-react 0.7.1 → 0.8.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/lib/components/Accordion/Accordion.jsx +2 -2
- package/lib/components/ActionButton/ActionButton.jsx +1 -1
- package/lib/components/AlertDialog/AlertDialog.d.ts +64 -0
- package/lib/components/AlertDialog/AlertDialog.d.ts.map +1 -0
- package/lib/components/AlertDialog/AlertDialog.jsx +138 -0
- package/lib/components/AlertDialog/AlertDialog.namespace.d.ts +2 -0
- package/lib/components/AlertDialog/AlertDialog.namespace.d.ts.map +1 -0
- package/lib/components/AlertDialog/AlertDialog.namespace.js +17 -0
- package/lib/components/AlertDialog/index.d.ts +3 -0
- package/lib/components/AlertDialog/index.d.ts.map +1 -0
- package/lib/components/AppBar/AppBar.d.ts +14 -1
- package/lib/components/AppBar/AppBar.d.ts.map +1 -1
- package/lib/components/AppBar/AppBar.jsx +39 -8
- package/lib/components/AppBar/AppBar.namespace.d.ts +1 -1
- package/lib/components/AppBar/AppBar.namespace.d.ts.map +1 -1
- package/lib/components/AppBar/index.d.ts +1 -1
- package/lib/components/AppBar/index.d.ts.map +1 -1
- package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts +182 -0
- package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts.map +1 -0
- package/lib/components/AttachmentDisplay/AttachmentDisplay.jsx +444 -0
- package/lib/components/AttachmentDisplay/index.d.ts +2 -0
- package/lib/components/AttachmentDisplay/index.d.ts.map +1 -0
- package/lib/components/AttachmentInput/AttachmentInput.d.ts +179 -0
- package/lib/components/AttachmentInput/AttachmentInput.d.ts.map +1 -0
- package/lib/components/AttachmentInput/AttachmentInput.jsx +520 -0
- package/lib/components/AttachmentInput/index.d.ts +2 -0
- package/lib/components/AttachmentInput/index.d.ts.map +1 -0
- package/lib/components/BottomSheet/BottomSheet.d.ts +1 -1
- package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/lib/components/BottomSheet/BottomSheet.jsx +1 -7
- package/lib/components/Callout/Callout.jsx +2 -2
- package/lib/components/Checkbox/Checkbox.jsx +2 -2
- package/lib/components/Chip/Chip.jsx +2 -2
- package/lib/components/ChipTabs/ChipTabs.d.ts +41 -0
- package/lib/components/ChipTabs/ChipTabs.d.ts.map +1 -0
- package/lib/components/ChipTabs/ChipTabs.jsx +39 -0
- package/lib/components/ChipTabs/ChipTabs.namespace.d.ts +2 -0
- package/lib/components/ChipTabs/ChipTabs.namespace.d.ts.map +1 -0
- package/lib/components/ChipTabs/ChipTabs.namespace.js +13 -0
- package/lib/components/ChipTabs/index.d.ts +3 -0
- package/lib/components/ChipTabs/index.d.ts.map +1 -0
- package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts +18 -0
- package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts.map +1 -0
- package/lib/components/ContextualFloatingButton/ContextualFloatingButton.jsx +113 -0
- package/lib/components/ContextualFloatingButton/index.d.ts +2 -0
- package/lib/components/ContextualFloatingButton/index.d.ts.map +1 -0
- package/lib/components/Dialog/Dialog.d.ts +87 -0
- package/lib/components/Dialog/Dialog.d.ts.map +1 -0
- package/lib/components/Dialog/Dialog.jsx +147 -0
- package/lib/components/Dialog/Dialog.namespace.d.ts +2 -0
- package/lib/components/Dialog/Dialog.namespace.d.ts.map +1 -0
- package/lib/components/Dialog/Dialog.namespace.js +18 -0
- package/lib/components/Dialog/index.d.ts +3 -0
- package/lib/components/Dialog/index.d.ts.map +1 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.d.ts +23 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.d.ts.map +1 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.jsx +76 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts +2 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts.map +1 -0
- package/lib/components/FloatingActionButton/FloatingActionButton.namespace.js +10 -0
- package/lib/components/FloatingActionButton/index.d.ts +3 -0
- package/lib/components/FloatingActionButton/index.d.ts.map +1 -0
- package/lib/components/HelpBubble/HelpBubble.d.ts +67 -0
- package/lib/components/HelpBubble/HelpBubble.d.ts.map +1 -0
- package/lib/components/HelpBubble/HelpBubble.jsx +600 -0
- package/lib/components/HelpBubble/HelpBubble.namespace.d.ts +2 -0
- package/lib/components/HelpBubble/HelpBubble.namespace.d.ts.map +1 -0
- package/lib/components/HelpBubble/HelpBubble.namespace.js +18 -0
- package/lib/components/HelpBubble/index.d.ts +3 -0
- package/lib/components/HelpBubble/index.d.ts.map +1 -0
- package/lib/components/Icon/Icon.d.ts +1 -0
- package/lib/components/Icon/Icon.d.ts.map +1 -1
- package/lib/components/Icon/Icon.jsx +2 -1
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts +28 -0
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts.map +1 -0
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.jsx +37 -0
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts +2 -0
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts.map +1 -0
- package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.js +9 -0
- package/lib/components/IdentityPlaceholder/identity-placeholder-business.js +4 -0
- package/lib/components/IdentityPlaceholder/identity-placeholder-person.js +4 -0
- package/lib/components/IdentityPlaceholder/index.d.ts +3 -0
- package/lib/components/IdentityPlaceholder/index.d.ts.map +1 -0
- package/lib/components/InputButton/InputButton.d.ts +2 -0
- package/lib/components/InputButton/InputButton.d.ts.map +1 -1
- package/lib/components/InputButton/InputButton.jsx +40 -8
- package/lib/components/List/List.d.ts +1 -1
- package/lib/components/List/List.d.ts.map +1 -1
- package/lib/components/List/List.jsx +26 -12
- package/lib/components/Menu/Menu.d.ts.map +1 -1
- package/lib/components/Menu/Menu.jsx +15 -5
- package/lib/components/PageBanner/PageBanner.d.ts +3 -0
- package/lib/components/PageBanner/PageBanner.d.ts.map +1 -1
- package/lib/components/PageBanner/PageBanner.jsx +49 -11
- package/lib/components/QuantityPicker/QuantityPicker.d.ts +53 -0
- package/lib/components/QuantityPicker/QuantityPicker.d.ts.map +1 -0
- package/lib/components/QuantityPicker/QuantityPicker.jsx +282 -0
- package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts +2 -0
- package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts.map +1 -0
- package/lib/components/QuantityPicker/QuantityPicker.namespace.js +11 -0
- package/lib/components/QuantityPicker/index.d.ts +3 -0
- package/lib/components/QuantityPicker/index.d.ts.map +1 -0
- package/lib/components/RadioGroup/RadioGroup.jsx +2 -2
- package/lib/components/ReactionButton/ReactionButton.d.ts +1 -1
- package/lib/components/ReactionButton/ReactionButton.d.ts.map +1 -1
- package/lib/components/ReactionButton/ReactionButton.jsx +22 -13
- package/lib/components/ScrollFog/ScrollFog.d.ts +41 -0
- package/lib/components/ScrollFog/ScrollFog.d.ts.map +1 -0
- package/lib/components/ScrollFog/ScrollFog.jsx +65 -0
- package/lib/components/ScrollFog/index.d.ts +2 -0
- package/lib/components/ScrollFog/index.d.ts.map +1 -0
- package/lib/components/SegmentedControl/SegmentedControl.jsx +2 -2
- package/lib/components/Select/Select.d.ts +112 -0
- package/lib/components/Select/Select.d.ts.map +1 -0
- package/lib/components/Select/Select.jsx +885 -0
- package/lib/components/Select/Select.namespace.d.ts +2 -0
- package/lib/components/Select/Select.namespace.d.ts.map +1 -0
- package/lib/components/Select/Select.namespace.js +23 -0
- package/lib/components/Select/index.d.ts +3 -0
- package/lib/components/Select/index.d.ts.map +1 -0
- package/lib/components/Skeleton/Skeleton.d.ts +15 -0
- package/lib/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/lib/components/Skeleton/Skeleton.jsx +18 -0
- package/lib/components/Skeleton/index.d.ts +2 -0
- package/lib/components/Skeleton/index.d.ts.map +1 -0
- package/lib/components/Slider/Slider.d.ts +101 -0
- package/lib/components/Slider/Slider.d.ts.map +1 -0
- package/lib/components/Slider/Slider.jsx +573 -0
- package/lib/components/Slider/Slider.namespace.d.ts +2 -0
- package/lib/components/Slider/Slider.namespace.d.ts.map +1 -0
- package/lib/components/Slider/Slider.namespace.js +19 -0
- package/lib/components/Slider/Slider.utils.d.ts +19 -0
- package/lib/components/Slider/Slider.utils.d.ts.map +1 -0
- package/lib/components/Slider/Slider.utils.js +106 -0
- package/lib/components/Slider/index.d.ts +3 -0
- package/lib/components/Slider/index.d.ts.map +1 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts.map +1 -1
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.jsx +22 -8
- package/lib/components/Switch/Switch.d.ts.map +1 -1
- package/lib/components/Switch/Switch.jsx +5 -3
- package/lib/components/Tabs/Tabs.d.ts +34 -2
- package/lib/components/Tabs/Tabs.d.ts.map +1 -1
- package/lib/components/Tabs/Tabs.jsx +186 -56
- package/lib/components/Tabs/Tabs.utils.d.ts +14 -1
- package/lib/components/Tabs/Tabs.utils.d.ts.map +1 -1
- package/lib/components/Tabs/Tabs.utils.js +24 -3
- package/lib/components/Tabs/index.d.ts +1 -1
- package/lib/components/Tabs/index.d.ts.map +1 -1
- package/lib/components/index.d.ts +14 -0
- package/lib/components/index.d.ts.map +1 -1
- package/lib/hooks/useControllableState.d.ts +1 -14
- package/lib/hooks/useControllableState.d.ts.map +1 -1
- package/lib/hooks/usePressTap.d.ts +1 -27
- package/lib/hooks/usePressTap.d.ts.map +1 -1
- package/lib/index.js +29 -6
- package/lib/{hooks/useControllableState.js → packages/lynx-react-headless/use-controllable-state/lib/index.js} +2 -3
- package/lib/{hooks/usePressTap.js → packages/lynx-react-headless/use-press-tap/lib/index.js} +13 -10
- package/lib/types.d.ts +1 -0
- package/lib/types.d.ts.map +1 -1
- package/package.json +9 -5
- package/src/components/AlertDialog/AlertDialog.namespace.ts +22 -0
- package/src/components/AlertDialog/AlertDialog.test.tsx +226 -0
- package/src/components/AlertDialog/AlertDialog.tsx +374 -0
- package/src/components/AlertDialog/index.ts +24 -0
- package/src/components/AppBar/AppBar.namespace.ts +1 -0
- package/src/components/AppBar/AppBar.test.tsx +231 -0
- package/src/components/AppBar/AppBar.tsx +105 -13
- package/src/components/AppBar/index.ts +1 -0
- package/src/components/AttachmentDisplay/AttachmentDisplay.tsx +886 -0
- package/src/components/AttachmentDisplay/index.ts +48 -0
- package/src/components/AttachmentInput/AttachmentInput.tsx +1001 -0
- package/src/components/AttachmentInput/index.ts +49 -0
- package/src/components/BottomSheet/BottomSheet.test.tsx +22 -7
- package/src/components/BottomSheet/BottomSheet.tsx +1 -19
- package/src/components/ChipTabs/ChipTabs.namespace.ts +14 -0
- package/src/components/ChipTabs/ChipTabs.tsx +119 -0
- package/src/components/ChipTabs/index.ts +16 -0
- package/src/components/ContextualFloatingButton/ContextualFloatingButton.test.tsx +63 -0
- package/src/components/ContextualFloatingButton/ContextualFloatingButton.tsx +232 -0
- package/src/components/ContextualFloatingButton/index.ts +4 -0
- package/src/components/Dialog/Dialog.namespace.ts +24 -0
- package/src/components/Dialog/Dialog.test.tsx +172 -0
- package/src/components/Dialog/Dialog.tsx +373 -0
- package/src/components/Dialog/index.ts +26 -0
- package/src/components/FloatingActionButton/FloatingActionButton.namespace.ts +8 -0
- package/src/components/FloatingActionButton/FloatingActionButton.test.tsx +59 -0
- package/src/components/FloatingActionButton/FloatingActionButton.tsx +207 -0
- package/src/components/FloatingActionButton/index.ts +10 -0
- package/src/components/HelpBubble/HelpBubble.namespace.ts +24 -0
- package/src/components/HelpBubble/HelpBubble.tsx +998 -0
- package/src/components/HelpBubble/index.ts +26 -0
- package/src/components/Icon/Icon.test.tsx +0 -3
- package/src/components/Icon/Icon.tsx +11 -1
- package/src/components/IdentityPlaceholder/IdentityPlaceholder.namespace.ts +6 -0
- package/src/components/IdentityPlaceholder/IdentityPlaceholder.tsx +103 -0
- package/src/components/IdentityPlaceholder/assets.d.ts +4 -0
- package/src/components/IdentityPlaceholder/identity-placeholder-business.webp +0 -0
- package/src/components/IdentityPlaceholder/identity-placeholder-person.webp +0 -0
- package/src/components/IdentityPlaceholder/index.ts +8 -0
- package/src/components/InputButton/InputButton.test.tsx +128 -1
- package/src/components/InputButton/InputButton.tsx +60 -9
- package/src/components/List/List.test.tsx +54 -2
- package/src/components/List/List.tsx +43 -10
- package/src/components/Menu/Menu.tsx +14 -4
- package/src/components/Menu/__tests__/Menu.test.tsx +34 -0
- package/src/components/PageBanner/PageBanner.test.tsx +110 -3
- package/src/components/PageBanner/PageBanner.tsx +83 -19
- package/src/components/QuantityPicker/QuantityPicker.namespace.ts +10 -0
- package/src/components/QuantityPicker/QuantityPicker.test.tsx +235 -0
- package/src/components/QuantityPicker/QuantityPicker.tsx +605 -0
- package/src/components/QuantityPicker/index.ts +14 -0
- package/src/components/ReactionButton/ReactionButton.feedback.test.tsx +50 -0
- package/src/components/ReactionButton/ReactionButton.test.tsx +5 -3
- package/src/components/ReactionButton/ReactionButton.tsx +20 -12
- package/src/components/ScrollFog/ScrollFog.test.tsx +222 -0
- package/src/components/ScrollFog/ScrollFog.tsx +172 -0
- package/src/components/ScrollFog/index.ts +1 -0
- package/src/components/Select/Select.namespace.ts +34 -0
- package/src/components/Select/Select.test.tsx +297 -0
- package/src/components/Select/Select.tsx +1483 -0
- package/src/components/Select/index.ts +39 -0
- package/src/components/Skeleton/Skeleton.test.tsx +64 -0
- package/src/components/Skeleton/Skeleton.tsx +45 -0
- package/src/components/Skeleton/index.ts +1 -0
- package/src/components/Slider/Slider.namespace.ts +26 -0
- package/src/components/Slider/Slider.test.tsx +260 -0
- package/src/components/Slider/Slider.tsx +897 -0
- package/src/components/Slider/Slider.utils.ts +167 -0
- package/src/components/Slider/index.ts +30 -0
- package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.test.tsx +21 -1
- package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.tsx +30 -7
- package/src/components/Switch/Switch.tsx +14 -13
- package/src/components/Tabs/Tabs.test.tsx +218 -1
- package/src/components/Tabs/Tabs.tsx +346 -75
- package/src/components/Tabs/Tabs.utils.ts +51 -1
- package/src/components/Tabs/index.ts +17 -1
- package/src/components/index.ts +14 -0
- package/src/hooks/useControllableState.ts +1 -43
- package/src/hooks/usePressTap.test.ts +23 -11
- package/src/hooks/usePressTap.ts +1 -60
- package/src/types.ts +1 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DialogBackdrop as DialogBackdropPrimitive,
|
|
3
|
+
DialogClose as DialogClosePrimitive,
|
|
4
|
+
DialogContent as DialogContentPrimitive,
|
|
5
|
+
DialogRoot as DialogRootPrimitive,
|
|
6
|
+
DialogTrigger as DialogTriggerPrimitive,
|
|
7
|
+
DialogView as DialogViewPrimitive,
|
|
8
|
+
type DialogBackdropProps as DialogPrimitiveBackdropProps,
|
|
9
|
+
type DialogCloseProps as DialogPrimitiveCloseProps,
|
|
10
|
+
type DialogContentProps as DialogPrimitiveContentProps,
|
|
11
|
+
type DialogRootProps as DialogPrimitiveRootProps,
|
|
12
|
+
type DialogTriggerProps as DialogPrimitiveTriggerProps,
|
|
13
|
+
type DialogViewProps as DialogPrimitiveViewProps,
|
|
14
|
+
} from "@lynx-js/lynx-ui-dialog";
|
|
15
|
+
import {
|
|
16
|
+
forwardRef,
|
|
17
|
+
type ForwardRefExoticComponent,
|
|
18
|
+
type PropsWithoutRef,
|
|
19
|
+
type ReactElement,
|
|
20
|
+
type RefAttributes,
|
|
21
|
+
} from "@lynx-js/react";
|
|
22
|
+
import {
|
|
23
|
+
alertDialog,
|
|
24
|
+
type AlertDialogVariantProps,
|
|
25
|
+
} from "@seed-design/lynx-css/recipes/alert-dialog";
|
|
26
|
+
import clsx from "clsx";
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
LynxAccessibilityProps,
|
|
30
|
+
LynxStyledElementProps,
|
|
31
|
+
LynxTextRef,
|
|
32
|
+
LynxViewRef,
|
|
33
|
+
} from "../../types";
|
|
34
|
+
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
|
|
35
|
+
import { useStyleProps, type StyleProps } from "../../utils/styled";
|
|
36
|
+
|
|
37
|
+
type AlertDialogComponent<Props> = ((props: Props) => ReactElement) & {
|
|
38
|
+
displayName?: string;
|
|
39
|
+
};
|
|
40
|
+
type LynxForwardRefComponent<T, Props> = ForwardRefExoticComponent<
|
|
41
|
+
PropsWithoutRef<Props> & RefAttributes<T>
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
type NativeLifecycleHandlers = {
|
|
45
|
+
bindanimationstart?: unknown;
|
|
46
|
+
bindanimationend?: unknown;
|
|
47
|
+
bindanimationcancel?: unknown;
|
|
48
|
+
bindtransitionstart?: unknown;
|
|
49
|
+
bindtransitionend?: unknown;
|
|
50
|
+
bindtap?: unknown;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const { ClassNamesProvider, PropsProvider, useClassNames, useProps } =
|
|
54
|
+
createSlotRecipeContext(alertDialog);
|
|
55
|
+
|
|
56
|
+
function omitHeadlessLifecycleHandlers<Props extends object>(
|
|
57
|
+
props: Props | undefined,
|
|
58
|
+
): Props | undefined {
|
|
59
|
+
if (!props) return props;
|
|
60
|
+
|
|
61
|
+
const {
|
|
62
|
+
bindanimationstart: _bindanimationstart,
|
|
63
|
+
bindanimationend: _bindanimationend,
|
|
64
|
+
bindanimationcancel: _bindanimationcancel,
|
|
65
|
+
bindtransitionstart: _bindtransitionstart,
|
|
66
|
+
bindtransitionend: _bindtransitionend,
|
|
67
|
+
bindtap: _bindtap,
|
|
68
|
+
...nativeProps
|
|
69
|
+
} = props as Props & NativeLifecycleHandlers;
|
|
70
|
+
|
|
71
|
+
return nativeProps as Props;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function useAlertDialogTransition(transition: boolean | undefined) {
|
|
75
|
+
const skipAnimation = useProps()?.skipAnimation === true;
|
|
76
|
+
|
|
77
|
+
return skipAnimation ? false : (transition ?? true);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
81
|
+
// Root
|
|
82
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
83
|
+
|
|
84
|
+
export interface AlertDialogRootProps
|
|
85
|
+
extends AlertDialogVariantProps,
|
|
86
|
+
Omit<DialogPrimitiveRootProps, "show" | "defaultShow" | "onShowChange"> {
|
|
87
|
+
/** Whether the alert dialog is open (controlled mode). */
|
|
88
|
+
open?: boolean;
|
|
89
|
+
/** Whether the alert dialog is open by default (uncontrolled mode). */
|
|
90
|
+
defaultOpen?: boolean;
|
|
91
|
+
/** Called when the alert dialog's open state changes. */
|
|
92
|
+
onOpenChange?: (open: boolean) => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @platform Lynx — wraps `@lynx-js/lynx-ui-dialog` as an alert dialog.
|
|
97
|
+
* Refs, `asChild`, focus management, Escape-key dismissal, and close reasons are
|
|
98
|
+
* not supported by the Lynx primitive.
|
|
99
|
+
*/
|
|
100
|
+
export const AlertDialogRoot = forwardRef<never, AlertDialogRootProps>((props, _ref) => {
|
|
101
|
+
const [variantProps, restProps] = alertDialog.splitVariantProps(props);
|
|
102
|
+
const { children, open, defaultOpen, onOpenChange, ...nativeProps } = restProps;
|
|
103
|
+
const classNames = alertDialog(variantProps);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<ClassNamesProvider value={classNames}>
|
|
107
|
+
<PropsProvider value={variantProps}>
|
|
108
|
+
<DialogRootPrimitive
|
|
109
|
+
{...nativeProps}
|
|
110
|
+
show={open}
|
|
111
|
+
defaultShow={defaultOpen}
|
|
112
|
+
onShowChange={onOpenChange}
|
|
113
|
+
>
|
|
114
|
+
{children}
|
|
115
|
+
</DialogRootPrimitive>
|
|
116
|
+
</PropsProvider>
|
|
117
|
+
</ClassNamesProvider>
|
|
118
|
+
);
|
|
119
|
+
}) as AlertDialogComponent<AlertDialogRootProps>;
|
|
120
|
+
AlertDialogRoot.displayName = "AlertDialogRoot";
|
|
121
|
+
|
|
122
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
123
|
+
// Trigger
|
|
124
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
125
|
+
|
|
126
|
+
export interface AlertDialogTriggerProps extends DialogPrimitiveTriggerProps {}
|
|
127
|
+
|
|
128
|
+
/** @platform Lynx — `asChild` and refs are unsupported. */
|
|
129
|
+
export const AlertDialogTrigger = forwardRef<never, AlertDialogTriggerProps>((props, _ref) => {
|
|
130
|
+
const { children, transition, ...nativeProps } = props;
|
|
131
|
+
const resolvedTransition = useAlertDialogTransition(transition);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<DialogTriggerPrimitive {...nativeProps} transition={resolvedTransition}>
|
|
135
|
+
{children}
|
|
136
|
+
</DialogTriggerPrimitive>
|
|
137
|
+
);
|
|
138
|
+
}) as AlertDialogComponent<AlertDialogTriggerProps>;
|
|
139
|
+
AlertDialogTrigger.displayName = "AlertDialogTrigger";
|
|
140
|
+
|
|
141
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
142
|
+
// Positioner
|
|
143
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
144
|
+
|
|
145
|
+
export interface AlertDialogPositionerProps extends DialogPrimitiveViewProps {}
|
|
146
|
+
|
|
147
|
+
/** @platform Lynx — maps to `DialogView`; refs are unsupported. */
|
|
148
|
+
export const AlertDialogPositioner = forwardRef<never, AlertDialogPositionerProps>(
|
|
149
|
+
(props, _ref) => {
|
|
150
|
+
const { children, className, container, style, transition, ...nativeProps } = props;
|
|
151
|
+
const classNames = useClassNames();
|
|
152
|
+
const resolvedTransition = useAlertDialogTransition(transition);
|
|
153
|
+
const positionerStyle = container ? { width: "100%", height: "100%", ...style } : style;
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<DialogViewPrimitive
|
|
157
|
+
{...nativeProps}
|
|
158
|
+
container={container}
|
|
159
|
+
className={clsx(classNames.positioner, className)}
|
|
160
|
+
style={positionerStyle}
|
|
161
|
+
transition={resolvedTransition}
|
|
162
|
+
>
|
|
163
|
+
{children}
|
|
164
|
+
</DialogViewPrimitive>
|
|
165
|
+
);
|
|
166
|
+
},
|
|
167
|
+
) as AlertDialogComponent<AlertDialogPositionerProps>;
|
|
168
|
+
AlertDialogPositioner.displayName = "AlertDialogPositioner";
|
|
169
|
+
|
|
170
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
171
|
+
// Backdrop
|
|
172
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
173
|
+
|
|
174
|
+
export interface AlertDialogBackdropProps extends DialogPrimitiveBackdropProps {}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @platform Lynx — refs are unsupported. Native lifecycle handlers in
|
|
178
|
+
* `dialogBackdropProps` are reserved by the headless primitive and are omitted.
|
|
179
|
+
* Alert dialogs do not dismiss when the backdrop is tapped by default.
|
|
180
|
+
*/
|
|
181
|
+
export const AlertDialogBackdrop = forwardRef<never, AlertDialogBackdropProps>((props, _ref) => {
|
|
182
|
+
const {
|
|
183
|
+
children,
|
|
184
|
+
className,
|
|
185
|
+
transition,
|
|
186
|
+
clickToClose = false,
|
|
187
|
+
dialogBackdropProps,
|
|
188
|
+
...nativeProps
|
|
189
|
+
} = props;
|
|
190
|
+
const classNames = useClassNames();
|
|
191
|
+
const resolvedTransition = useAlertDialogTransition(transition);
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<DialogBackdropPrimitive
|
|
195
|
+
{...nativeProps}
|
|
196
|
+
className={clsx(classNames.backdrop, className)}
|
|
197
|
+
transition={resolvedTransition}
|
|
198
|
+
clickToClose={clickToClose}
|
|
199
|
+
dialogBackdropProps={omitHeadlessLifecycleHandlers(dialogBackdropProps)}
|
|
200
|
+
>
|
|
201
|
+
{children}
|
|
202
|
+
</DialogBackdropPrimitive>
|
|
203
|
+
);
|
|
204
|
+
}) as AlertDialogComponent<AlertDialogBackdropProps>;
|
|
205
|
+
AlertDialogBackdrop.displayName = "AlertDialogBackdrop";
|
|
206
|
+
|
|
207
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
208
|
+
// Content
|
|
209
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
210
|
+
|
|
211
|
+
export interface AlertDialogContentProps
|
|
212
|
+
extends DialogPrimitiveContentProps,
|
|
213
|
+
LynxAccessibilityProps {}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @platform Lynx — refs are unsupported. Native lifecycle handlers in
|
|
217
|
+
* `dialogContentProps` are reserved by the headless primitive and are omitted.
|
|
218
|
+
*/
|
|
219
|
+
export const AlertDialogContent = forwardRef<never, AlertDialogContentProps>((props, _ref) => {
|
|
220
|
+
const {
|
|
221
|
+
children,
|
|
222
|
+
className,
|
|
223
|
+
transition,
|
|
224
|
+
dialogContentProps,
|
|
225
|
+
"accessibility-element": accessibilityElement = true,
|
|
226
|
+
"accessibility-role-description": accessibilityRoleDescription = "alertdialog",
|
|
227
|
+
...nativeProps
|
|
228
|
+
} = props;
|
|
229
|
+
const classNames = useClassNames();
|
|
230
|
+
const resolvedTransition = useAlertDialogTransition(transition);
|
|
231
|
+
const resolvedDialogContentProps = {
|
|
232
|
+
"accessibility-element": accessibilityElement,
|
|
233
|
+
"accessibility-role-description": accessibilityRoleDescription,
|
|
234
|
+
...omitHeadlessLifecycleHandlers(dialogContentProps),
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<DialogContentPrimitive
|
|
239
|
+
{...nativeProps}
|
|
240
|
+
className={clsx(classNames.content, className)}
|
|
241
|
+
transition={resolvedTransition}
|
|
242
|
+
dialogContentProps={resolvedDialogContentProps}
|
|
243
|
+
>
|
|
244
|
+
{children}
|
|
245
|
+
</DialogContentPrimitive>
|
|
246
|
+
);
|
|
247
|
+
}) as AlertDialogComponent<AlertDialogContentProps>;
|
|
248
|
+
AlertDialogContent.displayName = "AlertDialogContent";
|
|
249
|
+
|
|
250
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
251
|
+
// Local slots
|
|
252
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
253
|
+
|
|
254
|
+
export interface AlertDialogHeaderProps extends StyleProps, LynxStyledElementProps {}
|
|
255
|
+
|
|
256
|
+
export const AlertDialogHeader: LynxForwardRefComponent<unknown, AlertDialogHeaderProps> =
|
|
257
|
+
forwardRef<unknown, AlertDialogHeaderProps>((props, ref) => {
|
|
258
|
+
const { style, restProps } = useStyleProps(props);
|
|
259
|
+
const { children, className, ...nativeProps } = restProps;
|
|
260
|
+
const classNames = useClassNames();
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<view
|
|
264
|
+
{...(ref ? ({ ref: ref as LynxViewRef } as Record<string, unknown>) : {})}
|
|
265
|
+
{...nativeProps}
|
|
266
|
+
className={clsx(classNames.header, className)}
|
|
267
|
+
style={style as never}
|
|
268
|
+
>
|
|
269
|
+
{children}
|
|
270
|
+
</view>
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
AlertDialogHeader.displayName = "AlertDialogHeader";
|
|
274
|
+
|
|
275
|
+
export interface AlertDialogTitleProps
|
|
276
|
+
extends StyleProps,
|
|
277
|
+
LynxStyledElementProps,
|
|
278
|
+
LynxAccessibilityProps {}
|
|
279
|
+
|
|
280
|
+
export const AlertDialogTitle: LynxForwardRefComponent<unknown, AlertDialogTitleProps> = forwardRef<
|
|
281
|
+
unknown,
|
|
282
|
+
AlertDialogTitleProps
|
|
283
|
+
>((props, ref) => {
|
|
284
|
+
const { style, restProps } = useStyleProps(props);
|
|
285
|
+
const {
|
|
286
|
+
children,
|
|
287
|
+
className,
|
|
288
|
+
"accessibility-heading": accessibilityHeading = true,
|
|
289
|
+
...nativeProps
|
|
290
|
+
} = restProps;
|
|
291
|
+
const classNames = useClassNames();
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<text
|
|
295
|
+
{...(ref ? ({ ref: ref as LynxTextRef } as Record<string, unknown>) : {})}
|
|
296
|
+
{...nativeProps}
|
|
297
|
+
className={clsx(classNames.title, className)}
|
|
298
|
+
style={style as never}
|
|
299
|
+
accessibility-heading={accessibilityHeading}
|
|
300
|
+
>
|
|
301
|
+
{children}
|
|
302
|
+
</text>
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
AlertDialogTitle.displayName = "AlertDialogTitle";
|
|
306
|
+
|
|
307
|
+
export interface AlertDialogDescriptionProps
|
|
308
|
+
extends StyleProps,
|
|
309
|
+
LynxStyledElementProps,
|
|
310
|
+
LynxAccessibilityProps {}
|
|
311
|
+
|
|
312
|
+
export const AlertDialogDescription: LynxForwardRefComponent<unknown, AlertDialogDescriptionProps> =
|
|
313
|
+
forwardRef<unknown, AlertDialogDescriptionProps>((props, ref) => {
|
|
314
|
+
const { style, restProps } = useStyleProps(props);
|
|
315
|
+
const { children, className, ...nativeProps } = restProps;
|
|
316
|
+
const classNames = useClassNames();
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
<text
|
|
320
|
+
{...(ref ? ({ ref: ref as LynxTextRef } as Record<string, unknown>) : {})}
|
|
321
|
+
{...nativeProps}
|
|
322
|
+
className={clsx(classNames.description, className)}
|
|
323
|
+
style={style as never}
|
|
324
|
+
>
|
|
325
|
+
{children}
|
|
326
|
+
</text>
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
AlertDialogDescription.displayName = "AlertDialogDescription";
|
|
330
|
+
|
|
331
|
+
export interface AlertDialogFooterProps extends StyleProps, LynxStyledElementProps {}
|
|
332
|
+
|
|
333
|
+
export const AlertDialogFooter: LynxForwardRefComponent<unknown, AlertDialogFooterProps> =
|
|
334
|
+
forwardRef<unknown, AlertDialogFooterProps>((props, ref) => {
|
|
335
|
+
const { style, restProps } = useStyleProps(props);
|
|
336
|
+
const { children, className, ...nativeProps } = restProps;
|
|
337
|
+
const classNames = useClassNames();
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<view
|
|
341
|
+
{...(ref ? ({ ref: ref as LynxViewRef } as Record<string, unknown>) : {})}
|
|
342
|
+
{...nativeProps}
|
|
343
|
+
className={clsx(classNames.footer, className)}
|
|
344
|
+
style={style as never}
|
|
345
|
+
>
|
|
346
|
+
{children}
|
|
347
|
+
</view>
|
|
348
|
+
);
|
|
349
|
+
});
|
|
350
|
+
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
351
|
+
|
|
352
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
353
|
+
// Action
|
|
354
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
355
|
+
|
|
356
|
+
export interface AlertDialogActionProps extends DialogPrimitiveCloseProps {}
|
|
357
|
+
|
|
358
|
+
/** @platform Lynx — maps to `DialogClose`; `asChild` and refs are unsupported. */
|
|
359
|
+
export const AlertDialogAction = forwardRef<never, AlertDialogActionProps>((props, _ref) => {
|
|
360
|
+
const { children, className, transition, ...nativeProps } = props;
|
|
361
|
+
const classNames = useClassNames();
|
|
362
|
+
const resolvedTransition = useAlertDialogTransition(transition);
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<DialogClosePrimitive
|
|
366
|
+
{...nativeProps}
|
|
367
|
+
className={clsx(classNames.action, className)}
|
|
368
|
+
transition={resolvedTransition}
|
|
369
|
+
>
|
|
370
|
+
{children}
|
|
371
|
+
</DialogClosePrimitive>
|
|
372
|
+
);
|
|
373
|
+
}) as AlertDialogComponent<AlertDialogActionProps>;
|
|
374
|
+
AlertDialogAction.displayName = "AlertDialogAction";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AlertDialogAction,
|
|
3
|
+
type AlertDialogActionProps,
|
|
4
|
+
AlertDialogBackdrop,
|
|
5
|
+
type AlertDialogBackdropProps,
|
|
6
|
+
AlertDialogContent,
|
|
7
|
+
type AlertDialogContentProps,
|
|
8
|
+
AlertDialogDescription,
|
|
9
|
+
type AlertDialogDescriptionProps,
|
|
10
|
+
AlertDialogFooter,
|
|
11
|
+
type AlertDialogFooterProps,
|
|
12
|
+
AlertDialogHeader,
|
|
13
|
+
type AlertDialogHeaderProps,
|
|
14
|
+
AlertDialogPositioner,
|
|
15
|
+
type AlertDialogPositionerProps,
|
|
16
|
+
AlertDialogRoot,
|
|
17
|
+
type AlertDialogRootProps,
|
|
18
|
+
AlertDialogTitle,
|
|
19
|
+
type AlertDialogTitleProps,
|
|
20
|
+
AlertDialogTrigger,
|
|
21
|
+
type AlertDialogTriggerProps,
|
|
22
|
+
} from "./AlertDialog";
|
|
23
|
+
|
|
24
|
+
export * as AlertDialog from "./AlertDialog.namespace";
|
|
@@ -2,6 +2,7 @@ import "@testing-library/jest-dom";
|
|
|
2
2
|
import * as React from "@lynx-js/react";
|
|
3
3
|
import type { MainThread } from "@lynx-js/types";
|
|
4
4
|
import type { LynxIconElementProps } from "../../types";
|
|
5
|
+
import { Fragment, useEffect } from "@lynx-js/react";
|
|
5
6
|
import {
|
|
6
7
|
act,
|
|
7
8
|
fireEvent,
|
|
@@ -271,6 +272,236 @@ describe("AppBar", () => {
|
|
|
271
272
|
expect(main).toHaveStyle({ paddingLeft: "72px", paddingRight: "72px" });
|
|
272
273
|
});
|
|
273
274
|
});
|
|
275
|
+
|
|
276
|
+
it.each([
|
|
277
|
+
"left",
|
|
278
|
+
"right",
|
|
279
|
+
] as const)("bleeds both sides of a single button in the %s slot", (side) => {
|
|
280
|
+
const Slot = side === "left" ? AppBar.Left : AppBar.Right;
|
|
281
|
+
render(
|
|
282
|
+
<AppBar.Root>
|
|
283
|
+
<Slot>
|
|
284
|
+
<AppBar.IconButton accessibility-label="Back" />
|
|
285
|
+
</Slot>
|
|
286
|
+
</AppBar.Root>,
|
|
287
|
+
);
|
|
288
|
+
const button = getAppBarRoot().querySelector(".seed-app-bar__iconButton");
|
|
289
|
+
expect(button).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
290
|
+
expect(button).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it.each([
|
|
294
|
+
"left",
|
|
295
|
+
"right",
|
|
296
|
+
] as const)("bleeds only the outer sides of buttons in the %s slot", (side) => {
|
|
297
|
+
const Slot = side === "left" ? AppBar.Left : AppBar.Right;
|
|
298
|
+
render(
|
|
299
|
+
<AppBar.Root>
|
|
300
|
+
<Slot>
|
|
301
|
+
<AppBar.IconButton accessibility-label="Search" />
|
|
302
|
+
<AppBar.IconButton accessibility-label="Share" />
|
|
303
|
+
<AppBar.IconButton accessibility-label="Close" />
|
|
304
|
+
</Slot>
|
|
305
|
+
</AppBar.Root>,
|
|
306
|
+
);
|
|
307
|
+
const buttons = getAppBarRoot().querySelectorAll(".seed-app-bar__iconButton");
|
|
308
|
+
expect(buttons).toHaveLength(3);
|
|
309
|
+
expect(buttons[0]).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
310
|
+
expect(buttons[0]).not.toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
311
|
+
expect(buttons[1]).not.toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
312
|
+
expect(buttons[1]).not.toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
313
|
+
expect(buttons[2]).not.toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
314
|
+
expect(buttons[2]).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("updates both edges when a conditional sibling changes without remounting the button", () => {
|
|
318
|
+
const mount = vi.fn();
|
|
319
|
+
function WrappedButton() {
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
mount();
|
|
322
|
+
}, []);
|
|
323
|
+
return <AppBar.IconButton accessibility-label="Back" />;
|
|
324
|
+
}
|
|
325
|
+
function Example({ showCustom }: { showCustom: boolean }) {
|
|
326
|
+
return (
|
|
327
|
+
<AppBar.Root>
|
|
328
|
+
<AppBar.Left>
|
|
329
|
+
<WrappedButton />
|
|
330
|
+
{showCustom && (
|
|
331
|
+
<AppBar.Slot>
|
|
332
|
+
<text>Done</text>
|
|
333
|
+
</AppBar.Slot>
|
|
334
|
+
)}
|
|
335
|
+
</AppBar.Left>
|
|
336
|
+
</AppBar.Root>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
const { rerender } = render(<Example showCustom={false} />);
|
|
340
|
+
const button = () => getAppBarRoot().querySelector(".seed-app-bar__iconButton");
|
|
341
|
+
expect(button()).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
342
|
+
expect(button()).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
343
|
+
rerender(<Example showCustom />);
|
|
344
|
+
expect(button()).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
345
|
+
expect(button()).not.toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
346
|
+
rerender(<Example showCustom={false} />);
|
|
347
|
+
expect(button()).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
348
|
+
expect(mount).toHaveBeenCalledTimes(1);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("does not bleed a custom slot sitting at the slot edge", () => {
|
|
352
|
+
render(
|
|
353
|
+
<AppBar.Root>
|
|
354
|
+
<AppBar.Right>
|
|
355
|
+
<AppBar.Slot>
|
|
356
|
+
<text>Done</text>
|
|
357
|
+
</AppBar.Slot>
|
|
358
|
+
</AppBar.Right>
|
|
359
|
+
</AppBar.Root>,
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const custom = getAppBarRoot().querySelector<HTMLElement>(".seed-app-bar__custom");
|
|
363
|
+
expect(custom).toBeInTheDocument();
|
|
364
|
+
expect(custom!.style.getPropertyValue("margin-left")).toBe("");
|
|
365
|
+
expect(custom!.style.getPropertyValue("margin-right")).toBe("");
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("bleeds the trailing icon button but not a preceding custom slot", () => {
|
|
369
|
+
render(
|
|
370
|
+
<AppBar.Root>
|
|
371
|
+
<AppBar.Right>
|
|
372
|
+
<AppBar.Slot>
|
|
373
|
+
<text>Done</text>
|
|
374
|
+
</AppBar.Slot>
|
|
375
|
+
<AppBar.IconButton accessibility-label="Close" />
|
|
376
|
+
</AppBar.Right>
|
|
377
|
+
</AppBar.Root>,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const root = getAppBarRoot();
|
|
381
|
+
const custom = root.querySelector<HTMLElement>(".seed-app-bar__custom");
|
|
382
|
+
const iconButton = root.querySelector<HTMLElement>(".seed-app-bar__iconButton");
|
|
383
|
+
expect(custom!.style.getPropertyValue("margin-right")).toBe("");
|
|
384
|
+
expect(iconButton).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it.each([
|
|
388
|
+
"leading",
|
|
389
|
+
"trailing",
|
|
390
|
+
"both",
|
|
391
|
+
] as const)("respects explicit edge=%s over automatic edges", (edge) => {
|
|
392
|
+
render(
|
|
393
|
+
<AppBar.Root>
|
|
394
|
+
<AppBar.Left>
|
|
395
|
+
<AppBar.IconButton accessibility-label="Back" edge={edge} />
|
|
396
|
+
</AppBar.Left>
|
|
397
|
+
</AppBar.Root>,
|
|
398
|
+
);
|
|
399
|
+
const button = getAppBarRoot().querySelector(".seed-app-bar__iconButton");
|
|
400
|
+
expect(button?.classList.contains("seed-app-bar__icon-button-edge-leading")).toBe(
|
|
401
|
+
edge !== "trailing",
|
|
402
|
+
);
|
|
403
|
+
expect(button?.classList.contains("seed-app-bar__icon-button-edge-trailing")).toBe(
|
|
404
|
+
edge !== "leading",
|
|
405
|
+
);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("preserves caller styles when automatic edge compensation applies", () => {
|
|
409
|
+
render(
|
|
410
|
+
<AppBar.Root>
|
|
411
|
+
<AppBar.Left>
|
|
412
|
+
<AppBar.IconButton
|
|
413
|
+
accessibility-label="Back"
|
|
414
|
+
{...{ style: { width: "60px", opacity: 0.5 } }}
|
|
415
|
+
/>
|
|
416
|
+
</AppBar.Left>
|
|
417
|
+
</AppBar.Root>,
|
|
418
|
+
);
|
|
419
|
+
const button = getAppBarRoot().querySelector<HTMLElement>(".seed-app-bar__iconButton");
|
|
420
|
+
expect(button).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
421
|
+
expectStyle(button!.style, { width: "60px", opacity: "0.5" });
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("finds the physical edge through nested fragments and conditional children", () => {
|
|
425
|
+
render(
|
|
426
|
+
<AppBar.Root>
|
|
427
|
+
<AppBar.Right>
|
|
428
|
+
<Fragment>
|
|
429
|
+
{false && <AppBar.IconButton accessibility-label="Hidden" />}
|
|
430
|
+
<AppBar.IconButton accessibility-label="Search" />
|
|
431
|
+
<Fragment key="actions">
|
|
432
|
+
<AppBar.IconButton accessibility-label="Close" />
|
|
433
|
+
{null}
|
|
434
|
+
<Fragment />
|
|
435
|
+
</Fragment>
|
|
436
|
+
</Fragment>
|
|
437
|
+
</AppBar.Right>
|
|
438
|
+
</AppBar.Root>,
|
|
439
|
+
);
|
|
440
|
+
const buttons = getAppBarRoot().querySelectorAll<HTMLElement>(".seed-app-bar__iconButton");
|
|
441
|
+
expect(buttons).toHaveLength(2);
|
|
442
|
+
expect(buttons[0]).toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
443
|
+
expect(buttons[0]).not.toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
444
|
+
expect(buttons[1]).not.toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
445
|
+
expect(buttons[1]).toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it("does not leak edge to native children or bleed buttons inside custom layout boxes", () => {
|
|
449
|
+
render(
|
|
450
|
+
<AppBar.Root>
|
|
451
|
+
<AppBar.Left>
|
|
452
|
+
<view id="native-edge">
|
|
453
|
+
<AppBar.IconButton accessibility-label="Nested" />
|
|
454
|
+
</view>
|
|
455
|
+
</AppBar.Left>
|
|
456
|
+
<AppBar.Right>
|
|
457
|
+
<AppBar.Slot>
|
|
458
|
+
<AppBar.IconButton accessibility-label="Custom" />
|
|
459
|
+
</AppBar.Slot>
|
|
460
|
+
</AppBar.Right>
|
|
461
|
+
</AppBar.Root>,
|
|
462
|
+
);
|
|
463
|
+
const root = getAppBarRoot();
|
|
464
|
+
expect(root.querySelector("#native-edge")).not.toHaveAttribute("edge");
|
|
465
|
+
expect(root.querySelector("[edge]")).toBeNull();
|
|
466
|
+
for (const button of root.querySelectorAll(".seed-app-bar__iconButton")) {
|
|
467
|
+
expect(button).not.toHaveClass("seed-app-bar__icon-button-edge-leading");
|
|
468
|
+
expect(button).not.toHaveClass("seed-app-bar__icon-button-edge-trailing");
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it("passes edge through wrapper components without changing their props or remounting", () => {
|
|
473
|
+
const mount = vi.fn();
|
|
474
|
+
const received = vi.fn();
|
|
475
|
+
function WrappedButton(props: { edge?: "leading" | "trailing" }) {
|
|
476
|
+
received(props);
|
|
477
|
+
useEffect(() => {
|
|
478
|
+
mount();
|
|
479
|
+
}, []);
|
|
480
|
+
return <AppBar.IconButton accessibility-label="Wrapped" {...props} />;
|
|
481
|
+
}
|
|
482
|
+
const { rerender } = render(
|
|
483
|
+
<AppBar.Root>
|
|
484
|
+
<AppBar.Left>
|
|
485
|
+
<WrappedButton />
|
|
486
|
+
</AppBar.Left>
|
|
487
|
+
</AppBar.Root>,
|
|
488
|
+
);
|
|
489
|
+
expect(getAppBarRoot().querySelector(".seed-app-bar__iconButton")).toHaveClass(
|
|
490
|
+
"seed-app-bar__icon-button-edge-leading",
|
|
491
|
+
);
|
|
492
|
+
expect(received.mock.lastCall?.[0]).not.toHaveProperty("edge");
|
|
493
|
+
rerender(
|
|
494
|
+
<AppBar.Root>
|
|
495
|
+
<AppBar.Left>
|
|
496
|
+
<WrappedButton edge="trailing" />
|
|
497
|
+
</AppBar.Left>
|
|
498
|
+
</AppBar.Root>,
|
|
499
|
+
);
|
|
500
|
+
expect(getAppBarRoot().querySelector(".seed-app-bar__iconButton")).toHaveClass(
|
|
501
|
+
"seed-app-bar__icon-button-edge-trailing",
|
|
502
|
+
);
|
|
503
|
+
expect(mount).toHaveBeenCalledTimes(1);
|
|
504
|
+
});
|
|
274
505
|
});
|
|
275
506
|
|
|
276
507
|
describe("AppBar icon recipe ownership", () => {
|