@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,57 @@
|
|
|
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 { Switch } from "./index";
|
|
6
|
+
|
|
7
|
+
function getSwitchRoot(container: HTMLElement) {
|
|
8
|
+
const root = container.querySelector<HTMLElement>(".seed-switch__root");
|
|
9
|
+
|
|
10
|
+
if (!root) {
|
|
11
|
+
throw new Error("Expected Switch root to exist.");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return root;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("Switch", () => {
|
|
18
|
+
it("exposes switch accessibility state and preserves toggling", () => {
|
|
19
|
+
const onCheckedChange = vi.fn();
|
|
20
|
+
const { container } = render(
|
|
21
|
+
<Switch.Root accessibility-label="알림" onCheckedChange={onCheckedChange}>
|
|
22
|
+
<Switch.Control>
|
|
23
|
+
<Switch.Thumb />
|
|
24
|
+
</Switch.Control>
|
|
25
|
+
</Switch.Root>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const root = getSwitchRoot(container);
|
|
29
|
+
|
|
30
|
+
expect(root).toHaveAttribute("accessibility-element", "true");
|
|
31
|
+
expect(root).toHaveAttribute("accessibility-role-description", "switch");
|
|
32
|
+
expect(root).toHaveAttribute("accessibility-label", "알림");
|
|
33
|
+
expect(root).toHaveAttribute("accessibility-value", "not checked");
|
|
34
|
+
|
|
35
|
+
fireEvent.tap(root);
|
|
36
|
+
|
|
37
|
+
expect(onCheckedChange).toHaveBeenCalledWith(true);
|
|
38
|
+
expect(root).toHaveAttribute("accessibility-value", "checked");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("exposes the disabled state and ignores taps", () => {
|
|
42
|
+
const onCheckedChange = vi.fn();
|
|
43
|
+
const { container } = render(
|
|
44
|
+
<Switch.Root defaultChecked disabled onCheckedChange={onCheckedChange} />,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const root = getSwitchRoot(container);
|
|
48
|
+
|
|
49
|
+
expect(root).toHaveAttribute("accessibility-value", "checked");
|
|
50
|
+
expect(root).toHaveAttribute("accessibility-traits", "disabled");
|
|
51
|
+
|
|
52
|
+
fireEvent.tap(root);
|
|
53
|
+
|
|
54
|
+
expect(onCheckedChange).not.toHaveBeenCalled();
|
|
55
|
+
expect(root).toHaveAttribute("accessibility-value", "checked");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -9,7 +9,17 @@ import type { SwitchmarkVariantProps } from "@seed-design/lynx-css/recipes/switc
|
|
|
9
9
|
import { splitMultipleVariantsProps } from "../../utils/split-multiple-variants-props";
|
|
10
10
|
import { useControllableState } from "../../hooks/useControllableState";
|
|
11
11
|
import { usePressTap } from "../../hooks/usePressTap";
|
|
12
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
LynxAccessibilityProps,
|
|
14
|
+
LynxStyledElementProps,
|
|
15
|
+
LynxTextRef,
|
|
16
|
+
LynxViewRef,
|
|
17
|
+
} from "../../types";
|
|
18
|
+
import {
|
|
19
|
+
useScaleFeedback,
|
|
20
|
+
type ScaleFeedbackTargetProps,
|
|
21
|
+
} from "../../hooks/useScaleFeedback";
|
|
22
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
13
23
|
|
|
14
24
|
/**
|
|
15
25
|
* @platform Lynx
|
|
@@ -27,14 +37,16 @@ import type { LynxStyledElementProps, LynxTextRef, LynxViewRef } from "../../typ
|
|
|
27
37
|
interface SwitchContextValue {
|
|
28
38
|
checked: boolean;
|
|
29
39
|
disabled: boolean;
|
|
40
|
+
pressed: boolean;
|
|
30
41
|
switchVariantProps: SwitchVariantProps;
|
|
31
42
|
switchmarkVariantProps: SwitchmarkVariantProps;
|
|
32
43
|
toggle: () => void;
|
|
44
|
+
scaleFeedbackTargetProps: ScaleFeedbackTargetProps;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
const SwitchContext = React.createContext<SwitchContextValue | null>(null);
|
|
36
48
|
|
|
37
|
-
function useSwitchContext(consumer: string): SwitchContextValue {
|
|
49
|
+
export function useSwitchContext(consumer: string): SwitchContextValue {
|
|
38
50
|
const ctx = React.useContext(SwitchContext);
|
|
39
51
|
if (!ctx) {
|
|
40
52
|
throw new Error(`<${consumer}/> must be rendered inside <SwitchRoot/>.`);
|
|
@@ -62,7 +74,8 @@ function useSwitchmarkControlContext(consumer: string): SwitchmarkControlContext
|
|
|
62
74
|
export interface SwitchRootProps
|
|
63
75
|
extends SwitchVariantProps,
|
|
64
76
|
Omit<SwitchmarkVariantProps, "size">,
|
|
65
|
-
LynxStyledElementProps
|
|
77
|
+
LynxStyledElementProps,
|
|
78
|
+
LynxAccessibilityProps {
|
|
66
79
|
checked?: boolean;
|
|
67
80
|
defaultChecked?: boolean;
|
|
68
81
|
disabled?: boolean;
|
|
@@ -79,8 +92,15 @@ export const SwitchRoot = React.forwardRef<unknown, SwitchRootProps>((props, ref
|
|
|
79
92
|
onCheckedChange,
|
|
80
93
|
...restProps
|
|
81
94
|
} = props;
|
|
82
|
-
const [{ switch: switchVariantProps, switchmark: switchmarkVariantProps },
|
|
95
|
+
const [{ switch: switchVariantProps, switchmark: switchmarkVariantProps }, restNativeProps] =
|
|
83
96
|
splitMultipleVariantsProps(restProps, { switch: switchStyle, switchmark });
|
|
97
|
+
const {
|
|
98
|
+
"accessibility-element": accessibilityElement = true,
|
|
99
|
+
"accessibility-role-description": accessibilityRoleDescription = "switch",
|
|
100
|
+
"accessibility-traits": accessibilityTraits,
|
|
101
|
+
"accessibility-value": accessibilityValue,
|
|
102
|
+
...nativeProps
|
|
103
|
+
} = restNativeProps;
|
|
84
104
|
|
|
85
105
|
const [checked, setChecked] = useControllableState({
|
|
86
106
|
value: checkedProp,
|
|
@@ -90,10 +110,22 @@ export const SwitchRoot = React.forwardRef<unknown, SwitchRootProps>((props, ref
|
|
|
90
110
|
|
|
91
111
|
const toggle = React.useCallback(() => setChecked(!checked), [checked, setChecked]);
|
|
92
112
|
|
|
93
|
-
const {
|
|
113
|
+
const {
|
|
114
|
+
pressed,
|
|
115
|
+
bindtouchstart,
|
|
116
|
+
bindtouchend,
|
|
117
|
+
bindtouchcancel,
|
|
118
|
+
...pressHandlers
|
|
119
|
+
} = usePressTap({
|
|
94
120
|
disabled,
|
|
95
121
|
onTap: toggle,
|
|
96
122
|
});
|
|
123
|
+
const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
|
|
124
|
+
disabled,
|
|
125
|
+
onTouchStart: bindtouchstart,
|
|
126
|
+
onTouchEnd: bindtouchend,
|
|
127
|
+
onTouchCancel: bindtouchcancel,
|
|
128
|
+
});
|
|
97
129
|
|
|
98
130
|
const rootClassName = switchStyle({ ...switchVariantProps, disabled }).root;
|
|
99
131
|
|
|
@@ -101,20 +133,29 @@ export const SwitchRoot = React.forwardRef<unknown, SwitchRootProps>((props, ref
|
|
|
101
133
|
() => ({
|
|
102
134
|
checked,
|
|
103
135
|
disabled,
|
|
136
|
+
pressed,
|
|
104
137
|
switchVariantProps,
|
|
105
138
|
switchmarkVariantProps,
|
|
106
139
|
toggle,
|
|
140
|
+
scaleFeedbackTargetProps,
|
|
107
141
|
}),
|
|
108
|
-
[checked, disabled, switchVariantProps, switchmarkVariantProps, toggle],
|
|
142
|
+
[checked, disabled, pressed, switchVariantProps, switchmarkVariantProps, toggle, scaleFeedbackTargetProps],
|
|
109
143
|
);
|
|
110
144
|
|
|
111
145
|
return (
|
|
112
146
|
<SwitchContext.Provider value={contextValue}>
|
|
113
147
|
<view
|
|
114
|
-
{...(
|
|
148
|
+
{...mergeProps(
|
|
149
|
+
ref ? { ref: ref as LynxViewRef } : {},
|
|
150
|
+
scaleFeedbackTriggerProps,
|
|
151
|
+
pressHandlers,
|
|
152
|
+
nativeProps,
|
|
153
|
+
)}
|
|
115
154
|
className={clsx(rootClassName, className)}
|
|
116
|
-
{
|
|
117
|
-
{
|
|
155
|
+
accessibility-element={accessibilityElement}
|
|
156
|
+
accessibility-role-description={accessibilityRoleDescription}
|
|
157
|
+
accessibility-traits={accessibilityTraits ?? (disabled ? "disabled" : undefined)}
|
|
158
|
+
accessibility-value={accessibilityValue ?? (checked ? "checked" : "not checked")}
|
|
118
159
|
>
|
|
119
160
|
{children}
|
|
120
161
|
</view>
|
|
@@ -127,7 +168,8 @@ SwitchRoot.displayName = "SwitchRoot";
|
|
|
127
168
|
|
|
128
169
|
export interface SwitchControlProps
|
|
129
170
|
extends Pick<SwitchmarkVariantProps, "tone" | "size">,
|
|
130
|
-
|
|
171
|
+
// Keep the scale target's Android View even if shared props later expose flatten.
|
|
172
|
+
Omit<LynxStyledElementProps, "flatten"> {}
|
|
131
173
|
|
|
132
174
|
export const SwitchControl = React.forwardRef<unknown, SwitchControlProps>((props, ref) => {
|
|
133
175
|
const [variantProps, restProps] = switchmark.splitVariantProps(props);
|
|
@@ -146,9 +188,13 @@ export const SwitchControl = React.forwardRef<unknown, SwitchControlProps>((prop
|
|
|
146
188
|
value={{ thumbClassName: classes.thumb, switchmarkVariantProps }}
|
|
147
189
|
>
|
|
148
190
|
<view
|
|
149
|
-
{...(
|
|
191
|
+
{...mergeProps(
|
|
192
|
+
ref ? { ref: ref as LynxViewRef } : {},
|
|
193
|
+
context.scaleFeedbackTargetProps,
|
|
194
|
+
nativeProps,
|
|
195
|
+
)}
|
|
150
196
|
className={clsx(classes.root, className)}
|
|
151
|
-
{
|
|
197
|
+
flatten={false}
|
|
152
198
|
>
|
|
153
199
|
{children}
|
|
154
200
|
</view>
|
|
@@ -167,9 +213,8 @@ export const SwitchThumb = React.forwardRef<unknown, SwitchThumbProps>((props, r
|
|
|
167
213
|
|
|
168
214
|
return (
|
|
169
215
|
<view
|
|
170
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
216
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
171
217
|
className={clsx(thumbClassName, className)}
|
|
172
|
-
{...nativeProps}
|
|
173
218
|
/>
|
|
174
219
|
);
|
|
175
220
|
});
|
|
@@ -189,9 +234,8 @@ export const SwitchLabel = React.forwardRef<unknown, SwitchLabelProps>((props, r
|
|
|
189
234
|
|
|
190
235
|
return (
|
|
191
236
|
<text
|
|
192
|
-
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
237
|
+
{...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
|
|
193
238
|
className={clsx(labelClassName, className)}
|
|
194
|
-
{...nativeProps}
|
|
195
239
|
>
|
|
196
240
|
{children}
|
|
197
241
|
</text>
|
|
@@ -82,6 +82,25 @@ describe("Tabs", () => {
|
|
|
82
82
|
expect(second).toHaveAttribute("accessibility-value", "selected");
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
it("calls bindtap when the selected trigger is tapped again", () => {
|
|
86
|
+
const bindtap = vi.fn();
|
|
87
|
+
const onValueChange = vi.fn();
|
|
88
|
+
const { container } = render(
|
|
89
|
+
<Tabs.Root defaultValue="one" onValueChange={onValueChange}>
|
|
90
|
+
<Tabs.List>
|
|
91
|
+
<Tabs.Trigger value="one" bindtap={bindtap}>
|
|
92
|
+
첫 번째
|
|
93
|
+
</Tabs.Trigger>
|
|
94
|
+
</Tabs.List>
|
|
95
|
+
</Tabs.Root>,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
fireEvent.tap(getTrigger(container, "첫 번째"));
|
|
99
|
+
|
|
100
|
+
expect(bindtap).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
|
|
85
104
|
it("derives trigger positions from ordered widths instead of platform coordinates", () => {
|
|
86
105
|
expect(getTabsLayoutWidth({ detail: { width: 128 }, params: { width: 128 } })).toBe(128);
|
|
87
106
|
expect(
|
|
@@ -12,13 +12,16 @@ import clsx from "clsx";
|
|
|
12
12
|
|
|
13
13
|
import { useControllableState } from "../../hooks/useControllableState";
|
|
14
14
|
import { usePressTap } from "../../hooks/usePressTap";
|
|
15
|
+
import { useScaleFeedback } from "../../hooks/useScaleFeedback";
|
|
15
16
|
import type {
|
|
16
17
|
LynxAccessibilityProps,
|
|
18
|
+
LynxPressableProps,
|
|
17
19
|
LynxStyledElementProps,
|
|
18
20
|
LynxViewProps,
|
|
19
21
|
LynxViewRef,
|
|
20
22
|
} from "../../types";
|
|
21
23
|
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
|
|
24
|
+
import { Box } from "../Box";
|
|
22
25
|
import {
|
|
23
26
|
areTabsTransitionsEnabled,
|
|
24
27
|
getTabsLayoutWidth,
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
getTabsTriggerRects,
|
|
27
30
|
type TabsLayoutRect,
|
|
28
31
|
} from "./Tabs.utils";
|
|
32
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
29
33
|
|
|
30
34
|
type NativeViewProps = IntrinsicElements["view"];
|
|
31
35
|
type NativeViewPagerProps = IntrinsicElements["viewpager"];
|
|
@@ -333,8 +337,7 @@ export const TabsRoot = React.forwardRef<unknown, TabsRootProps>((props, ref) =>
|
|
|
333
337
|
<TabsContext.Provider value={contextValue}>
|
|
334
338
|
<ClassNamesProvider value={classNames}>
|
|
335
339
|
<view
|
|
336
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
337
|
-
{...nativeProps}
|
|
340
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
338
341
|
className={clsx(classNames.root, className)}
|
|
339
342
|
style={style}
|
|
340
343
|
>
|
|
@@ -381,19 +384,14 @@ export const TabsList = React.forwardRef<unknown, TabsListProps>((props, ref) =>
|
|
|
381
384
|
syncTriggerOrder(triggerOrder);
|
|
382
385
|
}, [items, syncTriggerOrder, triggerOrder]);
|
|
383
386
|
|
|
384
|
-
const mergedRef = React.
|
|
385
|
-
(
|
|
386
|
-
setListRef(node);
|
|
387
|
-
if (typeof ref === "function") ref(node);
|
|
388
|
-
else if (ref) ref.current = node;
|
|
389
|
-
},
|
|
387
|
+
const mergedRef = React.useMemo(
|
|
388
|
+
() => mergeProps({ ref: setListRef }, { ref: ref as LynxViewRef }).ref,
|
|
390
389
|
[ref, setListRef],
|
|
391
390
|
);
|
|
392
391
|
|
|
393
392
|
return (
|
|
394
393
|
<scroll-view
|
|
395
|
-
ref
|
|
396
|
-
{...nativeProps}
|
|
394
|
+
{...mergeProps({ ref: mergedRef }, nativeProps)}
|
|
397
395
|
scroll-orientation="horizontal"
|
|
398
396
|
scroll-bar-enable={false}
|
|
399
397
|
accessibility-element={false}
|
|
@@ -409,19 +407,26 @@ TabsList.displayName = "TabsList";
|
|
|
409
407
|
|
|
410
408
|
////////////////////////////////////////////////////////////////////////////////////
|
|
411
409
|
|
|
412
|
-
|
|
410
|
+
// Keep the scale target's Android View even if shared props later expose flatten.
|
|
411
|
+
export interface TabsTriggerProps
|
|
412
|
+
extends Omit<LynxStyledElementProps, "children" | "flatten">,
|
|
413
|
+
Pick<LynxPressableProps, "bindtap"> {
|
|
414
|
+
children: string | number;
|
|
413
415
|
value: string;
|
|
414
416
|
disabled?: boolean;
|
|
417
|
+
notification?: React.ReactNode;
|
|
415
418
|
"accessibility-label"?: LynxAccessibilityProps["accessibility-label"];
|
|
416
419
|
}
|
|
417
420
|
|
|
418
421
|
export const TabsTrigger = React.forwardRef<unknown, TabsTriggerProps>((props, ref) => {
|
|
419
422
|
const {
|
|
420
423
|
children,
|
|
424
|
+
notification,
|
|
421
425
|
className,
|
|
422
426
|
style,
|
|
423
427
|
value: triggerValue,
|
|
424
428
|
disabled = false,
|
|
429
|
+
bindtap,
|
|
425
430
|
"accessibility-label": accessibilityLabel,
|
|
426
431
|
...nativeProps
|
|
427
432
|
} = props;
|
|
@@ -439,11 +444,27 @@ export const TabsTrigger = React.forwardRef<unknown, TabsTriggerProps>((props, r
|
|
|
439
444
|
context.updateTriggerDisabled(triggerValue, disabled);
|
|
440
445
|
}, [context.updateTriggerDisabled, triggerValue, disabled]);
|
|
441
446
|
|
|
442
|
-
const handleTap = React.useCallback<NonNullable<NativeViewProps["bindtap"]>>(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
+
const handleTap = React.useCallback<NonNullable<NativeViewProps["bindtap"]>>(
|
|
448
|
+
(...args) => {
|
|
449
|
+
"background only";
|
|
450
|
+
bindtap?.(...args);
|
|
451
|
+
context.selectValue(triggerValue);
|
|
452
|
+
},
|
|
453
|
+
[bindtap, context.selectValue, triggerValue],
|
|
454
|
+
);
|
|
455
|
+
const {
|
|
456
|
+
pressed: _pressed,
|
|
457
|
+
bindtouchstart,
|
|
458
|
+
bindtouchend,
|
|
459
|
+
bindtouchcancel,
|
|
460
|
+
...pressHandlers
|
|
461
|
+
} = usePressTap({ disabled, onTap: handleTap });
|
|
462
|
+
const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
|
|
463
|
+
disabled,
|
|
464
|
+
onTouchStart: bindtouchstart,
|
|
465
|
+
onTouchEnd: bindtouchend,
|
|
466
|
+
onTouchCancel: bindtouchcancel,
|
|
467
|
+
});
|
|
447
468
|
|
|
448
469
|
const handleLayoutChange = React.useCallback<LayoutChangeHandler>(
|
|
449
470
|
(...args) => {
|
|
@@ -465,11 +486,15 @@ export const TabsTrigger = React.forwardRef<unknown, TabsTriggerProps>((props, r
|
|
|
465
486
|
|
|
466
487
|
return (
|
|
467
488
|
<view
|
|
468
|
-
{...(
|
|
469
|
-
|
|
470
|
-
|
|
489
|
+
{...mergeProps(
|
|
490
|
+
{ bindlayoutchange: handleLayoutChange },
|
|
491
|
+
ref ? { ref: ref as LynxViewRef } : {},
|
|
492
|
+
pressHandlers,
|
|
493
|
+
scaleFeedbackTargetProps,
|
|
494
|
+
scaleFeedbackTriggerProps,
|
|
495
|
+
nativeProps,
|
|
496
|
+
)}
|
|
471
497
|
flatten={false}
|
|
472
|
-
bindlayoutchange={handleLayoutChange}
|
|
473
498
|
accessibility-element={true}
|
|
474
499
|
accessibility-role-description="tab"
|
|
475
500
|
accessibility-label={accessibilityLabel ?? label}
|
|
@@ -478,7 +503,14 @@ export const TabsTrigger = React.forwardRef<unknown, TabsTriggerProps>((props, r
|
|
|
478
503
|
className={clsx(triggerClasses.trigger, className)}
|
|
479
504
|
style={style}
|
|
480
505
|
>
|
|
481
|
-
|
|
506
|
+
{notification ? (
|
|
507
|
+
<Box position="relative">
|
|
508
|
+
<text className={triggerClasses.triggerLabel}>{children}</text>
|
|
509
|
+
{notification}
|
|
510
|
+
</Box>
|
|
511
|
+
) : (
|
|
512
|
+
<text className={triggerClasses.triggerLabel}>{children}</text>
|
|
513
|
+
)}
|
|
482
514
|
</view>
|
|
483
515
|
);
|
|
484
516
|
});
|
|
@@ -507,9 +539,11 @@ export const TabsIndicator = React.forwardRef<unknown, TabsIndicatorProps>((prop
|
|
|
507
539
|
|
|
508
540
|
return (
|
|
509
541
|
<view
|
|
510
|
-
{...(
|
|
511
|
-
|
|
512
|
-
|
|
542
|
+
{...mergeProps(
|
|
543
|
+
{ "main-thread:ref": indicatorRef },
|
|
544
|
+
ref ? { ref: ref as LynxViewRef } : {},
|
|
545
|
+
nativeProps,
|
|
546
|
+
)}
|
|
513
547
|
accessibility-elements-hidden={true}
|
|
514
548
|
className={clsx(classNames.indicator, className)}
|
|
515
549
|
style={
|
|
@@ -545,8 +579,7 @@ export const TabsContent = React.forwardRef<unknown, TabsContentProps>((props, r
|
|
|
545
579
|
|
|
546
580
|
const content = (
|
|
547
581
|
<view
|
|
548
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
549
|
-
{...nativeProps}
|
|
582
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
550
583
|
accessibility-elements-hidden={!selected}
|
|
551
584
|
accessibility-role-description="tabpanel"
|
|
552
585
|
accessibility-value={selected ? "selected" : "not selected"}
|
|
@@ -603,8 +636,7 @@ export const TabsCarousel = React.forwardRef<unknown, TabsCarouselProps>((props,
|
|
|
603
636
|
return (
|
|
604
637
|
<TabsCarouselContext.Provider value={contextValue}>
|
|
605
638
|
<view
|
|
606
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
607
|
-
{...nativeProps}
|
|
639
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
608
640
|
className={clsx(classNames.carousel, className)}
|
|
609
641
|
style={style}
|
|
610
642
|
>
|
|
@@ -641,12 +673,8 @@ export const TabsCarouselCamera = React.forwardRef<unknown, TabsCarouselCameraPr
|
|
|
641
673
|
const { indicatorRef, pagerValues, triggerRects } = tabsContext;
|
|
642
674
|
const indicatorRects = pagerValues.map((value) => triggerRects[value] ?? null);
|
|
643
675
|
|
|
644
|
-
const mergedRef = React.
|
|
645
|
-
(
|
|
646
|
-
tabsContext.setPagerRef(node);
|
|
647
|
-
if (typeof ref === "function") ref(node);
|
|
648
|
-
else if (ref) ref.current = node;
|
|
649
|
-
},
|
|
676
|
+
const mergedRef = React.useMemo(
|
|
677
|
+
() => mergeProps({ ref: tabsContext.setPagerRef }, { ref: ref as LynxViewRef }).ref,
|
|
650
678
|
[ref, tabsContext.setPagerRef],
|
|
651
679
|
);
|
|
652
680
|
|
|
@@ -717,15 +745,19 @@ export const TabsCarouselCamera = React.forwardRef<unknown, TabsCarouselCameraPr
|
|
|
717
745
|
|
|
718
746
|
return (
|
|
719
747
|
<viewpager
|
|
720
|
-
|
|
721
|
-
|
|
748
|
+
{...mergeProps(
|
|
749
|
+
{
|
|
750
|
+
ref: mergedRef,
|
|
751
|
+
bindwillchange: handleWillChange,
|
|
752
|
+
bindchange: handleChange,
|
|
753
|
+
bindoffsetchange: handleOffsetChange,
|
|
754
|
+
"main-thread:bindoffsetchange": handleIndicatorOffsetChange,
|
|
755
|
+
},
|
|
756
|
+
nativeProps,
|
|
757
|
+
)}
|
|
722
758
|
initial-select-index={Math.max(0, tabsContext.selectedPagerIndex)}
|
|
723
759
|
enable-scroll={carouselContext.swipeable}
|
|
724
760
|
ios-gesture-offset={carouselContext.iosBackGestureEdgeWidth}
|
|
725
|
-
bindwillchange={handleWillChange}
|
|
726
|
-
bindchange={handleChange}
|
|
727
|
-
bindoffsetchange={handleOffsetChange}
|
|
728
|
-
main-thread:bindoffsetchange={handleIndicatorOffsetChange}
|
|
729
761
|
className={clsx(classNames.carouselCamera, className)}
|
|
730
762
|
style={style}
|
|
731
763
|
>
|
|
@@ -11,6 +11,7 @@ import { toArray } from "../../utils/children";
|
|
|
11
11
|
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
|
|
12
12
|
import { splitMultipleVariantsProps } from "../../utils/split-multiple-variants-props";
|
|
13
13
|
import { useStyleProps, type StyleProps } from "../../utils/styled";
|
|
14
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
14
15
|
|
|
15
16
|
const { PropsProvider, useProps, ClassNamesProvider, useClassNames } =
|
|
16
17
|
createSlotRecipeContext(tagGroupItem);
|
|
@@ -49,9 +50,8 @@ export const TagGroupRoot = React.forwardRef<unknown, TagGroupRootProps>((props,
|
|
|
49
50
|
return (
|
|
50
51
|
<PropsProvider value={tagGroupItemVariantProps}>
|
|
51
52
|
<view
|
|
52
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
53
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
53
54
|
className={clsx(classes.root, className)}
|
|
54
|
-
{...nativeProps}
|
|
55
55
|
>
|
|
56
56
|
{visibleChildren.map((child, index) => {
|
|
57
57
|
if (index === 0) return child;
|
|
@@ -97,10 +97,9 @@ export const TagGroupItem = React.forwardRef<unknown, TagGroupItemProps>((props,
|
|
|
97
97
|
return (
|
|
98
98
|
<ClassNamesProvider value={classes}>
|
|
99
99
|
<view
|
|
100
|
-
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
100
|
+
{...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
|
|
101
101
|
className={clsx(classes.root, className)}
|
|
102
102
|
style={style}
|
|
103
|
-
{...nativeProps}
|
|
104
103
|
>
|
|
105
104
|
{children}
|
|
106
105
|
</view>
|
|
@@ -118,9 +117,8 @@ export const TagGroupItemLabel = React.forwardRef<unknown, TagGroupItemLabelProp
|
|
|
118
117
|
const { children, className, ...nativeProps } = props;
|
|
119
118
|
return (
|
|
120
119
|
<text
|
|
121
|
-
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
120
|
+
{...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
|
|
122
121
|
className={clsx(classes.label, className)}
|
|
123
|
-
{...nativeProps}
|
|
124
122
|
>
|
|
125
123
|
{children}
|
|
126
124
|
</text>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type TextStyleProps,
|
|
13
13
|
} from "../../utils/styled";
|
|
14
14
|
import type { LynxStyledElementProps, LynxTextRef } from "../../types";
|
|
15
|
+
import { mergeProps } from "../../utils/merge-props";
|
|
15
16
|
|
|
16
17
|
function capitalize<T extends string>(value: T): Capitalize<T> {
|
|
17
18
|
return (value.charAt(0).toUpperCase() + value.slice(1)) as Capitalize<T>;
|
|
@@ -42,8 +43,7 @@ export const Text = React.forwardRef<unknown, TextProps>((props, ref) => {
|
|
|
42
43
|
|
|
43
44
|
return (
|
|
44
45
|
<text
|
|
45
|
-
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
46
|
-
{...nativeProps}
|
|
46
|
+
{...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
|
|
47
47
|
className={clsx(className)}
|
|
48
48
|
style={
|
|
49
49
|
{
|