@orioncactuscorp/ui 1.16.0 → 1.18.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/CHANGELOG.md +164 -0
- package/README.md +55 -14
- package/dist/components/ActionArea/ActionArea.css +1 -1
- package/dist/components/ActionArea/ActionArea.js +56 -55
- package/dist/components/BackgroundIconButton/BackgroundIconButton.css +1 -1
- package/dist/components/Badge/Badge.css +1 -1
- package/dist/components/Badge/Badge.js +45 -40
- package/dist/components/Badge/Badge.module.scss.js +9 -8
- package/dist/components/Fieldset/Fieldset.css +1 -1
- package/dist/components/Modal/Modal.css +1 -1
- package/dist/components/Modal/Modal.js +582 -563
- package/dist/components/Modal/Modal.module.scss.js +59 -57
- package/dist/components/Modal/blockSize.js +7 -0
- package/dist/components/Modal/cssTime.js +11 -0
- package/dist/components/Modal/fieldReveal.js +57 -0
- package/dist/components/Modal/headerTapScroll.js +10 -0
- package/dist/components/Modal/keyboardEditable.js +31 -0
- package/dist/components/Modal/keyboardInsetMemory.js +24 -0
- package/dist/components/Modal/keyboardSession.js +46 -73
- package/dist/components/Modal/modalResizeTarget.js +28 -0
- package/dist/components/Modal/modalScrollArbitration.js +69 -80
- package/dist/components/Modal/scrollportScroller.js +43 -0
- package/dist/components/Modal/tapCaret.js +32 -0
- package/dist/components/Modal/useBottomSheetIntrinsicHeight.js +58 -0
- package/dist/components/Modal/useFieldReveal.js +81 -0
- package/dist/components/Modal/useMeasuredElement.js +20 -0
- package/dist/components/Modal/useModalContentBlockTransition.js +128 -49
- package/dist/components/Modal/useModalContentSizeSignal.js +30 -0
- package/dist/components/Modal/useModalDrag.js +1136 -1056
- package/dist/components/Modal/useModalKeyboardAvoidance.js +200 -117
- package/dist/components/Modal/useModalViewportGeometry.js +35 -19
- package/dist/components/PositionSnap/policy.js +40 -43
- package/dist/components/internal/ModalPresentation.js +1 -1
- package/dist/styles.css +5 -5
- package/dist/ui/src/components/ActionArea/ActionArea.d.ts.map +1 -1
- package/dist/ui/src/components/Badge/Badge.d.ts.map +1 -1
- package/dist/ui/src/components/Badge/types.d.ts +1 -1
- package/dist/ui/src/components/Badge/types.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/Modal.d.ts +2 -2
- package/dist/ui/src/components/Modal/Modal.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/Modal.test.utils.d.ts +12 -0
- package/dist/ui/src/components/Modal/Modal.test.utils.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/blockSize.d.ts +2 -0
- package/dist/ui/src/components/Modal/blockSize.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/contexts.d.ts +6 -0
- package/dist/ui/src/components/Modal/contexts.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/cssTime.d.ts +4 -0
- package/dist/ui/src/components/Modal/cssTime.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/fieldReveal.d.ts +18 -0
- package/dist/ui/src/components/Modal/fieldReveal.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/headerTapScroll.d.ts +5 -0
- package/dist/ui/src/components/Modal/headerTapScroll.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/keyboardEditable.d.ts +6 -0
- package/dist/ui/src/components/Modal/keyboardEditable.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/keyboardInsetMemory.d.ts +5 -0
- package/dist/ui/src/components/Modal/keyboardInsetMemory.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/keyboardSession.d.ts +4 -11
- package/dist/ui/src/components/Modal/keyboardSession.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/modalResizeTarget.d.ts +12 -0
- package/dist/ui/src/components/Modal/modalResizeTarget.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/modalScrollArbitration.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/scrollportScroller.d.ts +20 -0
- package/dist/ui/src/components/Modal/scrollportScroller.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/tapCaret.d.ts +10 -0
- package/dist/ui/src/components/Modal/tapCaret.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/types.d.ts +6 -0
- package/dist/ui/src/components/Modal/types.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/useBottomSheetIntrinsicHeight.d.ts +28 -0
- package/dist/ui/src/components/Modal/useBottomSheetIntrinsicHeight.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/useFieldReveal.d.ts +28 -0
- package/dist/ui/src/components/Modal/useFieldReveal.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/{useElementSize.d.ts → useMeasuredElement.d.ts} +1 -1
- package/dist/ui/src/components/Modal/useMeasuredElement.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/useModalContentBlockTransition.d.ts +20 -1
- package/dist/ui/src/components/Modal/useModalContentBlockTransition.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/useModalContentSizeSignal.d.ts +22 -0
- package/dist/ui/src/components/Modal/useModalContentSizeSignal.d.ts.map +1 -0
- package/dist/ui/src/components/Modal/useModalDrag.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/useModalKeyboardAvoidance.d.ts +6 -1
- package/dist/ui/src/components/Modal/useModalKeyboardAvoidance.d.ts.map +1 -1
- package/dist/ui/src/components/Modal/useModalViewportGeometry.d.ts +1 -0
- package/dist/ui/src/components/Modal/useModalViewportGeometry.d.ts.map +1 -1
- package/dist/ui/src/components/PositionSnap/policy.d.ts.map +1 -1
- package/dist/ui/src/utils/gesture.d.ts +58 -0
- package/dist/ui/src/utils/gesture.d.ts.map +1 -0
- package/dist/utils/gesture.d.ts +2 -0
- package/dist/utils/gesture.js +103 -0
- package/docs/api-conventions.md +5 -0
- package/docs/gesture.md +64 -0
- package/docs/selector-contract.md +41 -10
- package/docs/spring.md +4 -0
- package/package.json +5 -1
- package/dist/components/Modal/useElementSize.js +0 -23
- package/dist/ui/src/components/Modal/useElementSize.d.ts.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface OcGestureDecelerationState {
|
|
2
|
+
/** Position in pixels. */
|
|
3
|
+
position: number;
|
|
4
|
+
/** Velocity in pixels per second. */
|
|
5
|
+
velocity: number;
|
|
6
|
+
}
|
|
7
|
+
export interface OcGestureDecelerationOptions {
|
|
8
|
+
/** Velocity retention per millisecond, strictly between 0 and 1. */
|
|
9
|
+
rate?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface OcGestureVelocitySample {
|
|
12
|
+
/** Monotonic time in milliseconds, in the same clock as read(now). */
|
|
13
|
+
time: number;
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
}
|
|
17
|
+
export interface OcGestureVelocity {
|
|
18
|
+
/** Pixels per second. */
|
|
19
|
+
x: number;
|
|
20
|
+
/** Pixels per second. */
|
|
21
|
+
y: number;
|
|
22
|
+
}
|
|
23
|
+
export interface OcGestureVelocityTrackerOptions {
|
|
24
|
+
windowMs?: number;
|
|
25
|
+
minimumSpanMs?: number;
|
|
26
|
+
/** Time since the last changed position before read returns zero. */
|
|
27
|
+
stopAfterMs?: number;
|
|
28
|
+
/** Per-axis speed limit in pixels per second. */
|
|
29
|
+
maxPxPerSecond?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface OcGestureVelocityTracker {
|
|
32
|
+
push: (sample: OcGestureVelocitySample) => void;
|
|
33
|
+
read: (now: number) => OcGestureVelocity;
|
|
34
|
+
clear: () => void;
|
|
35
|
+
}
|
|
36
|
+
declare function rubberBand(offset: number, dimension: number, resistance?: number): number;
|
|
37
|
+
declare function rubberBandClamp(value: number, min: number, max: number, dimension: number, resistance?: number): number;
|
|
38
|
+
declare function decelerate(state: OcGestureDecelerationState, elapsedMs: number, options?: OcGestureDecelerationOptions): OcGestureDecelerationState;
|
|
39
|
+
declare function projectDeceleration(velocity: number, options?: OcGestureDecelerationOptions): number;
|
|
40
|
+
declare function projectFling(position: number, velocity: number, options?: OcGestureDecelerationOptions): number;
|
|
41
|
+
declare function isDecelerationAtRest(velocity: number, threshold?: number): boolean;
|
|
42
|
+
declare function createVelocityTracker({ windowMs, minimumSpanMs, stopAfterMs, maxPxPerSecond, }?: OcGestureVelocityTrackerOptions): OcGestureVelocityTracker;
|
|
43
|
+
/** Gesture math uses px, px/s, and explicit millisecond timestamps; no DOM or React runtime. */
|
|
44
|
+
export declare const ocGesture: Readonly<{
|
|
45
|
+
rubberBand: typeof rubberBand;
|
|
46
|
+
rubberBandClamp: typeof rubberBandClamp;
|
|
47
|
+
decelerationRates: Readonly<{
|
|
48
|
+
normal: 0.998;
|
|
49
|
+
fast: 0.99;
|
|
50
|
+
}>;
|
|
51
|
+
decelerate: typeof decelerate;
|
|
52
|
+
projectDeceleration: typeof projectDeceleration;
|
|
53
|
+
projectFling: typeof projectFling;
|
|
54
|
+
isDecelerationAtRest: typeof isDecelerationAtRest;
|
|
55
|
+
createVelocityTracker: typeof createVelocityTracker;
|
|
56
|
+
}>;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=gesture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gesture.d.ts","sourceRoot":"","sources":["../../../../src/utils/gesture.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,yBAAyB;IACzB,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA8BD,iBAAS,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,SAAO,UAcvE;AAED,iBAAS,eAAe,CACtB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,UAAU,SAAO,UAalB;AAED,iBAAS,UAAU,CACjB,KAAK,EAAE,0BAA0B,EACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,4BAAiC,GACzC,0BAA0B,CAc5B;AAED,iBAAS,mBAAmB,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,4BAAiC,UAI3C;AAED,iBAAS,YAAY,CACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,4BAAiC,UAI3C;AAED,iBAAS,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAK,WAI7D;AAED,iBAAS,qBAAqB,CAAC,EAC7B,QAAc,EACd,aAAiB,EACjB,WAAiB,EACjB,cAAqB,GACtB,GAAE,+BAAoC,GAAG,wBAAwB,CAkDjE;AAED,gGAAgG;AAChG,eAAO,MAAM,SAAS;;;;;;;;;;;;EASpB,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
function r(t, e) {
|
|
2
|
+
if (!Number.isFinite(e)) throw new TypeError(`${t} must be finite.`);
|
|
3
|
+
return e;
|
|
4
|
+
}
|
|
5
|
+
function m(t, e) {
|
|
6
|
+
if (r(t, e), e < 0) throw new RangeError(`${t} must be non-negative.`);
|
|
7
|
+
return e;
|
|
8
|
+
}
|
|
9
|
+
function f(t, e) {
|
|
10
|
+
if (m(t, e), e === 0) throw new RangeError(`${t} must be positive.`);
|
|
11
|
+
return e;
|
|
12
|
+
}
|
|
13
|
+
const b = Object.freeze({ normal: 0.998, fast: 0.99 });
|
|
14
|
+
function g({
|
|
15
|
+
rate: t = b.normal
|
|
16
|
+
}) {
|
|
17
|
+
if (r("rate", t), t <= 0 || t >= 1)
|
|
18
|
+
throw new RangeError("rate must be between 0 and 1.");
|
|
19
|
+
return Math.log(t);
|
|
20
|
+
}
|
|
21
|
+
function y(t, e, o = 0.55) {
|
|
22
|
+
if (r("offset", t), m("dimension", e), f("resistance", o), t === 0 || e === 0) return 0;
|
|
23
|
+
const u = Math.abs(t), n = u * o, s = n <= e ? n / (1 + n / e) : e / (1 + e / u / o);
|
|
24
|
+
return Math.sign(t) * s;
|
|
25
|
+
}
|
|
26
|
+
function x(t, e, o, u, n = 0.55) {
|
|
27
|
+
if (r("value", t), r("min", e), r("max", o), m("dimension", u), f("resistance", n), e > o) throw new RangeError("min must not exceed max.");
|
|
28
|
+
const s = Math.min(Math.max(t, e), o);
|
|
29
|
+
return r(
|
|
30
|
+
"result",
|
|
31
|
+
s + y(t - s, u, n)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
function d(t, e, o = {}) {
|
|
35
|
+
r("position", t.position), r("velocity", t.velocity), m("elapsedMs", e);
|
|
36
|
+
const u = g(o), n = e * u;
|
|
37
|
+
return {
|
|
38
|
+
position: r(
|
|
39
|
+
"result.position",
|
|
40
|
+
t.position + t.velocity / 1e3 * (Math.expm1(n) / u)
|
|
41
|
+
),
|
|
42
|
+
velocity: t.velocity * Math.exp(n)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function p(t, e = {}) {
|
|
46
|
+
return r("velocity", t), r("result", -(t / 1e3) / g(e));
|
|
47
|
+
}
|
|
48
|
+
function M(t, e, o = {}) {
|
|
49
|
+
return r("position", t), r("result", t + p(e, o));
|
|
50
|
+
}
|
|
51
|
+
function R(t, e = 10) {
|
|
52
|
+
return r("velocity", t), f("threshold", e), Math.abs(t) < e;
|
|
53
|
+
}
|
|
54
|
+
function E({
|
|
55
|
+
windowMs: t = 100,
|
|
56
|
+
minimumSpanMs: e = 8,
|
|
57
|
+
stopAfterMs: o = 100,
|
|
58
|
+
maxPxPerSecond: u = 4e3
|
|
59
|
+
} = {}) {
|
|
60
|
+
if (f("windowMs", t), f("minimumSpanMs", e), f("stopAfterMs", o), f("maxPxPerSecond", u), e > t)
|
|
61
|
+
throw new RangeError("minimumSpanMs must not exceed windowMs.");
|
|
62
|
+
let n = [], s;
|
|
63
|
+
const h = (i) => Math.min(Math.max(i, -u), u);
|
|
64
|
+
return {
|
|
65
|
+
push(i) {
|
|
66
|
+
r("time", i.time), r("x", i.x), r("y", i.y);
|
|
67
|
+
const c = n.at(-1);
|
|
68
|
+
if (c && i.time < c.time)
|
|
69
|
+
throw new RangeError("Samples must be chronological.");
|
|
70
|
+
(!c || i.x !== c.x || i.y !== c.y) && (s = i.time), c?.time === i.time && n.pop(), n = n.filter((a) => a.time >= i.time - t), n.push({ ...i });
|
|
71
|
+
},
|
|
72
|
+
read(i) {
|
|
73
|
+
r("now", i);
|
|
74
|
+
const c = n.at(-1);
|
|
75
|
+
if (c && i < c.time)
|
|
76
|
+
throw new RangeError("now must not precede the latest sample.");
|
|
77
|
+
const a = n.find((w) => w.time >= i - t);
|
|
78
|
+
if (!a || !c || s === void 0 || i - s >= o || c.time - a.time < e)
|
|
79
|
+
return { x: 0, y: 0 };
|
|
80
|
+
const l = (c.time - a.time) / 1e3;
|
|
81
|
+
return {
|
|
82
|
+
x: h((c.x - a.x) / l),
|
|
83
|
+
y: h((c.y - a.y) / l)
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
clear() {
|
|
87
|
+
n = [], s = void 0;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const v = Object.freeze({
|
|
92
|
+
rubberBand: y,
|
|
93
|
+
rubberBandClamp: x,
|
|
94
|
+
decelerationRates: b,
|
|
95
|
+
decelerate: d,
|
|
96
|
+
projectDeceleration: p,
|
|
97
|
+
projectFling: M,
|
|
98
|
+
isDecelerationAtRest: R,
|
|
99
|
+
createVelocityTracker: E
|
|
100
|
+
});
|
|
101
|
+
export {
|
|
102
|
+
v as ocGesture
|
|
103
|
+
};
|
package/docs/api-conventions.md
CHANGED
|
@@ -86,6 +86,11 @@ named preset이 아니라 외부 문맥이나 직접 지정한 치수로 크기
|
|
|
86
86
|
`Badge`의 작은 preset도 `size='xsmall'`을 사용하므로 모든 named size가 이
|
|
87
87
|
표준 순서를 따릅니다.
|
|
88
88
|
|
|
89
|
+
`Badge`의 `variant='default'`는 소비자 커스터마이즈의 기준이 되는 canonical
|
|
90
|
+
기본 표현이며 `label-strong` 배경과 `background-normal-normal` 라벨 색을 사용합니다.
|
|
91
|
+
기존 `variant='normal'`은 `label-alternative` 라벨과 `fill-normal` 배경을 사용하는
|
|
92
|
+
레거시 표현으로 유지됩니다. 신규 코드는 `default`를 사용하세요.
|
|
93
|
+
|
|
89
94
|
`ProgressIndicator`는 선의 block size를 `small | medium | large`로 제공합니다.
|
|
90
95
|
기본 `small`은 모바일과 navigation chrome에 사용하고, `medium`과 `large`는
|
|
91
96
|
태블릿·데스크톱의 독립적인 작업 진행 표시에 사용합니다.
|
package/docs/gesture.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 제스처 계산 — ocGesture
|
|
2
|
+
|
|
3
|
+
`ocGesture`는 DOM·React·CSS·스케줄러에 의존하지 않는 제스처 계산 진입점입니다. 루트 export 대신 전용 경로로 가져옵니다. 런타임 named export는 `ocGesture` 하나이며 타입은 `OcGesture*` 이름으로 제공합니다.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { ocGesture } from '@orioncactuscorp/ui/utils/gesture';
|
|
7
|
+
|
|
8
|
+
const displayedX = ocGesture.rubberBandClamp(rawX, -200, 200, 100);
|
|
9
|
+
const tracker = ocGesture.createVelocityTracker();
|
|
10
|
+
tracker.push({ time: performance.now(), x: rawX, y: rawY });
|
|
11
|
+
const velocity = tracker.read(performance.now());
|
|
12
|
+
const next = ocGesture.decelerate(
|
|
13
|
+
{ position: displayedX, velocity: velocity.x },
|
|
14
|
+
elapsedMs,
|
|
15
|
+
{ rate: ocGesture.decelerationRates.fast },
|
|
16
|
+
);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 단위와 API
|
|
20
|
+
|
|
21
|
+
위치·dimension은 `px`, 속도는 **`px/s`**, 시간은 명시적인 `ms`입니다. 감속률은 매 밀리초의 속도 유지 비율입니다. 기존 spring에 속도를 전달할 때 추가로 1000을 곱하지 않습니다.
|
|
22
|
+
|
|
23
|
+
| API | 계약 |
|
|
24
|
+
| ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
25
|
+
| `rubberBand(offset, dimension, resistance = 0.55)` | 부호를 유지하는 저항. dimension은 완충 거리의 점근적 한도이며 0이면 결과 0 |
|
|
26
|
+
| `rubberBandClamp(value, min, max, dimension, resistance = 0.55)` | 범위 안은 그대로, 밖은 경계부터 저항 적용. min = max 허용 |
|
|
27
|
+
| `decelerationRates` | 읽기 전용 `{ normal: 0.998, fast: 0.99 }` |
|
|
28
|
+
| `decelerate(state, elapsedMs, { rate }?)` | 지수 감속의 연속 적분. 새 `{ position, velocity }` 반환 |
|
|
29
|
+
| `projectDeceleration(velocity, { rate }?)` | 같은 모델의 남은 이동 거리 |
|
|
30
|
+
| `projectFling(position, velocity, { rate }?)` | 현재 위치 + 남은 이동 거리 |
|
|
31
|
+
| `isDecelerationAtRest(velocity, threshold = 10)` | 절댓값이 threshold 미만이면 true. 최종 위치에 도달했다는 의미는 아님 |
|
|
32
|
+
| `createVelocityTracker(options?)` | `push(sample)`, `read(now)`, `clear()` 제공 |
|
|
33
|
+
|
|
34
|
+
감속 API 기본 rate는 `normal`입니다. 더 짧은 관성 이동이 필요한 이미지 뷰어에서는 `fast`를 명시할 수 있습니다. `Δx = (velocity / 1000) × expm1(elapsedMs × ln(rate)) / ln(rate)`로 계산하므로 경계 없는 적분은 프레임을 나누어도 같은 경로를 따릅니다. 투사 역시 이 연속 모델을 사용합니다.
|
|
35
|
+
|
|
36
|
+
모든 숫자는 유한해야 합니다. dimension과 elapsedMs는 0 이상, resistance와 정지 threshold는 0 초과, rate는 0 초과 1 미만, min은 max 이하입니다. 비유한 입력은 `TypeError`, 범위 위반은 `RangeError`이며 계산 결과가 표현 가능한 유한 범위를 넘으면 `TypeError`입니다. 내부 계산이 유한 정밀도로 수행되므로 극단적으로 작은 값은 0으로 반올림될 수 있습니다.
|
|
37
|
+
|
|
38
|
+
## 속도 추적
|
|
39
|
+
|
|
40
|
+
| 옵션 | 기본값 | 의미 |
|
|
41
|
+
| ---------------- | ------ | -------------------------------------------- |
|
|
42
|
+
| `windowMs` | 100 | read 시점부터 최근 샘플을 선택하는 창 |
|
|
43
|
+
| `minimumSpanMs` | 8 | 첫/마지막 샘플 사이 최소 간격. windowMs 이하 |
|
|
44
|
+
| `stopAfterMs` | 100 | 마지막 좌표 변경 이후 정지로 판단하는 시간 |
|
|
45
|
+
| `maxPxPerSecond` | 4000 | 축별 속도 상한 |
|
|
46
|
+
|
|
47
|
+
모든 옵션은 유한한 양수입니다. 최소 두 시각의 샘플이 필요합니다. 같은 시각의 샘플은 마지막 값으로 대체하고 역순 시각은 거부합니다. `read(now)`는 마지막 샘플보다 이른 시각을 거부합니다. timestamp에는 같은 단조 시계를 사용하세요. 샘플이 부족하거나 오래되었거나 stopAfterMs 이상 좌표 변경이 없으면 0을 반환합니다. 중복 좌표 push는 정지 타이머를 연장하지 않습니다. read는 상태를 변경하지 않습니다.
|
|
48
|
+
|
|
49
|
+
포인터 이동 속도와 화면에 표시된 콘텐츠 속도는 rubber band 구간에서 다릅니다. 어떤 좌표를 추적할지는 호출부가 선택합니다. 새 pointerdown과 pointercancel에서는 `clear()`를 호출하고, cancel을 정상 release로 처리하지 마세요. flick 임계값과 스냅 선택은 컴포넌트 정책입니다.
|
|
50
|
+
|
|
51
|
+
## 마찰과 spring 조합
|
|
52
|
+
|
|
53
|
+
자유 팬은 `decelerate`로 진행합니다. 고정된 스냅 목표나 경계 복귀에는 [spring API](./spring.md)를 사용합니다. spring은 초기 속도를 보존하지만 목표 거리와 설정에 따라 이후 가속할 수 있으므로, 자유 팬을 단순히 `projectFling` 목표로 spring 이동시키면 마찰 감속과 다른 경로가 됩니다.
|
|
54
|
+
|
|
55
|
+
이 API는 프레임 실행·경계 감지·바운스·중단을 소유하지 않습니다. 경계 있는 실행기를 구현할 때는 정확한 경계 도달 시각과 속도를 구한 후 남은 프레임 시간을 spring에 적용해야 합니다. 프레임 끝에서 경계를 발견하고 bounce를 시작하면 프레임 간격에 따라 경로가 달라집니다. 사용자 모션 설정과 입력 중단은 호출부가 처리합니다.
|
|
56
|
+
|
|
57
|
+
Modal과 PositionSnap은 같은 rubber band 계산을 사용합니다. Modal의 방향별 완충 한도와 기존 스냅·닫기 투사·속도 측정 정책은 유지됩니다. 이 유틸이 특정 OS의 모든 스크롤 동작을 재현한다는 보장은 없습니다.
|
|
58
|
+
|
|
59
|
+
## Migration Notes
|
|
60
|
+
|
|
61
|
+
- 기존 컴포넌트 소비자의 필수 변경은 없습니다.
|
|
62
|
+
- 로컬 구현을 교체할 때 기존 속도가 px/ms이면 입력에 1000을 곱하고 이후부터 px/s로 통일하세요.
|
|
63
|
+
- rate 인자는 `{ rate }` 객체이며 기본값은 `normal`입니다. 기존 fast 기반 뷰어는 명시적으로 `fast`를 지정하세요.
|
|
64
|
+
- React 훅이나 플링 애니메이터는 이번 API에 포함되지 않습니다.
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
| `Switch` | `--oc-switch-background-color` | `--oc-switch-color` | checked track, thumb |
|
|
47
47
|
| `BackgroundIconButton` | `--oc-background-icon-button-background-color` | `--oc-background-icon-button-color` | 모든 variant의 background, icon |
|
|
48
48
|
|
|
49
|
+
`BackgroundIconButton`의 disabled 상태는 불투명한 fill 레이어를 컴포넌트 루트 위에 덮어 그립니다. blend mode와 backdrop-filter가 비선형으로 합성되기 때문에, 장식 레이어를 그대로 둔 채 이 레이어의 `opacity`만 올려야 전환이 두 끝 상태의 선형 보간이 되어 중간에 튀지 않습니다. 이 fill 색은 `--oc-background-icon-button-disabled-background-color`로 재정의할 수 있고, 기본값은 `--oc-color-theme-interaction-disable`입니다. disabled에서는 이 레이어가 배경을 덮으므로 `--oc-background-icon-button-background-color` 값은 보이지 않습니다.
|
|
50
|
+
|
|
49
51
|
```css
|
|
50
52
|
.darkPrimaryControl {
|
|
51
53
|
--oc-radio-background-color: var(--oc-color-theme-label-strong);
|
|
@@ -54,6 +56,8 @@
|
|
|
54
56
|
}
|
|
55
57
|
```
|
|
56
58
|
|
|
59
|
+
`BackgroundIconButton`의 키보드 포커스 링은 본체보다 바깥으로 확장된 배경 크기와 `--oc-background-icon-button-radius`를 따릅니다. 공통 `--oc-focus-ring-width`, `--oc-focus-ring-offset`, `--oc-color-theme-focus-ring` 토큰으로 조정할 수 있습니다. 링은 배경의 clipping이나 Interaction의 opacity에 영향을 받지 않는 독립적인 장식 레이어이며, 버튼의 레이아웃과 터치 영역은 바꾸지 않습니다.
|
|
60
|
+
|
|
57
61
|
## Interaction 프리미티브
|
|
58
62
|
|
|
59
63
|
`Interaction`은 hover/press/focus 피드백을 그리는 시각 레이어입니다. 시각 pseudo는 passive이며 부모 컴포넌트가 자기 상태 selector로 Interaction의 opacity를 제어합니다. `self`가 아닌 Interaction은 자기 상태를 만들지 않지만, 선택적으로 확장된 투명 hit pseudo의 pointer event가 host로 버블링될 수 있습니다.
|
|
@@ -128,12 +132,35 @@
|
|
|
128
132
|
|
|
129
133
|
## Badge 계약
|
|
130
134
|
|
|
131
|
-
| Component | Root selector | Visual selectors
|
|
132
|
-
| --------- | --------------------------- |
|
|
133
|
-
| `Badge` | `data-oc-component="badge"` | `data-oc-variant="normal\|accent\|overlay"`, `data-oc-size="xsmall\|small"`, `data-oc-interactive="true"` | `content`
|
|
135
|
+
| Component | Root selector | Visual selectors | Stable parts |
|
|
136
|
+
| --------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
|
|
137
|
+
| `Badge` | `data-oc-component="badge"` | `data-oc-variant="default\|normal\|accent\|overlay"`, `data-oc-size="xsmall\|small"`, `data-oc-interactive="true"` | `content`, `surface`, `surface-default`, `surface-normal`, `surface-overlay` |
|
|
134
138
|
|
|
135
139
|
`Badge`의 작은 named size는 `data-oc-size="xsmall"`을 사용합니다. 이전
|
|
136
140
|
`data-oc-size="tiny"` 값은 major 변경으로 제거됐습니다.
|
|
141
|
+
`default`가 canonical 기본 variant이며, `normal`은 기존 소비자를 위한 호환
|
|
142
|
+
선택지입니다. variant를 생략하면 `data-oc-variant="default"`가 출력됩니다.
|
|
143
|
+
`default`는 `label-strong` 배경과 `background-normal-normal` 라벨 색을 사용하고,
|
|
144
|
+
`normal`은 기존 `label-alternative` 라벨과 `fill-normal` 배경을 유지합니다.
|
|
145
|
+
|
|
146
|
+
Badge의 `surface` part는 배경 레이어를 담당하며, `accent` 배경이 사라지고
|
|
147
|
+
`default` 또는 `overlay` 배경이 나타나는 전환을 별도 opacity 레이어로 처리합니다.
|
|
148
|
+
border는 다음 component contract 변수로 조정할 수 있습니다.
|
|
149
|
+
|
|
150
|
+
| Contract variable | Default | 용도 |
|
|
151
|
+
| ------------------------- | ------------- | ----------------- |
|
|
152
|
+
| `--oc-badge-border-width` | `1px` | inset border 두께 |
|
|
153
|
+
| `--oc-badge-border-color` | `transparent` | inset border 색상 |
|
|
154
|
+
|
|
155
|
+
border는 Badge의 기존 radius를 따르며 `oc-border` 기반의 고정 all/inset stroke로
|
|
156
|
+
그려집니다. 색상만 지정하면 기본 1px border가 표시되고, width를 함께 override할
|
|
157
|
+
수 있습니다. 예를 들어 다음처럼 색상만 지정할 수 있습니다.
|
|
158
|
+
|
|
159
|
+
```scss
|
|
160
|
+
.badgeWithBorder {
|
|
161
|
+
--oc-badge-border-color: var(--oc-color-theme-line-normal-normal);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
137
164
|
|
|
138
165
|
## Field 레이아웃 계약
|
|
139
166
|
|
|
@@ -289,15 +316,17 @@ Tab content는 inline padding 없이 배치되고 배경색이 transparent인 se
|
|
|
289
316
|
|
|
290
317
|
`ActionAreaLayout`은 스크롤 가능한 body와 고정 footer slot 사이의 scroll 경계를 소유합니다.
|
|
291
318
|
|
|
292
|
-
| Component | Root selector | Visual selectors
|
|
293
|
-
| ------------------------- | ----------------------------------------------- |
|
|
294
|
-
| `ActionArea` | `data-oc-component="action-area"` | `data-oc-variant`, `data-oc-background="true"` | `actions`, `caption`, `extra-slot`, `compact-row`, `compact-slot` |
|
|
295
|
-
| `ActionAreaLayout` | `data-oc-component="action-area-layout"` | `data-oc-scrollable="true\|false"`
|
|
296
|
-
| `ActionAreaLayout.Body` | `data-oc-component="action-area-layout-body"` | -
|
|
297
|
-
| `ActionAreaLayout.Footer` | `data-oc-component="action-area-layout-footer"` | -
|
|
319
|
+
| Component | Root selector | Visual selectors | Stable parts |
|
|
320
|
+
| ------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
321
|
+
| `ActionArea` | `data-oc-component="action-area"` | `data-oc-variant`, `data-oc-background="true"`, `data-oc-empty="true"` | `actions`, `caption`, `extra-slot`, `compact-row`, `compact-slot` |
|
|
322
|
+
| `ActionAreaLayout` | `data-oc-component="action-area-layout"` | `data-oc-scrollable="true\|false"` | - |
|
|
323
|
+
| `ActionAreaLayout.Body` | `data-oc-component="action-area-layout-body"` | - | `body` |
|
|
324
|
+
| `ActionAreaLayout.Footer` | `data-oc-component="action-area-layout-footer"` | - | `footer` |
|
|
298
325
|
|
|
299
326
|
- `data-oc-scrollable="true"`는 body에 보이는 scrollport 밖 overflow가 있다는 뜻입니다. 이 상태에서 직속 footer `ActionArea`는 block-end padding을 유지하고 `--oc-action-area-padding-block-start: 0`을 받으며, 대응하는 block-start 간격은 body에 예약됩니다.
|
|
300
327
|
- `ActionAreaLayout.ActionArea background="auto"`는 scroll 상태를 자식 `ActionArea`의 background 계약에 매핑합니다: body가 스크롤 가능하고 바닥에 닿지 않은 동안만 `data-oc-background="true"`가 방출됩니다. `data-oc-background`는 시각 gradient/background 상태이며 body 예약의 근거로 사용하지 마세요.
|
|
328
|
+
- 렌더링할 액션, caption, extraContent가 없는 `ActionArea`는 `data-oc-empty="true"`를 방출하고 자체 padding과 background를 접습니다. `ModalFooter`나 `FloatingWindowFooter`의 직속 빈 `ActionArea`는 footer 예약을 `0`으로 만들어 body는 기본 하단 여백만 유지합니다. depth navigation처럼 root에서는 액션이 없고 다음 depth부터 버튼이 생기는 구성에서 Footer를 계속 마운트해 둘 때 사용합니다. 여백이 필요하면 빈 `ActionArea` 대신 명시적 spacer를 두세요.
|
|
329
|
+
- `ModalBody` 또는 같은 presentation frame을 사용하는 `FloatingWindowBody`의 마지막 직속 자식이 `ActionArea`이면 owner surface가 inline padding과 block-end padding을 `0`, desktop action group의 max width를 `none`으로 자동 보정합니다. 본문 padding과 중복되지 않도록 하기 위한 기본값이며, `ActionArea`에 명시한 `--oc-action-area-*` 변수는 이 보정보다 우선합니다. bottom placement의 safe-area 및 footer 예약은 Modal surface/body가 계속 소유합니다.
|
|
301
330
|
|
|
302
331
|
## FloatingWindow 계약
|
|
303
332
|
|
|
@@ -369,6 +398,8 @@ Modal의 기본 `initialFocus="auto"`는 `ModalHeader`의 visible title을 `tabI
|
|
|
369
398
|
- `ModalContent`의 `className`은 motion layer, visual surface, bottom fill 세 레이어에 적용됩니다 — 공개 `--oc-modal-*` 변수 override가 layout 계산까지 도달하게 하기 위함입니다. `style`은 visual surface에 적용되며, `style`의 CSS custom property는 motion/bottom fill 레이어로도 전달됩니다.
|
|
370
399
|
- `ModalHeader bottomContent`는 기본 header row 아래 `data-oc-part="header-bottom"`에 보조 chrome을 렌더링합니다. Modal은 이 slot을 header 높이에 포함하고 `--oc-modal-container-padding-block-start`를 현재 size의 `--oc-modal-container-padding-block`으로 자동 설정해 body와 scroll 시작 간격을 예약합니다. 명시적인 `ModalContent style` 변수는 이 기본값을 override할 수 있습니다.
|
|
371
400
|
- `ModalHeader bottomContent`의 직계 `ProgressIndicator`는 edge-attached navigation chrome으로 취급해 `--oc-progress-indicator-radius: 0`을 자동 적용합니다. 별도 wrapper 없이 slot에 직접 배치하는 구성이 canonical usage입니다.
|
|
401
|
+
- `ModalHeader handle`은 `data-oc-part="handle-area"` 안에 32×4px bar `data-oc-part="handle"`과 Interaction을 렌더링합니다. drag가 활성화되면(`drag='handle'` 또는 `drag='content'`) handle-area는 `data-oc-draggable="true"`가 되어 두 모드에서 공통 pointer hit 영역이 됩니다. fine pointer에서는 surface 좌우 끝까지 닿는 16px 상단 strip, coarse pointer에서는 중앙 72×44px pad입니다. fine pointer의 full-width strip은 header control과 겹치지 않도록 header content의 상단 padding을 strip 높이(16px) 이상으로 보정하며, coarse pointer의 중앙 pad에는 이 보정을 적용하지 않습니다. hover 가능 기기에서 strip에 hover하면 bar가 제자리에서 1.1배(35.2×4.4px)로 커지고 Interaction hover가 켜지며, 누르고 있는 동안에는 drag hook이 handle-area에 `data-oc-state="pressed"`를 내보내 확대, Interaction active, `grabbing` cursor를 release까지 유지합니다. release 시 pointer가 area 위에 남아 있으면 hook이 `data-oc-state="hover"`를 내보내 브라우저의 `:hover` 재평가가 늦어지는 동안(WebKit) 확대 상태를 이어 주고, pointer가 area를 실제로 벗어나면 지웁니다. 확대는 `expand` intent의 smooth spring이며 reduced-motion에서는 scale 없이 tint만 남습니다. `drag='content'`는 handle-area와 header 전체를 같은 chrome drag arbitration으로 처리하고, `drag='handle'`는 handle-area에서만 drag를 시작합니다. 시각 커스터마이즈는 bar 요소(`background-color`, 크기)를 대상으로 하세요. `ModalNavigationSection`의 handle은 navigation row 전체가 drag 영역이므로 handle-area 없이 bar만 렌더링합니다.
|
|
402
|
+
- `ModalHeader`의 자체 영역(title, 빈 공간, handle-area)을 탭하면 body가 sheet 모션 spring으로 맨 위로 스크롤됩니다. iOS status bar 탭이 페이지를 맨 위로 보내는 것과 같은 보조 제스처로, 모달이 페이지 스크롤을 잠근 동안 그 역할을 이어받습니다. 제외 기준은 drag 시작을 막는 기준과 같습니다. 닫기·뒤로 가기 버튼, `trailingContent`/`bottomContent` 안의 컨트롤(button, link, input, `role="button"`·`option`·`radio` 등)과 `data-oc-modal-no-drag`로 표시한 콘텐츠(하위 요소 포함)에서 온 클릭은 제외되고, 소비자 `onClick`이 `preventDefault`하면 건너뜁니다. drag 뒤에 따라오는 click은 drag hook이 취소하므로 동작하지 않으며, body가 이미 맨 위면 아무 일도 하지 않습니다. reduced-motion에서는 즉시 이동합니다. 접근성 트리에는 아무 것도 추가하지 않습니다(header는 여전히 role 없는 chrome이며 스크롤 자체가 기본 수단입니다).
|
|
372
403
|
- `data-starting-style`/`data-ending-style`은 Base UI가 motion layer에 방출합니다.
|
|
373
404
|
- `data-oc-modal-backdrop="hidden"`으로 정착하면 backdrop 레이어는 렌더링되지 않습니다. 전환 중 잠시 남는 exiting backdrop 요소에 layout/hit-testing/커스터마이즈를 의존하지 마세요.
|
|
374
405
|
- `backdropFrom` snap 임계 아래에 정착한 bottom sheet는 backdrop 레이어에 `data-oc-modal-backdrop-passthrough="true"`를 방출합니다. 이 상태는 non-modal이며 배경이 상호작용 가능합니다. attribute는 드래그 프레임 단위가 아니라 정착(rest) 시점에 바뀝니다.
|
|
@@ -379,7 +410,7 @@ Modal의 기본 `initialFocus="auto"`는 `ModalHeader`의 visible title을 `tabI
|
|
|
379
410
|
- `ModalBody layout="fill"`은 header/footer/content padding 예약을 유지한 채 body content slot을 iframe·map·viewer 같은 embedded 표면용 fill container로 바꿉니다.
|
|
380
411
|
- size별 공개 변수: `--oc-modal-small-width`/`--oc-modal-medium-width`/`--oc-modal-large-width`와 `--oc-modal-{size}-padding-*`이 내부 `--oc-modal-container-padding-*` 계약으로 매핑됩니다. header/body/footer padding은 기본적으로 container padding을 상속하며, `--oc-modal-header-padding-*`/`--oc-modal-footer-padding-*`로 slot별 예외를 둘 수 있습니다. edge 정렬 chrome control용으로 `--oc-modal-header-edge-offset-inline`이 있습니다.
|
|
381
412
|
- 닫기 시도가 차단되어 피드백 중일 때 motion layer에 `data-oc-modal-feedback="reject"`가 방출됩니다. transform을 직접 덮지 말고 `--oc-modal-reject-distance` 같은 contract 변수를 사용하세요.
|
|
382
|
-
- bottom placement에서 소프트 키보드 회피 세션이 활성일 때 viewport 레이어(`data-oc-part="viewport"`)에 `data-oc-modal-keyboard-avoiding="true"`가 방출됩니다. 키보드 geometry 추격 transition의 게이트로 쓰이는 내부 지향 상태이며, 소비자는 이 attribute의 방출 타이밍(세션 시작/해제 시점의 지연 포함)에 의존하지 않는 것이 좋습니다.
|
|
413
|
+
- bottom placement에서 소프트 키보드 회피 세션이 활성일 때 viewport 레이어(`data-oc-part="viewport"`)에 `data-oc-modal-keyboard-avoiding="true"`가, 포커스가 떠나 키보드가 닫히는 동안에는 `data-oc-modal-keyboard-closing="true"`가 함께 방출됩니다. 키보드 geometry 추격 transition의 게이트로 쓰이는 내부 지향 상태이며, 소비자는 이 attribute의 방출 타이밍(세션 시작/해제 시점의 지연 포함)에 의존하지 않는 것이 좋습니다.
|
|
383
414
|
- `ModalNavigationSection`은 body content가 아니라 Modal chrome입니다. 루트는 `data-oc-state="open|closed"`, toggle row는 `data-oc-component="modal-navigation"` + `data-oc-part="navigation"` + `aria-expanded`/`aria-controls`, indicator는 `data-oc-part="indicator"`/`indicator-frame`, panel은 `data-oc-component="modal-navigation-panel"`(collapsed 동안 `aria-hidden`/`inert`), panel content는 `data-oc-part="panel-inner"`를 노출합니다.
|
|
384
415
|
|
|
385
416
|
## ScrollArea scrollbar 계약
|
package/docs/spring.md
CHANGED
|
@@ -380,3 +380,7 @@ runtime animator의 핵심 contract는 velocity continuity입니다. gesture 도
|
|
|
380
380
|
- gesture, drag, interrupt가 중요한 런타임 상호작용은 `createSpringAnimator` 사용
|
|
381
381
|
- React state target을 따라가야 하면 `useSpringTarget` 사용
|
|
382
382
|
- React component에서 spring 값을 직접 제어해야 하면 `useSpringValue` 사용
|
|
383
|
+
|
|
384
|
+
## 자유 플링
|
|
385
|
+
|
|
386
|
+
자유 팬의 단조 감속에는 [ocGesture](./gesture.md)의 마찰 적분을 사용합니다. spring은 초기 속도를 이어받지만 목표 거리와 설정에 따라 이후 가속할 수 있습니다. 예상 정지 위치로 spring 이동하는 것은 자유 감속과 다른 경로입니다. 두 API의 속도 단위는 px/s입니다.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orioncactuscorp/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "orioncactus UI foundations and core primitives",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
"./react/motion": {
|
|
70
70
|
"types": "./dist/react/motion.d.ts",
|
|
71
71
|
"import": "./dist/react/motion.js"
|
|
72
|
+
},
|
|
73
|
+
"./utils/gesture": {
|
|
74
|
+
"types": "./dist/utils/gesture.d.ts",
|
|
75
|
+
"import": "./dist/utils/gesture.js"
|
|
72
76
|
}
|
|
73
77
|
},
|
|
74
78
|
"peerDependencies": {
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { useState as o, useCallback as c, useLayoutEffect as a } from "react";
|
|
2
|
-
function m() {
|
|
3
|
-
const [e, s] = o(null), [u, r] = o(0), t = c((n) => {
|
|
4
|
-
if (!n) {
|
|
5
|
-
r(0);
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
r(n.getBoundingClientRect().height);
|
|
9
|
-
}, []);
|
|
10
|
-
return a(() => {
|
|
11
|
-
if (!e) return;
|
|
12
|
-
const n = window.requestAnimationFrame(() => t(e));
|
|
13
|
-
if (typeof ResizeObserver > "u")
|
|
14
|
-
return () => window.cancelAnimationFrame(n);
|
|
15
|
-
const i = new ResizeObserver(() => t(e));
|
|
16
|
-
return i.observe(e), () => {
|
|
17
|
-
window.cancelAnimationFrame(n), i.disconnect();
|
|
18
|
-
};
|
|
19
|
-
}, [t, e]), { node: e, setNode: s, height: u };
|
|
20
|
-
}
|
|
21
|
-
export {
|
|
22
|
-
m as useMeasuredElement
|
|
23
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useElementSize.d.ts","sourceRoot":"","sources":["../../../../../src/components/Modal/useElementSize.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW;;;;EAgCvD"}
|