Skip to content

Commit bc91f55

Browse files
committed
feat(lynx): use Element animate for scale feedback
1 parent 88e3ec6 commit bc91f55

17 files changed

Lines changed: 397 additions & 56 deletions

File tree

.changeset/bright-lynxes-press.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
Lynx 컴포넌트에 Scale Feedback을 추가합니다.
77

8-
- `useScaleFeedback` 훅으로 Self·Content Scale Feedback을 구성할 수 있습니다.
8+
- `ScaleFeedback` 유틸과 `useScaleFeedback` 훅으로 Self·Content Scale Feedback을 구성할 수 있습니다.
9+
- Rootage의 pressed scale duration과 easing을 사용해 Main Thread의 `Element.animate()`로 반응합니다.
910
- Action Button, Chip, Callout, Tabs, Accordion, Checkbox, Radio Group, Switch에 Scale Feedback을 적용합니다.
1011
- 최소 지원 버전은 Lynx Engine 3.9입니다.

bun.lock

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/content/lynx/components/concepts/scale-feedback.mdx

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ compatibility:
99

1010
SEED의 Scale Feedback은 누르는 동안 요소를 살짝 줄여 입력이 도달했음을 즉시 전달합니다. 고정된 배율을 쓰지 않고 렌더된 크기에서 배율을 계산하므로 작은 아이콘 버튼과 화면 폭을 채우는 요소가 비슷한 눌림 거리로 반응합니다.
1111

12-
Lynx 구현은 `@seed-design/lynx-react``useScaleFeedback`을 사용합니다.
12+
Lynx 구현은 `@seed-design/lynx-react``ScaleFeedback``useScaleFeedback`을 사용합니다. 단일 요소에 Self Scale을 적용할 때는 유틸 컴포넌트, trigger와 target을 나눠야 할 때는 훅을 사용하세요.
1313

1414
## Requirements
1515

16-
SEED가 지원하는 최소 버전은 **Lynx Engine 3.9**입니다. Main Thread Script와 `useMainThreadRef`더 낮은 버전에도 존재하지만, SEED는 Engine 3.9의 이벤트·Element API와 `GlobalProps.motion` 계약을 기준으로 구현하고 검증합니다.
16+
SEED가 지원하는 최소 버전은 **Lynx Engine 3.9**입니다. `Element.animate()` 자체는 더 낮은 버전에도 있지만, SEED는 Engine 3.9의 Main Thread Script와 GlobalProps 계약을 기준으로 구현하고 검증합니다.
1717

1818
```package-install
1919
@seed-design/lynx-react @seed-design/lynx-css
@@ -30,7 +30,27 @@ scale = (basis - 2) / basis
3030

3131
축소량, 폭 보정값, 최소 기준 길이의 의미는 [Scale Foundation](/foundations/feedback/scale)에서 확인할 수 있습니다.
3232

33-
## Usage
33+
## Self Scale with ScaleFeedback
34+
35+
단일 요소에 Self Scale을 적용할 때는 `ScaleFeedback`으로 감싸세요. 별도 wrapper를 렌더하지 않고 child에 필요한 Main Thread props를 합성합니다.
36+
37+
```tsx
38+
import { ScaleFeedback } from "@seed-design/lynx-react";
39+
40+
function Pressable() {
41+
return (
42+
<ScaleFeedback>
43+
<view>
44+
<text>눌러 보세요</text>
45+
</view>
46+
</ScaleFeedback>
47+
);
48+
}
49+
```
50+
51+
child는 하나의 Lynx element여야 하며, 사용자 컴포넌트라면 `main-thread:ref`와 Main Thread 이벤트 props를 실제 native element까지 전달해야 합니다. child에 같은 이벤트나 ref가 이미 있으면 child 로직을 먼저 실행한 뒤 SEED 로직을 실행합니다. ref cleanup도 함께 보존합니다.
52+
53+
## Self and Content with useScaleFeedback
3454

3555
훅은 터치를 받는 요소와 실제로 축소할 요소의 props를 나누어 반환합니다.
3656

@@ -58,7 +78,7 @@ function Pressable() {
5878
Main Thread의 실제 입력 지연과 transform 결과는 QR 코드 탭에서 Lynx Explorer로 확인하세요. WebLynx 미리보기는 구조와 기본 상호작용을 확인하는 용도입니다.
5979
</Callout>
6080

61-
## Self and Content
81+
## Choosing Self or Content
6282

6383
두 방식은 공식이 아니라 **target 위치**가 다릅니다.
6484

@@ -87,13 +107,26 @@ Scale Feedback은 하나의 touch 이벤트를 다음처럼 나눠 처리합니
87107

88108
| 실행 위치 | 책임 |
89109
|---|---|
90-
| Main Thread | layout 측정, touchstart의 transform 적용, touchend·touchcancel의 reset |
91-
| Background Thread | React `pressed` state, pressed color recipe, tap callback과 비즈니스 로직 |
110+
| Main Thread | layout 측정, touch 이벤트 처리, `Element.animate()` 실행·중단 |
111+
| Background Thread | `onPressStart`·`onPressEnd`·`onPressCancel` callback, tap과 비즈니스 로직 |
92112

93-
Main Thread 핸들러가 transform을 즉시 적용한`runOnBackground()` pressed 상태 갱신을 전달합니다. Main Thread 함수 안에서는 React state, 네트워크 요청, NativeModule을 직접 사용하지 않습니다.
113+
Main Thread 핸들러가 scale을 즉시 시작한필요한 callback만 `runOnBackground()`로 전달합니다. Main Thread 함수 안에서는 React state, 네트워크 요청, NativeModule을 직접 사용하지 않습니다.
94114

95115
`usePressTap`과 직접 조합할 때는 `bindtouchstart`, `bindtouchend`, `bindtouchcancel``onPressStart`, `onPressEnd`, `onPressCancel`로 전달합니다. 동일 touch 이벤트에 Main/Background 핸들러를 따로 등록하지 않습니다.
96116

117+
## Animation and Rootage values
118+
119+
Scale은 CSS `transition` 문자열을 inline style에 쓰지 않고 `Element.animate()`로 실행합니다. 따라서 target에 이미 선언된 background-color, color, border-color transition을 덮어쓰지 않습니다.
120+
121+
|| Rootage source | 현재 값 |
122+
|---|---|---|
123+
| Duration | `$duration.pressed-scale` | `150ms` |
124+
| Easing | `$timing-function.pressed-scale` | `cubic-bezier(0, 0, 0.15, 1)` |
125+
126+
빌드 시 `@seed-design/lynx-css/scale-feedback` 런타임 모듈을 생성하고, 훅은 이 값을 Main Thread에서 사용합니다. 값을 훅에 복사하지 않으므로 Rootage가 바뀌면 생성 결과를 통해 React와 Lynx가 함께 갱신됩니다.
127+
128+
touchend나 touchcancel이 이전 애니메이션 도중 발생하면 computed transform을 읽고 기존 `Animation`을 취소한 뒤 현재 지점에서 `scale(1)`로 돌아갑니다.
129+
97130
## Reduced Motion
98131

99132
`useScaleFeedback``@lynx-js/react``useGlobalProps()`에서 `motion`을 읽습니다.
@@ -117,6 +150,8 @@ GlobalProps 객체 자체가 없을 때도 기본 동작을 사용합니다. `mo
117150

118151
## API
119152

153+
<react-type-table path="../packages/lynx-react/src/components/ScaleFeedback/ScaleFeedback.tsx" name="ScaleFeedbackProps" />
154+
120155
<react-type-table path="../packages/lynx-react/src/hooks/useScaleFeedback.ts" name="UseScaleFeedbackOptions" />
121156

122157
<react-type-table path="../packages/lynx-react/src/hooks/useScaleFeedback.ts" name="UseScaleFeedbackReturn" />

docs/examples/lynx/scale-feedback/self-and-content.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
import "./styles";
22

33
import { root } from "@lynx-js/react";
4-
import { useScaleFeedback, useSeedClassName } from "@seed-design/lynx-react";
4+
import { ScaleFeedback, useScaleFeedback, useSeedClassName } from "@seed-design/lynx-react";
55

66
function Root() {
77
const seedClassName = useSeedClassName({ colorMode: "system" });
8-
const self = useScaleFeedback();
98
const content = useScaleFeedback();
109

1110
return (
1211
<page className={seedClassName}>
1312
<view className="scale-feedback-example">
1413
<text className="scale-feedback-example__label">Self Scale</text>
15-
<view
16-
className="scale-feedback-example__self"
17-
{...self.scaleFeedbackTriggerProps}
18-
{...self.scaleFeedbackTargetProps}
19-
>
20-
<text className="scale-feedback-example__self-text">표면 전체가 줄어듭니다</text>
21-
</view>
14+
<ScaleFeedback>
15+
<view className="scale-feedback-example__self">
16+
<text className="scale-feedback-example__self-text">표면 전체가 줄어듭니다</text>
17+
</view>
18+
</ScaleFeedback>
2219

2320
<text className="scale-feedback-example__label">Content Scale</text>
2421
<view
2522
className="scale-feedback-example__content-root"
2623
{...content.scaleFeedbackTriggerProps}
2724
>
28-
<view
29-
className="scale-feedback-example__content"
30-
{...content.scaleFeedbackTargetProps}
31-
>
25+
<view className="scale-feedback-example__content" {...content.scaleFeedbackTargetProps}>
3226
<text className="scale-feedback-example__content-text">
3327
배경은 그대로, 콘텐츠만 줄어듭니다
3428
</text>

docs/public/__docs__/index.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,12 @@
22082208
}
22092209
]
22102210
},
2211+
{
2212+
"id": "scale-feedback",
2213+
"title": "Scale Feedback",
2214+
"description": "Lynx에서 Main Thread 기반의 SEED Scale Feedback을 적용하는 방법을 알아봅니다.",
2215+
"docUrl": "/lynx/components/concepts/scale-feedback"
2216+
},
22112217
{
22122218
"id": "segmented-control",
22132219
"title": "Segmented Control",

packages/lynx-css/package.json

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/lynx-css/scale-feedback/index.d.ts

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/lynx-css/scale-feedback/index.mjs

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/lynx-css/scripts/generate-scale-feedback.mjs

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/lynx-react/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@
3333
},
3434
"peerDependencies": {
3535
"@lynx-js/react": ">=0.117.0",
36-
"@lynx-js/types": ">=3.7.0",
37-
"@seed-design/lynx-css": "0.0.0 || >=0.8.0 <1.0.0"
36+
"@lynx-js/types": ">=3.9.0",
37+
"@seed-design/lynx-css": "0.0.0 || >=0.10.0 <1.0.0"
3838
},
3939
"devDependencies": {
4040
"@lynx-js/react": "^0.117.0",
41-
"@lynx-js/types": "^3.7.0",
41+
"@lynx-js/types": "^3.9.0",
4242
"@seed-design/lynx-css": "0.9.2",
4343
"@testing-library/jest-dom": "^6.9.1",
4444
"jsdom": "^29.0.2",

0 commit comments

Comments
 (0)