@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,26 @@
|
|
|
1
|
+
export {
|
|
2
|
+
HelpBubbleAnchor,
|
|
3
|
+
HelpBubbleArrow,
|
|
4
|
+
HelpBubbleArrowTip,
|
|
5
|
+
HelpBubbleBody,
|
|
6
|
+
HelpBubbleCloseButton,
|
|
7
|
+
HelpBubbleContent,
|
|
8
|
+
HelpBubbleDescription,
|
|
9
|
+
HelpBubblePositioner,
|
|
10
|
+
HelpBubbleRoot,
|
|
11
|
+
HelpBubbleTitle,
|
|
12
|
+
HelpBubbleTrigger,
|
|
13
|
+
type HelpBubbleAnchorProps,
|
|
14
|
+
type HelpBubbleArrowProps,
|
|
15
|
+
type HelpBubbleArrowTipProps,
|
|
16
|
+
type HelpBubbleBodyProps,
|
|
17
|
+
type HelpBubbleCloseButtonProps,
|
|
18
|
+
type HelpBubbleContentProps,
|
|
19
|
+
type HelpBubbleDescriptionProps,
|
|
20
|
+
type HelpBubblePositionerProps,
|
|
21
|
+
type HelpBubbleRootProps,
|
|
22
|
+
type HelpBubbleTitleProps,
|
|
23
|
+
type HelpBubbleTriggerProps,
|
|
24
|
+
} from "./HelpBubble";
|
|
25
|
+
|
|
26
|
+
export * as HelpBubble from "./HelpBubble.namespace";
|
|
@@ -97,8 +97,6 @@ describe("InternalIcon", () => {
|
|
|
97
97
|
await waitSchedule();
|
|
98
98
|
|
|
99
99
|
const { image } = getSourceAndImage();
|
|
100
|
-
expect(frames.size).toBe(0);
|
|
101
|
-
expect(image.getAttribute("tint-color")).toBeNull();
|
|
102
100
|
|
|
103
101
|
rerender(renderIcon("checked"));
|
|
104
102
|
await waitSchedule();
|
|
@@ -106,7 +104,6 @@ describe("InternalIcon", () => {
|
|
|
106
104
|
expect(frames.size).toBe(1);
|
|
107
105
|
// The immediate read uses the old native style; the next frame must refresh it.
|
|
108
106
|
expect(image.getAttribute("tint-color")).toBe("rgb(134, 139, 148)");
|
|
109
|
-
|
|
110
107
|
computedColor = "rgb(255, 102, 0)";
|
|
111
108
|
runNextFrame();
|
|
112
109
|
|
|
@@ -262,10 +262,19 @@ export const SuffixIcon = createIconComponent<SuffixIconProps>(
|
|
|
262
262
|
export interface InternalIconProps extends LynxStyledElementProps {
|
|
263
263
|
icon: ReactElement<LynxIconElementProps>;
|
|
264
264
|
deps?: DependencyList;
|
|
265
|
+
disableDefaultResize?: boolean;
|
|
265
266
|
}
|
|
266
267
|
|
|
267
268
|
export const InternalIcon = React.forwardRef<unknown, InternalIconProps>((props, ref) => {
|
|
268
|
-
const {
|
|
269
|
+
const {
|
|
270
|
+
icon,
|
|
271
|
+
deps = [],
|
|
272
|
+
className,
|
|
273
|
+
style,
|
|
274
|
+
children: _children,
|
|
275
|
+
disableDefaultResize = false,
|
|
276
|
+
...nativeProps
|
|
277
|
+
} = props;
|
|
269
278
|
const sourceRef = useMainThreadRef<MainThread.Element>(null);
|
|
270
279
|
const styleColor = getStyleColor(style);
|
|
271
280
|
const iconColor = useIconColor([className, styleColor, ...(deps ?? [])], { sourceRef });
|
|
@@ -284,6 +293,7 @@ export const InternalIcon = React.forwardRef<unknown, InternalIconProps>((props,
|
|
|
284
293
|
>
|
|
285
294
|
{cloneElement(icon, {
|
|
286
295
|
...iconColor,
|
|
296
|
+
...(disableDefaultResize ? { "disable-default-resize": true } : {}),
|
|
287
297
|
className: icon.props.className,
|
|
288
298
|
style: {
|
|
289
299
|
...icon.props.style,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
identityPlaceholder,
|
|
3
|
+
type IdentityPlaceholderVariantProps,
|
|
4
|
+
} from "@seed-design/lynx-css/recipes/identity-placeholder";
|
|
5
|
+
import type { IntrinsicElements, NodesRef } from "@lynx-js/types";
|
|
6
|
+
import clsx from "clsx";
|
|
7
|
+
import * as React from "@lynx-js/react";
|
|
8
|
+
|
|
9
|
+
import type { LynxStyledElementProps, LynxViewRef } from "../../types";
|
|
10
|
+
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
|
|
11
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
12
|
+
import businessSource from "./identity-placeholder-business.webp";
|
|
13
|
+
import personSource from "./identity-placeholder-person.webp";
|
|
14
|
+
|
|
15
|
+
const { ClassNamesProvider, PropsProvider, useClassNames, useProps } =
|
|
16
|
+
createSlotRecipeContext(identityPlaceholder);
|
|
17
|
+
|
|
18
|
+
type Identity = NonNullable<IdentityPlaceholderVariantProps["identity"]>;
|
|
19
|
+
|
|
20
|
+
const identitySources = {
|
|
21
|
+
person: personSource,
|
|
22
|
+
business: businessSource,
|
|
23
|
+
} satisfies Record<Identity, string>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @platform Lynx
|
|
27
|
+
*
|
|
28
|
+
* Web의 SVG/asChild API 대신 native `<view>` props를 받습니다.
|
|
29
|
+
*/
|
|
30
|
+
export interface IdentityPlaceholderRootProps
|
|
31
|
+
extends IdentityPlaceholderVariantProps,
|
|
32
|
+
LynxStyledElementProps {}
|
|
33
|
+
|
|
34
|
+
export const IdentityPlaceholderRoot = React.forwardRef<unknown, IdentityPlaceholderRootProps>(
|
|
35
|
+
(props, ref) => {
|
|
36
|
+
const [variantProps, otherProps] = identityPlaceholder.splitVariantProps(props);
|
|
37
|
+
const { children, className, style, ...nativeProps } = otherProps;
|
|
38
|
+
const classNames = identityPlaceholder(variantProps);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<ClassNamesProvider value={classNames}>
|
|
42
|
+
<PropsProvider value={variantProps}>
|
|
43
|
+
<view
|
|
44
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
45
|
+
className={clsx(classNames.root, className)}
|
|
46
|
+
style={style}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
</view>
|
|
50
|
+
</PropsProvider>
|
|
51
|
+
</ClassNamesProvider>
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
IdentityPlaceholderRoot.displayName = "IdentityPlaceholderRoot";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @platform Lynx
|
|
59
|
+
*
|
|
60
|
+
* `src`와 `mode`는 identity variant가 소유합니다. Web SVG props 대신 native image
|
|
61
|
+
* props를 사용하며 SVG rendering과 `asChild`는 지원하지 않습니다.
|
|
62
|
+
*
|
|
63
|
+
* React SVG의 기본 `xMidYMid meet`처럼 도형 전체를 비율을 유지한 채 영역 안에 맞춥니다.
|
|
64
|
+
*
|
|
65
|
+
* 로컬 WebP는 `static-white-alpha-800`의 고정값 `#ffffffde`로 원본 SVG path를
|
|
66
|
+
* rasterize합니다. Native image의 SVG/fill 경로를 피하고, 토큰이 light/dark에서
|
|
67
|
+
* 동일하므로 동적 tint를 사용하지 않습니다.
|
|
68
|
+
*/
|
|
69
|
+
export interface IdentityPlaceholderImageProps
|
|
70
|
+
extends Omit<IntrinsicElements["image"], "src" | "mode" | "children"> {}
|
|
71
|
+
|
|
72
|
+
export const IdentityPlaceholderImage = React.forwardRef<unknown, IdentityPlaceholderImageProps>(
|
|
73
|
+
(props, ref) => {
|
|
74
|
+
const classNames = useClassNames();
|
|
75
|
+
const parentProps = useProps();
|
|
76
|
+
|
|
77
|
+
if (parentProps === null) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
"<IdentityPlaceholderImage/> must be rendered inside <IdentityPlaceholderRoot/>.",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const {
|
|
84
|
+
className,
|
|
85
|
+
"accessibility-label": accessibilityLabel,
|
|
86
|
+
"accessibility-traits": accessibilityTraits,
|
|
87
|
+
...nativeProps
|
|
88
|
+
} = props;
|
|
89
|
+
const identity = parentProps.identity ?? "person";
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<image
|
|
93
|
+
{...mergeProps(ref ? { ref: ref as React.Ref<NodesRef> } : {}, nativeProps)}
|
|
94
|
+
src={identitySources[identity]}
|
|
95
|
+
mode="aspectFit"
|
|
96
|
+
accessibility-label={accessibilityLabel ?? "Identity placeholder"}
|
|
97
|
+
accessibility-traits={accessibilityTraits ?? "image"}
|
|
98
|
+
className={clsx(classNames.image, className)}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
IdentityPlaceholderImage.displayName = "IdentityPlaceholderImage";
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import "@testing-library/jest-dom";
|
|
2
|
-
import
|
|
2
|
+
import * as React from "@lynx-js/react";
|
|
3
|
+
import { runOnBackground } from "@lynx-js/react";
|
|
4
|
+
import {
|
|
5
|
+
fireEvent,
|
|
6
|
+
getQueriesForElement,
|
|
7
|
+
render,
|
|
8
|
+
waitSchedule,
|
|
9
|
+
} from "@lynx-js/react/testing-library";
|
|
3
10
|
import { describe, expect, it, vi } from "vitest";
|
|
4
11
|
|
|
5
12
|
import { InputButton } from "./index";
|
|
13
|
+
import type { LynxIconElementProps } from "../../types";
|
|
14
|
+
import type { MainThread } from "@lynx-js/types";
|
|
15
|
+
|
|
16
|
+
const MockIcon = React.forwardRef<MainThread.Element, LynxIconElementProps>((props, ref) => (
|
|
17
|
+
<image {...props} {...(ref ? { "main-thread:ref": ref as React.Ref<MainThread.Element> } : {})} />
|
|
18
|
+
));
|
|
19
|
+
MockIcon.displayName = "MockIcon";
|
|
6
20
|
|
|
7
21
|
function getRenderedRoot() {
|
|
8
22
|
const root = elementTree.root;
|
|
@@ -76,6 +90,119 @@ describe("InputButton", () => {
|
|
|
76
90
|
);
|
|
77
91
|
});
|
|
78
92
|
|
|
93
|
+
it("groups fragment content while leaving the button and strokes outside the scale target", () => {
|
|
94
|
+
render(
|
|
95
|
+
<InputButton.Root>
|
|
96
|
+
<React.Fragment key="fragment-slots">
|
|
97
|
+
<InputButton.Button accessibility-label="Select" />
|
|
98
|
+
<InputButton.PrefixText>Prefix</InputButton.PrefixText>
|
|
99
|
+
<InputButton.Value>Value</InputButton.Value>
|
|
100
|
+
<InputButton.SuffixText>Suffix</InputButton.SuffixText>
|
|
101
|
+
</React.Fragment>
|
|
102
|
+
</InputButton.Root>,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const root = getRenderedRoot();
|
|
106
|
+
const content = root.querySelector(".seed-input-button__content");
|
|
107
|
+
const button = root.querySelector(".seed-input-button__button");
|
|
108
|
+
expect(content).toHaveAttribute("flatten", "false");
|
|
109
|
+
expect(content?.contains(button)).toBe(false);
|
|
110
|
+
expect(button?.querySelector(".seed-input-button__baseStroke")).toBeTruthy();
|
|
111
|
+
expect(button?.querySelector(".seed-input-button__stroke")).toBeTruthy();
|
|
112
|
+
expect(Array.from(content?.children ?? []).map((child) => child.textContent)).toEqual([
|
|
113
|
+
"Prefix",
|
|
114
|
+
"Value",
|
|
115
|
+
"Suffix",
|
|
116
|
+
]);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("preserves custom wrapped Button composition without moving or dropping children", () => {
|
|
120
|
+
const CustomButton = () => <InputButton.Button accessibility-label="Custom" />;
|
|
121
|
+
render(
|
|
122
|
+
<InputButton.Root>
|
|
123
|
+
<CustomButton />
|
|
124
|
+
<InputButton.Value>Value</InputButton.Value>
|
|
125
|
+
</InputButton.Root>,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const root = getRenderedRoot();
|
|
129
|
+
expect(root.querySelector(".seed-input-button__button")).toHaveAttribute(
|
|
130
|
+
"accessibility-label",
|
|
131
|
+
"Custom",
|
|
132
|
+
);
|
|
133
|
+
expect(root.querySelector(".seed-input-button__content")).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("keeps the clear action independent and hides it in readonly mode", () => {
|
|
137
|
+
const onOpen = vi.fn();
|
|
138
|
+
const onClear = vi.fn();
|
|
139
|
+
const { rerender } = render(
|
|
140
|
+
<InputButton.Root>
|
|
141
|
+
<InputButton.Button accessibility-label="Select" bindtap={onOpen} />
|
|
142
|
+
<InputButton.Value>Value</InputButton.Value>
|
|
143
|
+
<InputButton.ClearButton
|
|
144
|
+
icon={<MockIcon />}
|
|
145
|
+
accessibility-label="Clear"
|
|
146
|
+
bindtap={onClear}
|
|
147
|
+
/>
|
|
148
|
+
</InputButton.Root>,
|
|
149
|
+
);
|
|
150
|
+
const root = getRenderedRoot();
|
|
151
|
+
const clear = root.querySelector(".seed-input-button__clearButton") as HTMLElement;
|
|
152
|
+
expect(clear).toHaveAttribute("flatten", "false");
|
|
153
|
+
fireEvent.tap(clear);
|
|
154
|
+
expect(onClear).toHaveBeenCalledTimes(1);
|
|
155
|
+
expect(onOpen).not.toHaveBeenCalled();
|
|
156
|
+
expect(root.querySelector(".seed-input-button__button")).not.toHaveClass(
|
|
157
|
+
"seed-input-button__button--pressed_true",
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
rerender(
|
|
161
|
+
<InputButton.Root readOnly>
|
|
162
|
+
<InputButton.Button accessibility-label="Select" bindtap={onOpen} />
|
|
163
|
+
<InputButton.ClearButton
|
|
164
|
+
icon={<MockIcon />}
|
|
165
|
+
accessibility-label="Clear"
|
|
166
|
+
bindtap={onClear}
|
|
167
|
+
/>
|
|
168
|
+
</InputButton.Root>,
|
|
169
|
+
);
|
|
170
|
+
expect(getRenderedRoot().querySelector(".seed-input-button__clearButton")).toBeNull();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("bridges Main Thread presses while preserving the consumer Main Thread handler", async () => {
|
|
174
|
+
function Example({ report }: { report: () => void }) {
|
|
175
|
+
function handleTouch() {
|
|
176
|
+
"main thread";
|
|
177
|
+
runOnBackground(report)();
|
|
178
|
+
}
|
|
179
|
+
return (
|
|
180
|
+
<InputButton.Root>
|
|
181
|
+
<InputButton.Button
|
|
182
|
+
accessibility-label="Select"
|
|
183
|
+
main-thread:bindtouchstart={handleTouch}
|
|
184
|
+
/>
|
|
185
|
+
<InputButton.Value>Value</InputButton.Value>
|
|
186
|
+
</InputButton.Root>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const report = vi.fn();
|
|
190
|
+
const { container } = render(<Example report={report} />, {
|
|
191
|
+
enableMainThread: true,
|
|
192
|
+
enableBackgroundThread: true,
|
|
193
|
+
});
|
|
194
|
+
await waitSchedule();
|
|
195
|
+
const button = container.querySelector(".seed-input-button__button");
|
|
196
|
+
if (!button) throw new Error("Expected button");
|
|
197
|
+
fireEvent.touchstart(button, {});
|
|
198
|
+
await waitSchedule();
|
|
199
|
+
expect(report).toHaveBeenCalledTimes(1);
|
|
200
|
+
expect(button.className).toContain("pressed_true");
|
|
201
|
+
fireEvent.touchcancel(button, {});
|
|
202
|
+
await waitSchedule();
|
|
203
|
+
expect(button.className).not.toContain("pressed_true");
|
|
204
|
+
});
|
|
205
|
+
|
|
79
206
|
it("throws when a slot is rendered outside InputButton.Root", () => {
|
|
80
207
|
expect(() => render(<InputButton.Value>값</InputButton.Value>)).toThrow(/InputButton\.Value/);
|
|
81
208
|
});
|
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
import clsx from "clsx";
|
|
8
8
|
|
|
9
9
|
import { usePressTap } from "../../hooks/usePressTap";
|
|
10
|
+
import { useScaleFeedback, type ScaleFeedbackTriggerProps } from "../../hooks/useScaleFeedback";
|
|
11
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
12
|
+
import { toArray } from "../../utils/children";
|
|
10
13
|
import type {
|
|
11
14
|
LynxAccessibilityProps,
|
|
12
15
|
LynxPressableProps,
|
|
@@ -20,6 +23,8 @@ interface InputButtonContextValue {
|
|
|
20
23
|
variantProps: InputButtonVariantProps;
|
|
21
24
|
disabled: boolean;
|
|
22
25
|
readOnly: boolean;
|
|
26
|
+
pressed: boolean;
|
|
27
|
+
scaleFeedbackTriggerProps: ScaleFeedbackTriggerProps;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
const InputButtonContext = React.createContext<InputButtonContextValue | null>(null);
|
|
@@ -42,6 +47,8 @@ function useInputButtonContext(consumer: string): InputButtonContextValue {
|
|
|
42
47
|
* 웹 대비 미지원 기능:
|
|
43
48
|
* - `size="responsive"`: Lynx에는 CSS viewport breakpoint가 없음
|
|
44
49
|
* - HTML form 제출과 DOM ARIA id 연결
|
|
50
|
+
* - Content Scale을 적용하려면 Button을 Root의 직접 자식 또는 Fragment 안에 둡니다.
|
|
51
|
+
* 커스텀 컴포넌트로 감싼 Button은 기존 구조를 보존하며 Content Scale을 생략합니다.
|
|
45
52
|
*/
|
|
46
53
|
export interface InputButtonRootProps
|
|
47
54
|
extends Omit<InputButtonVariantProps, "pressed">,
|
|
@@ -54,9 +61,21 @@ export const InputButtonRoot = React.forwardRef<NodesRef, InputButtonRootProps>(
|
|
|
54
61
|
const disabled = variantProps.disabled ?? false;
|
|
55
62
|
const readOnly = variantProps.readOnly ?? false;
|
|
56
63
|
const classes = inputButton(variantProps);
|
|
64
|
+
const { pressed, bindtouchstart, bindtouchend, bindtouchcancel } = usePressTap({
|
|
65
|
+
disabled: disabled || readOnly,
|
|
66
|
+
});
|
|
67
|
+
const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
|
|
68
|
+
disabled: disabled || readOnly,
|
|
69
|
+
onTouchStart: bindtouchstart,
|
|
70
|
+
onTouchEnd: bindtouchend,
|
|
71
|
+
onTouchCancel: bindtouchcancel,
|
|
72
|
+
});
|
|
73
|
+
const childArray = flattenInputButtonChildren(children);
|
|
74
|
+
const buttonChildren = childArray.filter(isInputButtonButton);
|
|
75
|
+
const contentChildren = childArray.filter((child) => !isInputButtonButton(child));
|
|
57
76
|
const contextValue = React.useMemo(
|
|
58
|
-
() => ({ variantProps, disabled, readOnly }),
|
|
59
|
-
[variantProps, disabled, readOnly],
|
|
77
|
+
() => ({ variantProps, disabled, readOnly, pressed, scaleFeedbackTriggerProps }),
|
|
78
|
+
[variantProps, disabled, readOnly, pressed, scaleFeedbackTriggerProps],
|
|
60
79
|
);
|
|
61
80
|
|
|
62
81
|
return (
|
|
@@ -66,7 +85,16 @@ export const InputButtonRoot = React.forwardRef<NodesRef, InputButtonRootProps>(
|
|
|
66
85
|
className={clsx(classes.root, className)}
|
|
67
86
|
{...nativeProps}
|
|
68
87
|
>
|
|
69
|
-
{
|
|
88
|
+
{buttonChildren.length > 0 ? (
|
|
89
|
+
<>
|
|
90
|
+
{buttonChildren}
|
|
91
|
+
<view {...scaleFeedbackTargetProps} className={classes.content}>
|
|
92
|
+
{contentChildren}
|
|
93
|
+
</view>
|
|
94
|
+
</>
|
|
95
|
+
) : (
|
|
96
|
+
children
|
|
97
|
+
)}
|
|
70
98
|
</view>
|
|
71
99
|
</InputButtonContext.Provider>
|
|
72
100
|
);
|
|
@@ -93,12 +121,12 @@ export const InputButtonButton = React.forwardRef<unknown, InputButtonButtonProp
|
|
|
93
121
|
...nativeProps
|
|
94
122
|
} = props;
|
|
95
123
|
const nonInteractive = context.disabled || context.readOnly;
|
|
96
|
-
const {
|
|
124
|
+
const { bindtap: handleTap, "main-thread:bindtap": handleMainThreadTap } = usePressTap({
|
|
97
125
|
disabled: nonInteractive,
|
|
98
126
|
onTap: bindtap,
|
|
99
127
|
mainThreadOnTap: mainThreadBindtap,
|
|
100
128
|
});
|
|
101
|
-
const classes = inputButton({ ...context.variantProps, pressed });
|
|
129
|
+
const classes = inputButton({ ...context.variantProps, pressed: context.pressed });
|
|
102
130
|
|
|
103
131
|
return (
|
|
104
132
|
<view
|
|
@@ -106,8 +134,11 @@ export const InputButtonButton = React.forwardRef<unknown, InputButtonButtonProp
|
|
|
106
134
|
className={clsx(classes.button, className)}
|
|
107
135
|
accessibility-element={accessibilityElement}
|
|
108
136
|
accessibility-traits={accessibilityTraits ?? (nonInteractive ? "disabled" : "button")}
|
|
109
|
-
{...
|
|
110
|
-
|
|
137
|
+
{...mergeProps(
|
|
138
|
+
{ bindtap: handleTap, "main-thread:bindtap": handleMainThreadTap },
|
|
139
|
+
context.scaleFeedbackTriggerProps,
|
|
140
|
+
nativeProps,
|
|
141
|
+
)}
|
|
111
142
|
>
|
|
112
143
|
<view className={classes.baseStroke} accessibility-elements-hidden={true} />
|
|
113
144
|
<view className={classes.stroke} accessibility-elements-hidden={true} />
|
|
@@ -117,6 +148,18 @@ export const InputButtonButton = React.forwardRef<unknown, InputButtonButtonProp
|
|
|
117
148
|
});
|
|
118
149
|
InputButtonButton.displayName = "InputButtonButton";
|
|
119
150
|
|
|
151
|
+
function isInputButtonButton(node: React.ReactNode) {
|
|
152
|
+
return React.isValidElement(node) && node.type === InputButtonButton;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function flattenInputButtonChildren(children: React.ReactNode): React.ReactNode[] {
|
|
156
|
+
return toArray(children).flatMap((child) =>
|
|
157
|
+
React.isValidElement<{ children?: React.ReactNode }>(child) && child.type === React.Fragment
|
|
158
|
+
? flattenInputButtonChildren(child.props.children)
|
|
159
|
+
: [child],
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
120
163
|
////////////////////////////////////////////////////////////////////////////////////
|
|
121
164
|
|
|
122
165
|
export interface InputButtonValueProps extends LynxStyledElementProps {}
|
|
@@ -272,6 +315,9 @@ export const InputButtonClearButton = React.forwardRef<unknown, InputButtonClear
|
|
|
272
315
|
mainThreadOnTap: mainThreadBindtap,
|
|
273
316
|
});
|
|
274
317
|
const classes = inputButton({ ...context.variantProps, pressed });
|
|
318
|
+
const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
|
|
319
|
+
disabled: nonInteractive,
|
|
320
|
+
});
|
|
275
321
|
|
|
276
322
|
if (nonInteractive) return null;
|
|
277
323
|
|
|
@@ -286,8 +332,13 @@ export const InputButtonClearButton = React.forwardRef<unknown, InputButtonClear
|
|
|
286
332
|
accessibility-element={accessibilityElement}
|
|
287
333
|
accessibility-label={accessibilityLabel}
|
|
288
334
|
accessibility-traits="button"
|
|
289
|
-
{...
|
|
290
|
-
|
|
335
|
+
{...mergeProps(
|
|
336
|
+
pressHandlers,
|
|
337
|
+
scaleFeedbackTriggerProps,
|
|
338
|
+
scaleFeedbackTargetProps,
|
|
339
|
+
otherProps,
|
|
340
|
+
{ flatten: false },
|
|
341
|
+
)}
|
|
291
342
|
/>
|
|
292
343
|
);
|
|
293
344
|
},
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import "@testing-library/jest-dom";
|
|
2
|
-
import { fireEvent, render } from "@lynx-js/react/testing-library";
|
|
2
|
+
import { fireEvent, render, waitSchedule } from "@lynx-js/react/testing-library";
|
|
3
3
|
import { describe, expect, it, vi } from "vitest";
|
|
4
4
|
|
|
5
|
+
import { Checkbox } from "../Checkbox";
|
|
6
|
+
import { Switch } from "../Switch";
|
|
5
7
|
import { RadioGroup } from "../RadioGroup";
|
|
6
8
|
import { List, ListHeader } from "./index";
|
|
7
9
|
|
|
@@ -66,7 +68,7 @@ describe("List", () => {
|
|
|
66
68
|
);
|
|
67
69
|
});
|
|
68
70
|
|
|
69
|
-
it("tracks button pressed state and ignores a disabled tap", () => {
|
|
71
|
+
it("tracks button pressed state and ignores a disabled tap", async () => {
|
|
70
72
|
const onTap = vi.fn();
|
|
71
73
|
const { rerender } = render(
|
|
72
74
|
<List.ButtonItem className="button-item" bindtap={onTap} accessibility-label="열기">
|
|
@@ -74,15 +76,19 @@ describe("List", () => {
|
|
|
74
76
|
<List.Title>버튼</List.Title>
|
|
75
77
|
</List.Content>
|
|
76
78
|
</List.ButtonItem>,
|
|
79
|
+
{ enableMainThread: true, enableBackgroundThread: true },
|
|
77
80
|
);
|
|
78
81
|
|
|
82
|
+
await waitSchedule();
|
|
79
83
|
let item = getListItem("button-item");
|
|
80
84
|
fireEvent.touchstart(item, {});
|
|
85
|
+
await waitSchedule();
|
|
81
86
|
expect(item.querySelector(".seed-list-item__pressedOverlay")).toHaveClass(
|
|
82
87
|
"seed-list-item__pressedOverlay--pressed_true",
|
|
83
88
|
);
|
|
84
89
|
|
|
85
90
|
fireEvent.tap(item);
|
|
91
|
+
await waitSchedule();
|
|
86
92
|
expect(onTap).toHaveBeenCalledTimes(1);
|
|
87
93
|
|
|
88
94
|
rerender(
|
|
@@ -94,6 +100,7 @@ describe("List", () => {
|
|
|
94
100
|
);
|
|
95
101
|
item = getListItem("button-item");
|
|
96
102
|
fireEvent.tap(item);
|
|
103
|
+
await waitSchedule();
|
|
97
104
|
|
|
98
105
|
expect(onTap).toHaveBeenCalledTimes(1);
|
|
99
106
|
expect(item).toHaveAttribute("accessibility-traits", "disabled");
|
|
@@ -159,4 +166,49 @@ describe("List", () => {
|
|
|
159
166
|
expect(first).toHaveAttribute("accessibility-value", "선택 안 됨");
|
|
160
167
|
expect(second).toHaveAttribute("accessibility-value", "선택됨");
|
|
161
168
|
});
|
|
169
|
+
it("scales only interactive row content and suppresses nested control targets", () => {
|
|
170
|
+
render(
|
|
171
|
+
<List.Root>
|
|
172
|
+
<List.Item className="static-row">
|
|
173
|
+
<List.Title>Static</List.Title>
|
|
174
|
+
</List.Item>
|
|
175
|
+
<List.CheckboxItem className="check-row">
|
|
176
|
+
<List.Prefix>
|
|
177
|
+
<Checkbox.Control />
|
|
178
|
+
</List.Prefix>
|
|
179
|
+
<List.Title>Check</List.Title>
|
|
180
|
+
</List.CheckboxItem>
|
|
181
|
+
<List.SwitchItem className="switch-row">
|
|
182
|
+
<List.Suffix>
|
|
183
|
+
<Switch.Control>
|
|
184
|
+
<Switch.Thumb />
|
|
185
|
+
</Switch.Control>
|
|
186
|
+
</List.Suffix>
|
|
187
|
+
</List.SwitchItem>
|
|
188
|
+
<RadioGroup.Root>
|
|
189
|
+
<List.RadioItem value="a" className="radio-row">
|
|
190
|
+
<List.Prefix>
|
|
191
|
+
<RadioGroup.ItemControl />
|
|
192
|
+
</List.Prefix>
|
|
193
|
+
</List.RadioItem>
|
|
194
|
+
</RadioGroup.Root>
|
|
195
|
+
</List.Root>,
|
|
196
|
+
);
|
|
197
|
+
expect(getListItem("static-row").querySelector(".seed-list-item__layout")).not.toHaveAttribute(
|
|
198
|
+
"flatten",
|
|
199
|
+
"false",
|
|
200
|
+
);
|
|
201
|
+
for (const name of ["check-row", "switch-row", "radio-row"]) {
|
|
202
|
+
const row = getListItem(name);
|
|
203
|
+
const layout = row.querySelector(".seed-list-item__layout")!;
|
|
204
|
+
expect(layout).toHaveAttribute("flatten", "false");
|
|
205
|
+
expect(layout).not.toContainElement(row.querySelector(".seed-list-item__pressedOverlay"));
|
|
206
|
+
if (name === "switch-row") {
|
|
207
|
+
// Switch keeps its native view for its own thumb animation even without a scale target.
|
|
208
|
+
expect(layout.querySelector(".seed-switchmark__root")).toHaveAttribute("flatten", "false");
|
|
209
|
+
} else {
|
|
210
|
+
expect(layout.querySelectorAll('[flatten="false"]')).toHaveLength(0);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
162
214
|
});
|