@seed-design/lynx-react 0.6.3 → 0.7.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.d.ts.map +1 -1
- package/lib/components/Accordion/Accordion.jsx +24 -14
- package/lib/components/ActionButton/ActionButton.d.ts +1 -1
- package/lib/components/ActionButton/ActionButton.d.ts.map +1 -1
- package/lib/components/ActionButton/ActionButton.jsx +12 -4
- package/lib/components/AppBar/AppBar.d.ts.map +1 -1
- package/lib/components/AppBar/AppBar.jsx +9 -8
- package/lib/components/Badge/Badge.d.ts.map +1 -1
- package/lib/components/Badge/Badge.jsx +2 -1
- package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/lib/components/BottomSheet/BottomSheet.jsx +9 -9
- package/lib/components/Box/Box.d.ts.map +1 -1
- package/lib/components/Box/Box.jsx +2 -1
- package/lib/components/Callout/Callout.d.ts +2 -2
- package/lib/components/Callout/Callout.d.ts.map +1 -1
- package/lib/components/Callout/Callout.jsx +20 -10
- package/lib/components/Checkbox/Checkbox.d.ts +4 -2
- package/lib/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/lib/components/Checkbox/Checkbox.jsx +33 -17
- package/lib/components/Chip/Chip.d.ts +1 -1
- package/lib/components/Chip/Chip.d.ts.map +1 -1
- package/lib/components/Chip/Chip.jsx +36 -16
- package/lib/components/Count/Count.d.ts +7 -0
- package/lib/components/Count/Count.d.ts.map +1 -0
- package/lib/components/Count/Count.jsx +19 -0
- package/lib/components/Count/index.d.ts +2 -0
- package/lib/components/Count/index.d.ts.map +1 -0
- package/lib/components/Divider/Divider.d.ts.map +1 -1
- package/lib/components/Divider/Divider.jsx +2 -1
- package/lib/components/Field/Field.d.ts.map +1 -1
- package/lib/components/Field/Field.jsx +11 -15
- package/lib/components/Icon/Icon.d.ts.map +1 -1
- package/lib/components/Icon/Icon.jsx +4 -3
- package/lib/components/InputButton/InputButton.d.ts +40 -0
- package/lib/components/InputButton/InputButton.d.ts.map +1 -0
- package/lib/components/InputButton/InputButton.jsx +118 -0
- package/lib/components/InputButton/InputButton.namespace.d.ts +2 -0
- package/lib/components/InputButton/InputButton.namespace.d.ts.map +1 -0
- package/lib/components/InputButton/InputButton.namespace.js +16 -0
- package/lib/components/InputButton/index.d.ts +3 -0
- package/lib/components/InputButton/index.d.ts.map +1 -0
- package/lib/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.d.ts.map +1 -1
- package/lib/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.jsx +12 -8
- package/lib/components/List/List.d.ts +51 -0
- package/lib/components/List/List.d.ts.map +1 -0
- package/lib/components/List/List.jsx +176 -0
- package/lib/components/List/List.namespace.d.ts +2 -0
- package/lib/components/List/List.namespace.d.ts.map +1 -0
- package/lib/components/List/List.namespace.js +18 -0
- package/lib/components/List/index.d.ts +3 -0
- package/lib/components/List/index.d.ts.map +1 -0
- package/lib/components/MannerTemp/MannerTemp.d.ts.map +1 -1
- package/lib/components/MannerTemp/MannerTemp.jsx +3 -2
- package/lib/components/MannerTempBadge/MannerTempBadge.d.ts.map +1 -1
- package/lib/components/MannerTempBadge/MannerTempBadge.jsx +2 -1
- package/lib/components/Menu/Menu.d.ts +69 -0
- package/lib/components/Menu/Menu.d.ts.map +1 -0
- package/lib/components/Menu/Menu.jsx +520 -0
- package/lib/components/Menu/Menu.namespace.d.ts +2 -0
- package/lib/components/Menu/Menu.namespace.d.ts.map +1 -0
- package/lib/components/Menu/Menu.namespace.js +21 -0
- package/lib/components/Menu/index.d.ts +3 -0
- package/lib/components/Menu/index.d.ts.map +1 -0
- package/lib/components/NotificationBadge/NotificationBadge.d.ts.map +1 -1
- package/lib/components/NotificationBadge/NotificationBadge.jsx +3 -2
- package/lib/components/PageBanner/PageBanner.d.ts +5 -5
- package/lib/components/PageBanner/PageBanner.d.ts.map +1 -1
- package/lib/components/PageBanner/PageBanner.jsx +25 -14
- package/lib/components/ProgressCircle/ProgressCircle.d.ts +2 -2
- package/lib/components/ProgressCircle/ProgressCircle.d.ts.map +1 -1
- package/lib/components/ProgressCircle/ProgressCircle.jsx +4 -3
- package/lib/components/RadioGroup/RadioGroup.d.ts +5 -3
- package/lib/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/lib/components/RadioGroup/RadioGroup.jsx +22 -9
- package/lib/components/ReactionButton/ReactionButton.d.ts +20 -0
- package/lib/components/ReactionButton/ReactionButton.d.ts.map +1 -0
- package/lib/components/ReactionButton/ReactionButton.jsx +88 -0
- package/lib/components/ReactionButton/index.d.ts +2 -0
- package/lib/components/ReactionButton/index.d.ts.map +1 -0
- package/lib/components/ScaleFeedback/ScaleFeedback.d.ts +11 -0
- package/lib/components/ScaleFeedback/ScaleFeedback.d.ts.map +1 -0
- package/lib/components/ScaleFeedback/ScaleFeedback.jsx +16 -0
- package/lib/components/ScaleFeedback/index.d.ts +2 -0
- package/lib/components/ScaleFeedback/index.d.ts.map +1 -0
- package/lib/components/SegmentedControl/SegmentedControl.d.ts +1 -0
- package/lib/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/lib/components/SegmentedControl/SegmentedControl.jsx +23 -10
- package/lib/components/SelectBox/SelectBox.d.ts.map +1 -1
- package/lib/components/SelectBox/SelectBox.jsx +23 -13
- package/lib/components/Stack/Stack.d.ts.map +1 -1
- package/lib/components/Stack/Stack.jsx +2 -1
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts +85 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts.map +1 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.jsx +256 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.d.ts +2 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.d.ts.map +1 -0
- package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.js +24 -0
- package/lib/components/SwipeableMenuSheet/index.d.ts +3 -0
- package/lib/components/SwipeableMenuSheet/index.d.ts.map +1 -0
- package/lib/components/Switch/Switch.d.ts +27 -3
- package/lib/components/Switch/Switch.d.ts.map +1 -1
- package/lib/components/Switch/Switch.jsx +22 -9
- package/lib/components/Tabs/Tabs.d.ts +4 -2
- package/lib/components/Tabs/Tabs.d.ts.map +1 -1
- package/lib/components/Tabs/Tabs.jsx +37 -22
- package/lib/components/TagGroup/TagGroup.d.ts.map +1 -1
- package/lib/components/TagGroup/TagGroup.jsx +4 -3
- package/lib/components/Text/Text.d.ts.map +1 -1
- package/lib/components/Text/Text.jsx +2 -1
- package/lib/components/TextField/TextField.d.ts.map +1 -1
- package/lib/components/TextField/TextField.jsx +35 -23
- package/lib/components/index.d.ts +7 -0
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/private/Positioning.d.ts +69 -0
- package/lib/components/private/Positioning.d.ts.map +1 -0
- package/lib/components/private/Positioning.js +109 -0
- package/lib/components/private/TrackPositioning.d.ts +22 -0
- package/lib/components/private/TrackPositioning.d.ts.map +1 -0
- package/lib/contexts/ScaleFeedbackContentContext.d.ts +4 -0
- package/lib/contexts/ScaleFeedbackContentContext.d.ts.map +1 -0
- package/lib/contexts/ScaleFeedbackContentContext.js +6 -0
- package/lib/contexts/index.d.ts +2 -0
- package/lib/contexts/index.d.ts.map +1 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.d.ts.map +1 -1
- package/lib/hooks/useIconColor.d.ts.map +1 -1
- package/lib/hooks/useIconColor.js +1 -1
- package/lib/hooks/usePressTap.d.ts +4 -3
- package/lib/hooks/usePressTap.d.ts.map +1 -1
- package/lib/hooks/useScaleFeedback.d.ts +48 -0
- package/lib/hooks/useScaleFeedback.d.ts.map +1 -0
- package/lib/hooks/useScaleFeedback.js +108 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +17 -3
- package/lib/node_modules/.bun/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js +493 -0
- package/lib/node_modules/.bun/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +114 -0
- package/lib/utils/calculate-scale-feedback.d.ts +5 -0
- package/lib/utils/calculate-scale-feedback.d.ts.map +1 -0
- package/lib/utils/calculate-scale-feedback.js +13 -0
- package/lib/utils/compose-event-handlers.d.ts +5 -0
- package/lib/utils/compose-event-handlers.d.ts.map +1 -0
- package/lib/utils/compose-event-handlers.js +16 -0
- package/lib/utils/create-slot-recipe-context.d.ts.map +1 -1
- package/lib/utils/create-slot-recipe-context.jsx +6 -16
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/merge-props.d.ts +15 -0
- package/lib/utils/merge-props.d.ts.map +1 -0
- package/lib/utils/merge-props.js +36 -0
- package/lib/utils/merge-refs.d.ts +8 -0
- package/lib/utils/merge-refs.d.ts.map +1 -0
- package/lib/utils/merge-refs.js +38 -0
- package/package.json +6 -5
- package/src/components/Accordion/Accordion.tsx +36 -27
- package/src/components/ActionButton/ActionButton.tsx +27 -12
- package/src/components/AppBar/AppBar.tsx +17 -18
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/BottomSheet/BottomSheet.tsx +9 -17
- package/src/components/Box/Box.tsx +2 -2
- package/src/components/Callout/Callout.tsx +39 -22
- package/src/components/Checkbox/Checkbox.test.tsx +44 -0
- package/src/components/Checkbox/Checkbox.tsx +52 -21
- package/src/components/Chip/Chip.test.tsx +50 -1
- package/src/components/Chip/Chip.tsx +75 -31
- package/src/components/Count/Count.tsx +35 -0
- package/src/components/Count/index.ts +1 -0
- package/src/components/Divider/Divider.tsx +2 -2
- package/src/components/Field/Field.tsx +15 -28
- package/src/components/Icon/Icon.tsx +14 -7
- package/src/components/InputButton/InputButton.namespace.ts +20 -0
- package/src/components/InputButton/InputButton.test.tsx +82 -0
- package/src/components/InputButton/InputButton.tsx +295 -0
- package/src/components/InputButton/index.ts +2 -0
- package/src/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.tsx +16 -21
- package/src/components/List/List.namespace.ts +24 -0
- package/src/components/List/List.test.tsx +162 -0
- package/src/components/List/List.tsx +476 -0
- package/src/components/List/index.ts +3 -0
- package/src/components/MannerTemp/MannerTemp.tsx +3 -4
- package/src/components/MannerTempBadge/MannerTempBadge.tsx +2 -2
- package/src/components/Menu/Menu.namespace.ts +26 -0
- package/src/components/Menu/Menu.tsx +883 -0
- package/src/components/Menu/index.ts +31 -0
- package/src/components/NotificationBadge/NotificationBadge.tsx +4 -9
- package/src/components/PageBanner/PageBanner.test.tsx +3 -0
- package/src/components/PageBanner/PageBanner.tsx +54 -45
- package/src/components/ProgressCircle/ProgressCircle.test.tsx +48 -0
- package/src/components/ProgressCircle/ProgressCircle.tsx +22 -3
- package/src/components/RadioGroup/RadioGroup.test.tsx +87 -0
- package/src/components/RadioGroup/RadioGroup.tsx +50 -14
- package/src/components/ReactionButton/ReactionButton.test.tsx +122 -0
- package/src/components/ReactionButton/ReactionButton.tsx +139 -0
- package/src/components/ReactionButton/index.ts +1 -0
- package/src/components/ScaleFeedback/ScaleFeedback.test.tsx +41 -0
- package/src/components/ScaleFeedback/ScaleFeedback.tsx +32 -0
- package/src/components/ScaleFeedback/index.ts +1 -0
- package/src/components/SegmentedControl/SegmentedControl.test.tsx +15 -3
- package/src/components/SegmentedControl/SegmentedControl.tsx +35 -14
- package/src/components/SelectBox/SelectBox.test.tsx +39 -1
- package/src/components/SelectBox/SelectBox.tsx +27 -16
- package/src/components/Stack/Stack.tsx +2 -2
- package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.ts +37 -0
- package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.test.tsx +258 -0
- package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.tsx +655 -0
- package/src/components/SwipeableMenuSheet/index.ts +43 -0
- package/src/components/Switch/Switch.test.tsx +57 -0
- package/src/components/Switch/Switch.tsx +60 -16
- package/src/components/Tabs/Tabs.test.tsx +19 -0
- package/src/components/Tabs/Tabs.tsx +72 -40
- package/src/components/TagGroup/TagGroup.tsx +4 -6
- package/src/components/Text/Text.tsx +2 -2
- package/src/components/TextField/TextField.tsx +60 -54
- package/src/components/index.ts +7 -0
- package/src/components/private/Positioning.test.ts +235 -0
- package/src/components/private/Positioning.ts +223 -0
- package/src/components/private/TrackPositioning.test.ts +58 -0
- package/src/components/private/TrackPositioning.ts +37 -0
- package/src/contexts/ScaleFeedbackContentContext.ts +4 -0
- package/src/contexts/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useIconColor.ts +5 -4
- package/src/hooks/usePressTap.ts +4 -3
- package/src/hooks/useScaleFeedback.integration.test.tsx +85 -0
- package/src/hooks/useScaleFeedback.test.ts +50 -0
- package/src/hooks/useScaleFeedback.ts +199 -0
- package/src/index.ts +1 -0
- package/src/utils/calculate-scale-feedback.ts +12 -0
- package/src/utils/compose-event-handlers.ts +16 -0
- package/src/utils/create-slot-recipe-context.tsx +6 -7
- package/src/utils/index.ts +1 -0
- package/src/utils/merge-props.test.tsx +152 -0
- package/src/utils/merge-props.ts +62 -0
- package/src/utils/merge-refs.ts +44 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import * as React from "@lynx-js/react";
|
|
2
|
+
import type { NodesRef } from "@lynx-js/types";
|
|
3
|
+
import {
|
|
4
|
+
inputButton,
|
|
5
|
+
type InputButtonVariantProps,
|
|
6
|
+
} from "@seed-design/lynx-css/recipes/input-button";
|
|
7
|
+
import clsx from "clsx";
|
|
8
|
+
|
|
9
|
+
import { usePressTap } from "../../hooks/usePressTap";
|
|
10
|
+
import type {
|
|
11
|
+
LynxAccessibilityProps,
|
|
12
|
+
LynxPressableProps,
|
|
13
|
+
LynxStyledElementProps,
|
|
14
|
+
LynxTextRef,
|
|
15
|
+
LynxViewRef,
|
|
16
|
+
} from "../../types";
|
|
17
|
+
import { InternalIcon, type InternalIconProps } from "../Icon/Icon";
|
|
18
|
+
|
|
19
|
+
interface InputButtonContextValue {
|
|
20
|
+
variantProps: InputButtonVariantProps;
|
|
21
|
+
disabled: boolean;
|
|
22
|
+
readOnly: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const InputButtonContext = React.createContext<InputButtonContextValue | null>(null);
|
|
26
|
+
|
|
27
|
+
function useInputButtonContext(consumer: string): InputButtonContextValue {
|
|
28
|
+
const context = React.useContext(InputButtonContext);
|
|
29
|
+
|
|
30
|
+
if (!context) {
|
|
31
|
+
throw new Error(`<${consumer}/> must be rendered inside <InputButton.Root/>.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return context;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @platform Lynx
|
|
41
|
+
*
|
|
42
|
+
* 웹 대비 미지원 기능:
|
|
43
|
+
* - `size="responsive"`: Lynx에는 CSS viewport breakpoint가 없음
|
|
44
|
+
* - HTML form 제출과 DOM ARIA id 연결
|
|
45
|
+
*/
|
|
46
|
+
export interface InputButtonRootProps
|
|
47
|
+
extends Omit<InputButtonVariantProps, "pressed">,
|
|
48
|
+
LynxStyledElementProps {}
|
|
49
|
+
|
|
50
|
+
export const InputButtonRoot = React.forwardRef<NodesRef, InputButtonRootProps>(
|
|
51
|
+
(props, forwardedRef) => {
|
|
52
|
+
const [variantProps, otherProps] = inputButton.splitVariantProps(props);
|
|
53
|
+
const { children, className, ...nativeProps } = otherProps;
|
|
54
|
+
const disabled = variantProps.disabled ?? false;
|
|
55
|
+
const readOnly = variantProps.readOnly ?? false;
|
|
56
|
+
const classes = inputButton(variantProps);
|
|
57
|
+
const contextValue = React.useMemo(
|
|
58
|
+
() => ({ variantProps, disabled, readOnly }),
|
|
59
|
+
[variantProps, disabled, readOnly],
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<InputButtonContext.Provider value={contextValue}>
|
|
64
|
+
<view
|
|
65
|
+
{...(forwardedRef ? { ref: forwardedRef } : {})}
|
|
66
|
+
className={clsx(classes.root, className)}
|
|
67
|
+
{...nativeProps}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</view>
|
|
71
|
+
</InputButtonContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
InputButtonRoot.displayName = "InputButtonRoot";
|
|
76
|
+
|
|
77
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
78
|
+
|
|
79
|
+
export interface InputButtonButtonProps
|
|
80
|
+
extends LynxStyledElementProps,
|
|
81
|
+
LynxPressableProps,
|
|
82
|
+
LynxAccessibilityProps {}
|
|
83
|
+
|
|
84
|
+
export const InputButtonButton = React.forwardRef<unknown, InputButtonButtonProps>((props, ref) => {
|
|
85
|
+
const context = useInputButtonContext("InputButton.Button");
|
|
86
|
+
const {
|
|
87
|
+
children,
|
|
88
|
+
className,
|
|
89
|
+
bindtap,
|
|
90
|
+
"main-thread:bindtap": mainThreadBindtap,
|
|
91
|
+
"accessibility-element": accessibilityElement = true,
|
|
92
|
+
"accessibility-traits": accessibilityTraits,
|
|
93
|
+
...nativeProps
|
|
94
|
+
} = props;
|
|
95
|
+
const nonInteractive = context.disabled || context.readOnly;
|
|
96
|
+
const { pressed, ...pressHandlers } = usePressTap({
|
|
97
|
+
disabled: nonInteractive,
|
|
98
|
+
onTap: bindtap,
|
|
99
|
+
mainThreadOnTap: mainThreadBindtap,
|
|
100
|
+
});
|
|
101
|
+
const classes = inputButton({ ...context.variantProps, pressed });
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<view
|
|
105
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
106
|
+
className={clsx(classes.button, className)}
|
|
107
|
+
accessibility-element={accessibilityElement}
|
|
108
|
+
accessibility-traits={accessibilityTraits ?? (nonInteractive ? "disabled" : "button")}
|
|
109
|
+
{...pressHandlers}
|
|
110
|
+
{...nativeProps}
|
|
111
|
+
>
|
|
112
|
+
<view className={classes.baseStroke} accessibility-elements-hidden={true} />
|
|
113
|
+
<view className={classes.stroke} accessibility-elements-hidden={true} />
|
|
114
|
+
{children}
|
|
115
|
+
</view>
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
InputButtonButton.displayName = "InputButtonButton";
|
|
119
|
+
|
|
120
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
121
|
+
|
|
122
|
+
export interface InputButtonValueProps extends LynxStyledElementProps {}
|
|
123
|
+
|
|
124
|
+
export const InputButtonValue = React.forwardRef<unknown, InputButtonValueProps>((props, ref) => {
|
|
125
|
+
const context = useInputButtonContext("InputButton.Value");
|
|
126
|
+
const classes = inputButton(context.variantProps);
|
|
127
|
+
const { children, className, ...nativeProps } = props;
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<text
|
|
131
|
+
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
132
|
+
className={clsx(classes.value, className)}
|
|
133
|
+
accessibility-elements-hidden={true}
|
|
134
|
+
{...nativeProps}
|
|
135
|
+
>
|
|
136
|
+
{children}
|
|
137
|
+
</text>
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
InputButtonValue.displayName = "InputButtonValue";
|
|
141
|
+
|
|
142
|
+
export interface InputButtonPlaceholderProps extends LynxStyledElementProps {}
|
|
143
|
+
|
|
144
|
+
export const InputButtonPlaceholder = React.forwardRef<unknown, InputButtonPlaceholderProps>(
|
|
145
|
+
(props, ref) => {
|
|
146
|
+
const context = useInputButtonContext("InputButton.Placeholder");
|
|
147
|
+
const classes = inputButton(context.variantProps);
|
|
148
|
+
const { children, className, ...nativeProps } = props;
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<text
|
|
152
|
+
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
153
|
+
className={clsx(classes.placeholder, className)}
|
|
154
|
+
accessibility-elements-hidden={true}
|
|
155
|
+
{...nativeProps}
|
|
156
|
+
>
|
|
157
|
+
{children}
|
|
158
|
+
</text>
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
InputButtonPlaceholder.displayName = "InputButtonPlaceholder";
|
|
163
|
+
|
|
164
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
165
|
+
|
|
166
|
+
export interface InputButtonPrefixTextProps extends LynxStyledElementProps {}
|
|
167
|
+
|
|
168
|
+
export const InputButtonPrefixText = React.forwardRef<unknown, InputButtonPrefixTextProps>(
|
|
169
|
+
(props, ref) => {
|
|
170
|
+
const context = useInputButtonContext("InputButton.PrefixText");
|
|
171
|
+
const classes = inputButton(context.variantProps);
|
|
172
|
+
const { children, className, ...nativeProps } = props;
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<text
|
|
176
|
+
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
177
|
+
className={clsx(classes.prefixText, className)}
|
|
178
|
+
accessibility-elements-hidden={true}
|
|
179
|
+
{...nativeProps}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
</text>
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
);
|
|
186
|
+
InputButtonPrefixText.displayName = "InputButtonPrefixText";
|
|
187
|
+
|
|
188
|
+
export interface InputButtonPrefixIconProps extends InternalIconProps {}
|
|
189
|
+
|
|
190
|
+
export const InputButtonPrefixIcon = React.forwardRef<unknown, InputButtonPrefixIconProps>(
|
|
191
|
+
(props, ref) => {
|
|
192
|
+
const context = useInputButtonContext("InputButton.PrefixIcon");
|
|
193
|
+
const classes = inputButton(context.variantProps);
|
|
194
|
+
const { className, ...otherProps } = props;
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<InternalIcon
|
|
198
|
+
ref={ref}
|
|
199
|
+
className={clsx(classes.prefixIcon, className)}
|
|
200
|
+
accessibility-elements-hidden={true}
|
|
201
|
+
{...otherProps}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
InputButtonPrefixIcon.displayName = "InputButtonPrefixIcon";
|
|
207
|
+
|
|
208
|
+
export interface InputButtonSuffixTextProps extends LynxStyledElementProps {}
|
|
209
|
+
|
|
210
|
+
export const InputButtonSuffixText = React.forwardRef<unknown, InputButtonSuffixTextProps>(
|
|
211
|
+
(props, ref) => {
|
|
212
|
+
const context = useInputButtonContext("InputButton.SuffixText");
|
|
213
|
+
const classes = inputButton(context.variantProps);
|
|
214
|
+
const { children, className, ...nativeProps } = props;
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<text
|
|
218
|
+
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
219
|
+
className={clsx(classes.suffixText, className)}
|
|
220
|
+
accessibility-elements-hidden={true}
|
|
221
|
+
{...nativeProps}
|
|
222
|
+
>
|
|
223
|
+
{children}
|
|
224
|
+
</text>
|
|
225
|
+
);
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
InputButtonSuffixText.displayName = "InputButtonSuffixText";
|
|
229
|
+
|
|
230
|
+
export interface InputButtonSuffixIconProps extends InternalIconProps {}
|
|
231
|
+
|
|
232
|
+
export const InputButtonSuffixIcon = React.forwardRef<unknown, InputButtonSuffixIconProps>(
|
|
233
|
+
(props, ref) => {
|
|
234
|
+
const context = useInputButtonContext("InputButton.SuffixIcon");
|
|
235
|
+
const classes = inputButton(context.variantProps);
|
|
236
|
+
const { className, ...otherProps } = props;
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<InternalIcon
|
|
240
|
+
ref={ref}
|
|
241
|
+
className={clsx(classes.suffixIcon, className)}
|
|
242
|
+
accessibility-elements-hidden={true}
|
|
243
|
+
{...otherProps}
|
|
244
|
+
/>
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
);
|
|
248
|
+
InputButtonSuffixIcon.displayName = "InputButtonSuffixIcon";
|
|
249
|
+
|
|
250
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
251
|
+
|
|
252
|
+
export interface InputButtonClearButtonProps
|
|
253
|
+
extends InternalIconProps,
|
|
254
|
+
LynxPressableProps,
|
|
255
|
+
LynxAccessibilityProps {}
|
|
256
|
+
|
|
257
|
+
export const InputButtonClearButton = React.forwardRef<unknown, InputButtonClearButtonProps>(
|
|
258
|
+
(props, ref) => {
|
|
259
|
+
const context = useInputButtonContext("InputButton.ClearButton");
|
|
260
|
+
const {
|
|
261
|
+
className,
|
|
262
|
+
bindtap,
|
|
263
|
+
"main-thread:bindtap": mainThreadBindtap,
|
|
264
|
+
"accessibility-element": accessibilityElement = true,
|
|
265
|
+
"accessibility-label": accessibilityLabel,
|
|
266
|
+
...otherProps
|
|
267
|
+
} = props;
|
|
268
|
+
const nonInteractive = context.disabled || context.readOnly;
|
|
269
|
+
const { pressed, ...pressHandlers } = usePressTap({
|
|
270
|
+
disabled: nonInteractive,
|
|
271
|
+
onTap: bindtap,
|
|
272
|
+
mainThreadOnTap: mainThreadBindtap,
|
|
273
|
+
});
|
|
274
|
+
const classes = inputButton({ ...context.variantProps, pressed });
|
|
275
|
+
|
|
276
|
+
if (nonInteractive) return null;
|
|
277
|
+
|
|
278
|
+
if (process.env.NODE_ENV !== "production" && !accessibilityLabel) {
|
|
279
|
+
console.warn("InputButton.ClearButton requires `accessibility-label` for accessibility.");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return (
|
|
283
|
+
<InternalIcon
|
|
284
|
+
ref={ref}
|
|
285
|
+
className={clsx(classes.clearButton, className)}
|
|
286
|
+
accessibility-element={accessibilityElement}
|
|
287
|
+
accessibility-label={accessibilityLabel}
|
|
288
|
+
accessibility-traits="button"
|
|
289
|
+
{...pressHandlers}
|
|
290
|
+
{...otherProps}
|
|
291
|
+
/>
|
|
292
|
+
);
|
|
293
|
+
},
|
|
294
|
+
);
|
|
295
|
+
InputButtonClearButton.displayName = "InputButtonClearButton";
|
|
@@ -21,6 +21,7 @@ import { KeyboardAvoidanceActionsContext, type KeyboardAvoidanceActions } from "
|
|
|
21
21
|
import { createKeyboardAvoidingEngine, type KeyboardAvoidingScheduler } from "./engine";
|
|
22
22
|
import { lynxKeyboardEventSource } from "./keyboard-event-source";
|
|
23
23
|
import { lynxKeyboardAvoidingNativeDriver } from "./native-driver";
|
|
24
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
24
25
|
|
|
25
26
|
type NativeScrollViewProps = IntrinsicElements["scroll-view"];
|
|
26
27
|
type LayoutChangeHandler = NonNullable<NativeScrollViewProps["bindlayoutchange"]>;
|
|
@@ -147,17 +148,8 @@ export const KeyboardAvoidingScrollView: LynxForwardRefComponent<
|
|
|
147
148
|
[],
|
|
148
149
|
);
|
|
149
150
|
|
|
150
|
-
const mergedRef =
|
|
151
|
-
(
|
|
152
|
-
"background only";
|
|
153
|
-
|
|
154
|
-
scrollRef.current = node;
|
|
155
|
-
if (typeof forwardedRef === "function") {
|
|
156
|
-
forwardedRef(node);
|
|
157
|
-
} else if (forwardedRef) {
|
|
158
|
-
forwardedRef.current = node;
|
|
159
|
-
}
|
|
160
|
-
},
|
|
151
|
+
const mergedRef = useMemo(
|
|
152
|
+
() => mergeProps({ ref: scrollRef }, { ref: forwardedRef }).ref,
|
|
161
153
|
[forwardedRef],
|
|
162
154
|
);
|
|
163
155
|
|
|
@@ -276,21 +268,24 @@ export const KeyboardAvoidingScrollView: LynxForwardRefComponent<
|
|
|
276
268
|
return (
|
|
277
269
|
<KeyboardAvoidanceActionsContext.Provider value={actions}>
|
|
278
270
|
<scroll-view
|
|
279
|
-
{...
|
|
280
|
-
|
|
271
|
+
{...mergeProps(
|
|
272
|
+
{
|
|
273
|
+
ref: mergedRef,
|
|
274
|
+
bindlayoutchange: handleLayoutChange,
|
|
275
|
+
bindtouchstart: handleTouchStart,
|
|
276
|
+
bindtouchend: handleTouchEnd,
|
|
277
|
+
bindtouchcancel: handleTouchCancel,
|
|
278
|
+
bindscroll: handleScroll,
|
|
279
|
+
bindscrollend: handleScrollEnd,
|
|
280
|
+
},
|
|
281
|
+
nativeProps,
|
|
282
|
+
)}
|
|
281
283
|
scroll-orientation="vertical"
|
|
282
284
|
flatten={false}
|
|
283
|
-
bindlayoutchange={handleLayoutChange}
|
|
284
|
-
bindtouchstart={handleTouchStart}
|
|
285
|
-
bindtouchend={handleTouchEnd}
|
|
286
|
-
bindtouchcancel={handleTouchCancel}
|
|
287
|
-
bindscroll={handleScroll}
|
|
288
|
-
bindscrollend={handleScrollEnd}
|
|
289
285
|
>
|
|
290
286
|
{children}
|
|
291
287
|
<view
|
|
292
|
-
{...({ ref: spacerRef as LynxViewRef } as Record<string, unknown
|
|
293
|
-
{...spacerProps}
|
|
288
|
+
{...mergeProps({ ref: spacerRef as LynxViewRef } as Record<string, unknown>, spacerProps)}
|
|
294
289
|
/>
|
|
295
290
|
</scroll-view>
|
|
296
291
|
</KeyboardAvoidanceActionsContext.Provider>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export {
|
|
2
|
+
ListButtonItem as ButtonItem,
|
|
3
|
+
ListCheckboxItem as CheckboxItem,
|
|
4
|
+
ListContent as Content,
|
|
5
|
+
ListDetail as Detail,
|
|
6
|
+
ListItem as Item,
|
|
7
|
+
ListPrefix as Prefix,
|
|
8
|
+
ListRadioItem as RadioItem,
|
|
9
|
+
ListRoot as Root,
|
|
10
|
+
ListSuffix as Suffix,
|
|
11
|
+
ListSwitchItem as SwitchItem,
|
|
12
|
+
ListTitle as Title,
|
|
13
|
+
type ListButtonItemProps as ButtonItemProps,
|
|
14
|
+
type ListCheckboxItemProps as CheckboxItemProps,
|
|
15
|
+
type ListContentProps as ContentProps,
|
|
16
|
+
type ListDetailProps as DetailProps,
|
|
17
|
+
type ListItemProps as ItemProps,
|
|
18
|
+
type ListPrefixProps as PrefixProps,
|
|
19
|
+
type ListRadioItemProps as RadioItemProps,
|
|
20
|
+
type ListRootProps as RootProps,
|
|
21
|
+
type ListSuffixProps as SuffixProps,
|
|
22
|
+
type ListSwitchItemProps as SwitchItemProps,
|
|
23
|
+
type ListTitleProps as TitleProps,
|
|
24
|
+
} from "./List";
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { fireEvent, render } from "@lynx-js/react/testing-library";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { RadioGroup } from "../RadioGroup";
|
|
6
|
+
import { List, ListHeader } from "./index";
|
|
7
|
+
|
|
8
|
+
function getRenderedRoot() {
|
|
9
|
+
const root = elementTree.root;
|
|
10
|
+
|
|
11
|
+
if (!root) {
|
|
12
|
+
throw new Error("Expected Lynx render root to exist.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return root;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getListItem(className: string) {
|
|
19
|
+
const item = getRenderedRoot().querySelector<HTMLElement>(`.${className}`);
|
|
20
|
+
|
|
21
|
+
if (!item) {
|
|
22
|
+
throw new Error(`Expected ${className} to exist.`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return item;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("List", () => {
|
|
29
|
+
it("renders a header variant", () => {
|
|
30
|
+
render(
|
|
31
|
+
<view>
|
|
32
|
+
<ListHeader variant="boldSolid" className="list-header">
|
|
33
|
+
목록 제목
|
|
34
|
+
</ListHeader>
|
|
35
|
+
</view>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(getRenderedRoot().querySelector(".list-header")).toHaveClass(
|
|
39
|
+
"seed-list-header--variant_boldSolid",
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("renders the container and item slots", () => {
|
|
44
|
+
render(
|
|
45
|
+
<List.Root className="list-root">
|
|
46
|
+
<List.Item highlighted className="static-item">
|
|
47
|
+
<List.Prefix>앞</List.Prefix>
|
|
48
|
+
<List.Content>
|
|
49
|
+
<List.Title>제목</List.Title>
|
|
50
|
+
<List.Detail>설명</List.Detail>
|
|
51
|
+
</List.Content>
|
|
52
|
+
<List.Suffix>뒤</List.Suffix>
|
|
53
|
+
</List.Item>
|
|
54
|
+
</List.Root>,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const item = getListItem("static-item");
|
|
58
|
+
|
|
59
|
+
expect(getRenderedRoot().querySelector(".list-root")).toHaveClass("seed-list");
|
|
60
|
+
expect(item.querySelector(".seed-list-item__prefix")).toHaveTextContent("앞");
|
|
61
|
+
expect(item.querySelector(".seed-list-item__title")).toHaveTextContent("제목");
|
|
62
|
+
expect(item.querySelector(".seed-list-item__detail")).toHaveTextContent("설명");
|
|
63
|
+
expect(item.querySelector(".seed-list-item__suffix")).toHaveTextContent("뒤");
|
|
64
|
+
expect(item.querySelector(".seed-list-item__pressedOverlay")).toHaveClass(
|
|
65
|
+
"seed-list-item__pressedOverlay--highlighted_true",
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("tracks button pressed state and ignores a disabled tap", () => {
|
|
70
|
+
const onTap = vi.fn();
|
|
71
|
+
const { rerender } = render(
|
|
72
|
+
<List.ButtonItem className="button-item" bindtap={onTap} accessibility-label="열기">
|
|
73
|
+
<List.Content>
|
|
74
|
+
<List.Title>버튼</List.Title>
|
|
75
|
+
</List.Content>
|
|
76
|
+
</List.ButtonItem>,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
let item = getListItem("button-item");
|
|
80
|
+
fireEvent.touchstart(item, {});
|
|
81
|
+
expect(item.querySelector(".seed-list-item__pressedOverlay")).toHaveClass(
|
|
82
|
+
"seed-list-item__pressedOverlay--pressed_true",
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
fireEvent.tap(item);
|
|
86
|
+
expect(onTap).toHaveBeenCalledTimes(1);
|
|
87
|
+
|
|
88
|
+
rerender(
|
|
89
|
+
<List.ButtonItem disabled className="button-item" bindtap={onTap} accessibility-label="열기">
|
|
90
|
+
<List.Content>
|
|
91
|
+
<List.Title>버튼</List.Title>
|
|
92
|
+
</List.Content>
|
|
93
|
+
</List.ButtonItem>,
|
|
94
|
+
);
|
|
95
|
+
item = getListItem("button-item");
|
|
96
|
+
fireEvent.tap(item);
|
|
97
|
+
|
|
98
|
+
expect(onTap).toHaveBeenCalledTimes(1);
|
|
99
|
+
expect(item).toHaveAttribute("accessibility-traits", "disabled");
|
|
100
|
+
expect(item.querySelector(".seed-list-item__title")).toHaveClass(
|
|
101
|
+
"seed-list-item__title--disabled_true",
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("uses the existing checkbox and switch state", () => {
|
|
106
|
+
const onCheckedChange = vi.fn();
|
|
107
|
+
|
|
108
|
+
render(
|
|
109
|
+
<List.Root>
|
|
110
|
+
<List.CheckboxItem className="checkbox-item" onCheckedChange={onCheckedChange}>
|
|
111
|
+
<List.Content>
|
|
112
|
+
<List.Title>체크</List.Title>
|
|
113
|
+
</List.Content>
|
|
114
|
+
</List.CheckboxItem>
|
|
115
|
+
<List.SwitchItem className="switch-item">
|
|
116
|
+
<List.Content>
|
|
117
|
+
<List.Title>스위치</List.Title>
|
|
118
|
+
</List.Content>
|
|
119
|
+
</List.SwitchItem>
|
|
120
|
+
</List.Root>,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const checkbox = getListItem("checkbox-item");
|
|
124
|
+
const checkboxRoot = checkbox.parentElement as HTMLElement;
|
|
125
|
+
expect(checkbox).toHaveAttribute("accessibility-value", "선택 안 됨");
|
|
126
|
+
fireEvent.tap(checkboxRoot);
|
|
127
|
+
expect(onCheckedChange).toHaveBeenCalledWith(true);
|
|
128
|
+
expect(checkbox).toHaveAttribute("accessibility-value", "선택됨");
|
|
129
|
+
|
|
130
|
+
const switchItem = getListItem("switch-item");
|
|
131
|
+
const switchRoot = switchItem.parentElement as HTMLElement;
|
|
132
|
+
expect(switchItem).toHaveAttribute("accessibility-value", "꺼짐");
|
|
133
|
+
fireEvent.tap(switchRoot);
|
|
134
|
+
expect(switchItem).toHaveAttribute("accessibility-value", "켜짐");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("uses radio-group selection state", () => {
|
|
138
|
+
render(
|
|
139
|
+
<RadioGroup.Root defaultValue="first">
|
|
140
|
+
<List.RadioItem value="first" className="first-radio">
|
|
141
|
+
<List.Content>
|
|
142
|
+
<List.Title>첫 번째</List.Title>
|
|
143
|
+
</List.Content>
|
|
144
|
+
</List.RadioItem>
|
|
145
|
+
<List.RadioItem value="second" className="second-radio">
|
|
146
|
+
<List.Content>
|
|
147
|
+
<List.Title>두 번째</List.Title>
|
|
148
|
+
</List.Content>
|
|
149
|
+
</List.RadioItem>
|
|
150
|
+
</RadioGroup.Root>,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const first = getListItem("first-radio");
|
|
154
|
+
const second = getListItem("second-radio");
|
|
155
|
+
expect(first).toHaveAttribute("accessibility-value", "선택됨");
|
|
156
|
+
expect(second).toHaveAttribute("accessibility-value", "선택 안 됨");
|
|
157
|
+
|
|
158
|
+
fireEvent.tap(second.parentElement as HTMLElement);
|
|
159
|
+
expect(first).toHaveAttribute("accessibility-value", "선택 안 됨");
|
|
160
|
+
expect(second).toHaveAttribute("accessibility-value", "선택됨");
|
|
161
|
+
});
|
|
162
|
+
});
|