@openiot-devteam/layout 0.3.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/README.md +147 -0
- package/dist/dim-bridge.d.mts +21 -0
- package/dist/dim-bridge.d.mts.map +1 -0
- package/dist/dim-bridge.mjs +22 -0
- package/dist/dim-bridge.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +6 -0
- package/dist/native/FitLayout.d.mts +26 -0
- package/dist/native/FitLayout.d.mts.map +1 -0
- package/dist/native/FitLayout.mjs +80 -0
- package/dist/native/FitLayout.mjs.map +1 -0
- package/dist/native/ScreenLayout.d.mts +42 -0
- package/dist/native/ScreenLayout.d.mts.map +1 -0
- package/dist/native/ScreenLayout.mjs +90 -0
- package/dist/native/ScreenLayout.mjs.map +1 -0
- package/dist/native/overlays.d.mts +43 -0
- package/dist/native/overlays.d.mts.map +1 -0
- package/dist/native/overlays.mjs +170 -0
- package/dist/native/overlays.mjs.map +1 -0
- package/dist/native.d.mts +7 -0
- package/dist/native.mjs +6 -0
- package/dist/tokens.d.mts +43 -0
- package/dist/tokens.d.mts.map +1 -0
- package/dist/tokens.mjs +50 -0
- package/dist/tokens.mjs.map +1 -0
- package/dist/types.d.mts +91 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/web/FitLayout.d.mts +55 -0
- package/dist/web/FitLayout.d.mts.map +1 -0
- package/dist/web/FitLayout.mjs +111 -0
- package/dist/web/FitLayout.mjs.map +1 -0
- package/dist/web/ScreenLayout.d.mts +61 -0
- package/dist/web/ScreenLayout.d.mts.map +1 -0
- package/dist/web/ScreenLayout.mjs +118 -0
- package/dist/web/ScreenLayout.mjs.map +1 -0
- package/dist/web/overlays.d.mts +58 -0
- package/dist/web/overlays.d.mts.map +1 -0
- package/dist/web/overlays.mjs +173 -0
- package/dist/web/overlays.mjs.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# @openiot-devteam/layout
|
|
2
|
+
|
|
3
|
+
모바일 화면 골격을 웹(Next)과 React Native(Expo)에서 **같은 API**로 쓰는 패키지입니다.
|
|
4
|
+
|
|
5
|
+
사내 앱 6곳에 흩어져 있던 레이아웃 14종을 4개로 정리한 결과물입니다. 가르는 축은
|
|
6
|
+
**본문이 스크롤되는가** 하나이고, 나머지 차이는 전부 prop 으로 내려갑니다.
|
|
7
|
+
|
|
8
|
+
| 컴포넌트 | 대체하는 것 |
|
|
9
|
+
| -------------- | ---------------------------------------------------------------------------- |
|
|
10
|
+
| `ScreenLayout` | `BasicLayout` · `TabsLayout` · `ContentLayout` 의 하단 CTA · full-bleed 조립 |
|
|
11
|
+
| `FitLayout` | `DeviceConnectLayout` · `DeviceControlLayout` |
|
|
12
|
+
| `BottomSheet` | `BottomSheetCalendar` · `BottomSheetTimePicker` · `BottomSheetBanner` |
|
|
13
|
+
| `Dialog` | `StandardModal` · `AppDialog` |
|
|
14
|
+
|
|
15
|
+
## 설치
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i @openiot-devteam/layout
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
RN 앱은 `react-native-safe-area-context` 가 필요합니다 (사내 앱 5곳 모두 이미 설치돼 있습니다).
|
|
22
|
+
웹 전용 프로젝트는 추가 설치가 없습니다.
|
|
23
|
+
|
|
24
|
+
## 쓰는 법
|
|
25
|
+
|
|
26
|
+
import 경로는 웹과 RN 이 완전히 같습니다. `package.json` 의 `react-native` export 조건 덕분에
|
|
27
|
+
Metro 는 네이티브 구현을, 그 외 번들러는 웹 구현을 자동으로 고릅니다.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { ScreenLayout, FitLayout, Stack, BottomSheet, Dialog } from '@openiot-devteam/layout'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### ScreenLayout — 스크롤형
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
// 폼 · CTA
|
|
37
|
+
<ScreenLayout header={<Header title="방문차량 등록" onBackPress={back} />} footer={<Button>등록하기</Button>}>
|
|
38
|
+
<Stack>
|
|
39
|
+
<VehicleCard />
|
|
40
|
+
<DateCard />
|
|
41
|
+
</Stack>
|
|
42
|
+
</ScreenLayout>
|
|
43
|
+
|
|
44
|
+
// 탭 하위 화면 — 탭바가 safe-area 를 직접 처리하므로 safeBottom 을 끕니다
|
|
45
|
+
<ScreenLayout header={<Header leftIcon={<Logo />} />} footer={<TabBar />} safeBottom={false}>
|
|
46
|
+
…
|
|
47
|
+
</ScreenLayout>
|
|
48
|
+
|
|
49
|
+
// 헤더 2단 (구 smart-key full-bleed)
|
|
50
|
+
<ScreenLayout header={<><LogoHeader /><TitleHeader /></>}>…</ScreenLayout>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
하단 CTA 를 그릴 수 있는 곳은 `footer` **하나뿐**입니다. 예전에는 `BasicLayout` 과
|
|
54
|
+
`ContentLayout` 양쪽에서 그릴 수 있어 같은 화면에 CTA 가 두 번 잡히는 일이 있었습니다.
|
|
55
|
+
|
|
56
|
+
### FitLayout — 고정형 (스크롤 없음)
|
|
57
|
+
|
|
58
|
+
단계가 바뀌어도 버튼 위치가 흔들리지 않아야 하는 화면에 씁니다. 내용 길이가 가변이면
|
|
59
|
+
`ScreenLayout` 을 쓰세요.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// 기기 연결 마법사
|
|
63
|
+
<FitLayout
|
|
64
|
+
header={<Header onBackPress={back} />}
|
|
65
|
+
regions={[
|
|
66
|
+
{ height: 160, node: <Guide /> },
|
|
67
|
+
{ height: 328, node: <DeviceImage /> },
|
|
68
|
+
{ height: 'fill', node: <Info /> },
|
|
69
|
+
]}
|
|
70
|
+
action={<Button>기기 연결하기</Button>}
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
// 기기 제어 — 마지막 구획을 시트로
|
|
74
|
+
<FitLayout
|
|
75
|
+
header={<Header title="거실 공기청정기" onBackPress={back} />}
|
|
76
|
+
regions={[
|
|
77
|
+
{ height: 336, node: <Summary /> },
|
|
78
|
+
{ height: 'fill', variant: 'sheet', node: <Controls /> },
|
|
79
|
+
]}
|
|
80
|
+
sheetBackground="#292E36"
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 오버레이
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<BottomSheet open={open} onOpenChange={setOpen} label="날짜 선택">
|
|
88
|
+
<Calendar />
|
|
89
|
+
</BottomSheet>
|
|
90
|
+
|
|
91
|
+
<Dialog
|
|
92
|
+
open={open}
|
|
93
|
+
onOpenChange={setOpen}
|
|
94
|
+
title="기기 연결을 해제할까요?"
|
|
95
|
+
description="해제하면 기록이 더 이상 수집되지 않아요"
|
|
96
|
+
cancel={{ label: '취소' }}
|
|
97
|
+
confirm={{ label: '해제', tone: 'danger', onPress: disconnect }}
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`BottomSheet` 는 `side` 를 열지 않습니다. 실사용이 bottom 하나뿐인데 4방향을 열어두면
|
|
102
|
+
쓰이지 않을 조합까지 유지보수해야 하기 때문입니다.
|
|
103
|
+
|
|
104
|
+
### 웹뷰 앱의 딤
|
|
105
|
+
|
|
106
|
+
웹이 직접 딤을 그리면 웹뷰 영역 안에만 칠해져 상태바와 홈 인디케이터가 밝게 남습니다.
|
|
107
|
+
진입점에서 한 번 등록해 두면 `BottomSheet` · `Dialog` 가 알아서 신호를 올립니다.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { setDimHandler } from '@openiot-devteam/layout'
|
|
111
|
+
|
|
112
|
+
setDimHandler((visible) => postToRN({ type: 'DIALOG_DIM', payload: { visible } }))
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
등록하지 않으면 아무 일도 하지 않으므로 일반 브라우저에서도 그대로 동작합니다.
|
|
116
|
+
오버레이가 중첩돼도 마지막 하나가 닫힐 때만 딤이 내려갑니다.
|
|
117
|
+
|
|
118
|
+
## 스타일 정책
|
|
119
|
+
|
|
120
|
+
구조(높이 · 여백 · flex)는 **인라인 스타일과 `StyleSheet`** 로 넣습니다. Tailwind 클래스를
|
|
121
|
+
내보내지 않는 이유는, 소비 프로젝트가 이 패키지를 Tailwind content 범위에 넣지 않으면
|
|
122
|
+
클래스가 CSS 로 생성되지 않아 레이아웃이 조용히 무너지기 때문입니다. RN 쪽도 같은 이유로
|
|
123
|
+
NativeWind 를 쓰지 않아, NativeWind 를 설정하지 않은 앱(`openiot-203-app` ·
|
|
124
|
+
`203-karking-guest-app`)에서도 그대로 동작합니다.
|
|
125
|
+
|
|
126
|
+
색·타이포 같은 표현은 이 패키지가 건드리지 않습니다. `className`(웹)과 `style`(양쪽)이
|
|
127
|
+
그대로 전달되니 앱의 테마를 얹으세요.
|
|
128
|
+
|
|
129
|
+
한 가지 주의 — 구조 값은 인라인이라 클래스로 덮이지 않습니다. 여백을 바꾸고 싶으면
|
|
130
|
+
클래스가 아니라 prop 을 쓰세요.
|
|
131
|
+
|
|
132
|
+
## 토큰
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { LAYOUT } from '@openiot-devteam/layout/tokens'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
플랫폼 의존이 없는 순수 상수라 RN·웹·빌드 스크립트 어디서나 import 할 수 있습니다.
|
|
139
|
+
|
|
140
|
+
| 값 | 용도 |
|
|
141
|
+
| --------------------- | ------------------------ |
|
|
142
|
+
| `maxWidth` 428 | 모바일 콘텐츠 최대 폭 |
|
|
143
|
+
| `header.minHeight` 40 | 헤더 최소 높이 |
|
|
144
|
+
| `content` 20/24/32/48 | 본문 px / pt / pb / gap |
|
|
145
|
+
| `footer.height` 96 | 하단 CTA 영역 |
|
|
146
|
+
| `tabBar` 60 / 68 | 웹 고정 / RN + safe-area |
|
|
147
|
+
| `stackGap` 16 | 섹션 묶음 간격 |
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/dim-bridge.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 웹뷰 앱 전용 — 오버레이가 열릴 때 네이티브에 딤을 요청한다.
|
|
4
|
+
*
|
|
5
|
+
* 웹이 직접 딤을 그리면 웹뷰 영역 안에만 칠해져서 상태바와 홈 인디케이터가 밝게 남는다.
|
|
6
|
+
* 그래서 실제 딤은 RN 이 전체 화면에 그리고, 웹은 신호만 보낸다.
|
|
7
|
+
*
|
|
8
|
+
* 앱 진입점에서 한 번 등록해 두면 BottomSheet · Dialog 가 알아서 호출하므로
|
|
9
|
+
* 사용처에서는 신경 쓸 일이 없다. 등록하지 않으면 아무 일도 하지 않는다(브라우저에서 그대로 동작).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // 웹뷰로 띄우는 앱의 진입점에서
|
|
14
|
+
* setDimHandler((visible) => postToRN({ type: 'DIALOG_DIM', payload: { visible } }))
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
type DimHandler = (visible: boolean) => void;
|
|
18
|
+
declare function setDimHandler(fn: DimHandler | null): void;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { setDimHandler };
|
|
21
|
+
//# sourceMappingURL=dim-bridge.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dim-bridge.d.mts","names":[],"sources":["../src/dim-bridge.ts"],"mappings":";;;;;;AAemC;AAMnC;;;;AAAmD;;;;;KAN9C,UAAA,IAAc,OAAgB;AAAA,iBAMnB,aAAA,CAAc,EAAqB,EAAjB,UAAU"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/dim-bridge.ts
|
|
2
|
+
let handler = null;
|
|
3
|
+
/** 동시에 열린 오버레이 수 — 중첩되어도 마지막 하나가 닫힐 때만 딤을 내린다. */
|
|
4
|
+
let openCount = 0;
|
|
5
|
+
function setDimHandler(fn) {
|
|
6
|
+
handler = fn;
|
|
7
|
+
}
|
|
8
|
+
/** @internal 오버레이가 열릴 때 호출. */
|
|
9
|
+
function acquireDim() {
|
|
10
|
+
openCount += 1;
|
|
11
|
+
if (openCount === 1) handler?.(true);
|
|
12
|
+
}
|
|
13
|
+
/** @internal 오버레이가 닫힐 때 호출. */
|
|
14
|
+
function releaseDim() {
|
|
15
|
+
if (openCount === 0) return;
|
|
16
|
+
openCount -= 1;
|
|
17
|
+
if (openCount === 0) handler?.(false);
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { acquireDim, releaseDim, setDimHandler };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=dim-bridge.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dim-bridge.mjs","names":[],"sources":["../src/dim-bridge.ts"],"sourcesContent":["/**\n * 웹뷰 앱 전용 — 오버레이가 열릴 때 네이티브에 딤을 요청한다.\n *\n * 웹이 직접 딤을 그리면 웹뷰 영역 안에만 칠해져서 상태바와 홈 인디케이터가 밝게 남는다.\n * 그래서 실제 딤은 RN 이 전체 화면에 그리고, 웹은 신호만 보낸다.\n *\n * 앱 진입점에서 한 번 등록해 두면 BottomSheet · Dialog 가 알아서 호출하므로\n * 사용처에서는 신경 쓸 일이 없다. 등록하지 않으면 아무 일도 하지 않는다(브라우저에서 그대로 동작).\n *\n * @example\n * ```ts\n * // 웹뷰로 띄우는 앱의 진입점에서\n * setDimHandler((visible) => postToRN({ type: 'DIALOG_DIM', payload: { visible } }))\n * ```\n */\ntype DimHandler = (visible: boolean) => void\n\nlet handler: DimHandler | null = null\n/** 동시에 열린 오버레이 수 — 중첩되어도 마지막 하나가 닫힐 때만 딤을 내린다. */\nlet openCount = 0\n\nexport function setDimHandler(fn: DimHandler | null): void {\n handler = fn\n}\n\n/** @internal 오버레이가 열릴 때 호출. */\nexport function acquireDim(): void {\n openCount += 1\n if (openCount === 1) handler?.(true)\n}\n\n/** @internal 오버레이가 닫힐 때 호출. */\nexport function releaseDim(): void {\n if (openCount === 0) return\n openCount -= 1\n if (openCount === 0) handler?.(false)\n}\n"],"mappings":";AAiBA,IAAI,UAA6B;;AAEjC,IAAI,YAAY;AAEhB,SAAgB,cAAc,IAA6B;CACzD,UAAU;AACZ;;AAGA,SAAgB,aAAmB;CACjC,aAAa;CACb,IAAI,cAAc,GAAG,UAAU,IAAI;AACrC;;AAGA,SAAgB,aAAmB;CACjC,IAAI,cAAc,GAAG;CACrB,aAAa;CACb,IAAI,cAAc,GAAG,UAAU,KAAK;AACtC"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BottomSheetBaseProps, DialogBaseProps, FitLayoutBaseProps, FitRegion, OverlayBaseProps, ScreenLayoutBaseProps } from "./types.mjs";
|
|
2
|
+
import { ScreenLayout, ScreenLayoutProps, Stack, StackProps } from "./web/ScreenLayout.mjs";
|
|
3
|
+
import { FitLayout, FitLayoutProps } from "./web/FitLayout.mjs";
|
|
4
|
+
import { BottomSheet, BottomSheetProps, Dialog, DialogProps } from "./web/overlays.mjs";
|
|
5
|
+
import { LAYOUT, LayoutTokens } from "./tokens.mjs";
|
|
6
|
+
import { setDimHandler } from "./dim-bridge.mjs";
|
|
7
|
+
export { BottomSheet, type BottomSheetBaseProps, type BottomSheetProps, Dialog, type DialogBaseProps, type DialogProps, FitLayout, type FitLayoutBaseProps, type FitLayoutProps, type FitRegion, LAYOUT, type LayoutTokens, type OverlayBaseProps, ScreenLayout, type ScreenLayoutBaseProps, type ScreenLayoutProps, Stack, type StackProps, setDimHandler };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LAYOUT } from "./tokens.mjs";
|
|
2
|
+
import { ScreenLayout, Stack } from "./web/ScreenLayout.mjs";
|
|
3
|
+
import { FitLayout } from "./web/FitLayout.mjs";
|
|
4
|
+
import { setDimHandler } from "./dim-bridge.mjs";
|
|
5
|
+
import { BottomSheet, Dialog } from "./web/overlays.mjs";
|
|
6
|
+
export { BottomSheet, Dialog, FitLayout, LAYOUT, ScreenLayout, Stack, setDimHandler };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FitLayoutBaseProps } from "../types.mjs";
|
|
2
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
//#region src/native/FitLayout.d.ts
|
|
5
|
+
interface FitLayoutProps extends FitLayoutBaseProps {
|
|
6
|
+
style?: StyleProp<ViewStyle>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 고정형 화면 골격 (RN) — 웹의 `FitLayout` 과 같은 prop 계약.
|
|
10
|
+
*
|
|
11
|
+
* 스크롤 없이 구획을 배분한다. 구 `DeviceConnectLayout` · `DeviceControlLayout` 대체.
|
|
12
|
+
*
|
|
13
|
+
* `'sheet'` 구획이 마지막이면 하단 safe-area 는 시트 내용이 직접 처리하는 편이 자연스러워
|
|
14
|
+
* `action` 이 없을 때는 레이아웃이 하단 여백을 넣지 않는다.
|
|
15
|
+
*/
|
|
16
|
+
declare function FitLayout({
|
|
17
|
+
header,
|
|
18
|
+
regions,
|
|
19
|
+
action,
|
|
20
|
+
sheetBackground,
|
|
21
|
+
safeBottom,
|
|
22
|
+
style
|
|
23
|
+
}: FitLayoutProps): import("react").JSX.Element;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { FitLayout, FitLayoutProps };
|
|
26
|
+
//# sourceMappingURL=FitLayout.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FitLayout.d.mts","names":[],"sources":["../../src/native/FitLayout.tsx"],"mappings":";;;;UAKiB,cAAA,SAAuB,kBAAA;EACtC,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;;;;;;;;iBA0BJ,SAAA;EACd,MAAA;EACA,OAAA;EACA,MAAA;EACA,eAAA;EACA,UAAA;EACA;AAAA,GACC,cAAA,mBAAc,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { LAYOUT } from "../tokens.mjs";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { StyleSheet, View } from "react-native";
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
5
|
+
//#region src/native/FitLayout.tsx
|
|
6
|
+
function regionStyle(region, sheetBackground) {
|
|
7
|
+
const base = region.height === "fill" ? {
|
|
8
|
+
flex: 1,
|
|
9
|
+
width: "100%"
|
|
10
|
+
} : {
|
|
11
|
+
height: region.height,
|
|
12
|
+
width: "100%"
|
|
13
|
+
};
|
|
14
|
+
if (region.variant !== "sheet") return base;
|
|
15
|
+
return {
|
|
16
|
+
...base,
|
|
17
|
+
borderTopLeftRadius: LAYOUT.fitSheetRadius,
|
|
18
|
+
borderTopRightRadius: LAYOUT.fitSheetRadius,
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
...sheetBackground ? { backgroundColor: sheetBackground } : null
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 고정형 화면 골격 (RN) — 웹의 `FitLayout` 과 같은 prop 계약.
|
|
25
|
+
*
|
|
26
|
+
* 스크롤 없이 구획을 배분한다. 구 `DeviceConnectLayout` · `DeviceControlLayout` 대체.
|
|
27
|
+
*
|
|
28
|
+
* `'sheet'` 구획이 마지막이면 하단 safe-area 는 시트 내용이 직접 처리하는 편이 자연스러워
|
|
29
|
+
* `action` 이 없을 때는 레이아웃이 하단 여백을 넣지 않는다.
|
|
30
|
+
*/
|
|
31
|
+
function FitLayout({ header, regions, action, sheetBackground, safeBottom = true, style }) {
|
|
32
|
+
const insets = useSafeAreaInsets();
|
|
33
|
+
const lastIsSheet = regions[regions.length - 1]?.variant === "sheet";
|
|
34
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
35
|
+
style: [
|
|
36
|
+
styles.root,
|
|
37
|
+
{
|
|
38
|
+
paddingTop: insets.top,
|
|
39
|
+
paddingBottom: action === void 0 && safeBottom && !lastIsSheet ? insets.bottom : 0
|
|
40
|
+
},
|
|
41
|
+
style
|
|
42
|
+
],
|
|
43
|
+
children: [
|
|
44
|
+
header !== void 0 && /* @__PURE__ */ jsx(View, {
|
|
45
|
+
style: styles.header,
|
|
46
|
+
children: header
|
|
47
|
+
}),
|
|
48
|
+
regions.map((region, i) => /* @__PURE__ */ jsx(View, {
|
|
49
|
+
style: regionStyle(region, sheetBackground),
|
|
50
|
+
children: region.node
|
|
51
|
+
}, region.key ?? i)),
|
|
52
|
+
action !== void 0 && /* @__PURE__ */ jsx(View, {
|
|
53
|
+
style: [styles.action, { paddingBottom: safeBottom ? LAYOUT.footer.paddingY + insets.bottom : LAYOUT.footer.paddingY }],
|
|
54
|
+
children: action
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const styles = StyleSheet.create({
|
|
60
|
+
root: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
width: "100%",
|
|
63
|
+
flexDirection: "column"
|
|
64
|
+
},
|
|
65
|
+
header: {
|
|
66
|
+
width: "100%",
|
|
67
|
+
minHeight: LAYOUT.header.minHeight,
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
justifyContent: "center"
|
|
70
|
+
},
|
|
71
|
+
action: {
|
|
72
|
+
width: "100%",
|
|
73
|
+
paddingHorizontal: LAYOUT.footer.paddingX,
|
|
74
|
+
paddingTop: LAYOUT.footer.paddingY
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
//#endregion
|
|
78
|
+
export { FitLayout };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=FitLayout.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FitLayout.mjs","names":[],"sources":["../../src/native/FitLayout.tsx"],"sourcesContent":["import { StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { LAYOUT } from '../tokens.js'\nimport type { FitLayoutBaseProps, FitRegion } from '../types.js'\n\nexport interface FitLayoutProps extends FitLayoutBaseProps {\n style?: StyleProp<ViewStyle>\n}\n\nfunction regionStyle(region: FitRegion, sheetBackground?: string): StyleProp<ViewStyle> {\n const base: ViewStyle =\n region.height === 'fill' ? { flex: 1, width: '100%' } : { height: region.height, width: '100%' }\n\n if (region.variant !== 'sheet') return base\n\n return {\n ...base,\n borderTopLeftRadius: LAYOUT.fitSheetRadius,\n borderTopRightRadius: LAYOUT.fitSheetRadius,\n overflow: 'hidden',\n ...(sheetBackground ? { backgroundColor: sheetBackground } : null),\n }\n}\n\n/**\n * 고정형 화면 골격 (RN) — 웹의 `FitLayout` 과 같은 prop 계약.\n *\n * 스크롤 없이 구획을 배분한다. 구 `DeviceConnectLayout` · `DeviceControlLayout` 대체.\n *\n * `'sheet'` 구획이 마지막이면 하단 safe-area 는 시트 내용이 직접 처리하는 편이 자연스러워\n * `action` 이 없을 때는 레이아웃이 하단 여백을 넣지 않는다.\n */\nexport function FitLayout({\n header,\n regions,\n action,\n sheetBackground,\n safeBottom = true,\n style,\n}: FitLayoutProps) {\n const insets = useSafeAreaInsets()\n const lastIsSheet = regions[regions.length - 1]?.variant === 'sheet'\n\n return (\n <View\n style={[\n styles.root,\n {\n paddingTop: insets.top,\n paddingBottom: action === undefined && safeBottom && !lastIsSheet ? insets.bottom : 0,\n },\n style,\n ]}\n >\n {header !== undefined && <View style={styles.header}>{header}</View>}\n\n {regions.map((region, i) => (\n <View key={region.key ?? i} style={regionStyle(region, sheetBackground)}>\n {region.node}\n </View>\n ))}\n\n {action !== undefined && (\n <View\n style={[\n styles.action,\n {\n paddingBottom: safeBottom\n ? LAYOUT.footer.paddingY + insets.bottom\n : LAYOUT.footer.paddingY,\n },\n ]}\n >\n {action}\n </View>\n )}\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n root: { flex: 1, width: '100%', flexDirection: 'column' },\n header: {\n width: '100%',\n minHeight: LAYOUT.header.minHeight,\n flexDirection: 'column',\n justifyContent: 'center',\n },\n action: {\n width: '100%',\n paddingHorizontal: LAYOUT.footer.paddingX,\n paddingTop: LAYOUT.footer.paddingY,\n },\n})\n"],"mappings":";;;;;AASA,SAAS,YAAY,QAAmB,iBAAgD;CACtF,MAAM,OACJ,OAAO,WAAW,SAAS;EAAE,MAAM;EAAG,OAAO;CAAO,IAAI;EAAE,QAAQ,OAAO;EAAQ,OAAO;CAAO;CAEjG,IAAI,OAAO,YAAY,SAAS,OAAO;CAEvC,OAAO;EACL,GAAG;EACH,qBAAqB,OAAO;EAC5B,sBAAsB,OAAO;EAC7B,UAAU;EACV,GAAI,kBAAkB,EAAE,iBAAiB,gBAAgB,IAAI;CAC/D;AACF;;;;;;;;;AAUA,SAAgB,UAAU,EACxB,QACA,SACA,QACA,iBACA,aAAa,MACb,SACiB;CACjB,MAAM,SAAS,kBAAkB;CACjC,MAAM,cAAc,QAAQ,QAAQ,SAAS,EAAE,EAAE,YAAY;CAE7D,OACE,qBAAC,MAAD;EACE,OAAO;GACL,OAAO;GACP;IACE,YAAY,OAAO;IACnB,eAAe,WAAW,KAAA,KAAa,cAAc,CAAC,cAAc,OAAO,SAAS;GACtF;GACA;EACF;YARF;GAUG,WAAW,KAAA,KAAa,oBAAC,MAAD;IAAM,OAAO,OAAO;cAAS;GAAa,CAAA;GAElE,QAAQ,KAAK,QAAQ,MACpB,oBAAC,MAAD;IAA4B,OAAO,YAAY,QAAQ,eAAe;cACnE,OAAO;GACJ,GAFK,OAAO,OAAO,CAEnB,CACP;GAEA,WAAW,KAAA,KACV,oBAAC,MAAD;IACE,OAAO,CACL,OAAO,QACP,EACE,eAAe,aACX,OAAO,OAAO,WAAW,OAAO,SAChC,OAAO,OAAO,SACpB,CACF;cAEC;GACG,CAAA;EAEJ;;AAEV;AAEA,MAAM,SAAS,WAAW,OAAO;CAC/B,MAAM;EAAE,MAAM;EAAG,OAAO;EAAQ,eAAe;CAAS;CACxD,QAAQ;EACN,OAAO;EACP,WAAW,OAAO,OAAO;EACzB,eAAe;EACf,gBAAgB;CAClB;CACA,QAAQ;EACN,OAAO;EACP,mBAAmB,OAAO,OAAO;EACjC,YAAY,OAAO,OAAO;CAC5B;AACF,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ScreenLayoutBaseProps } from "../types.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
4
|
+
|
|
5
|
+
//#region src/native/ScreenLayout.d.ts
|
|
6
|
+
interface ScreenLayoutProps extends ScreenLayoutBaseProps {
|
|
7
|
+
style?: StyleProp<ViewStyle>;
|
|
8
|
+
/** 본문 스크롤을 끄고 싶을 때 (기본 true). */
|
|
9
|
+
scrollable?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 스크롤형 화면 골격 (RN) — 웹의 `ScreenLayout` 과 같은 prop 계약.
|
|
13
|
+
*
|
|
14
|
+
* 상단 safe-area 는 이 레이아웃이 직접 padding 으로 처리한다. `SafeAreaView` 를 쓰지 않는
|
|
15
|
+
* 이유는 하단 inset 을 `footer` 유무에 따라 다르게 줘야 하기 때문이다.
|
|
16
|
+
*
|
|
17
|
+
* NativeWind 없이 `StyleSheet` 만 쓰므로 NativeWind 를 설정하지 않은 앱
|
|
18
|
+
* (openiot-203-app · 203-karking-guest-app)에서도 그대로 동작한다.
|
|
19
|
+
*/
|
|
20
|
+
declare function ScreenLayout({
|
|
21
|
+
header,
|
|
22
|
+
children,
|
|
23
|
+
footer,
|
|
24
|
+
banner,
|
|
25
|
+
safeBottom,
|
|
26
|
+
scrollable,
|
|
27
|
+
style
|
|
28
|
+
}: ScreenLayoutProps): import("react").JSX.Element;
|
|
29
|
+
interface StackProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
gap?: number;
|
|
32
|
+
style?: StyleProp<ViewStyle>;
|
|
33
|
+
}
|
|
34
|
+
/** 섹션을 일정 간격으로 쌓는 유틸 (구 `ContentLayout`). */
|
|
35
|
+
declare function Stack({
|
|
36
|
+
children,
|
|
37
|
+
gap,
|
|
38
|
+
style
|
|
39
|
+
}: StackProps): import("react").JSX.Element;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ScreenLayout, ScreenLayoutProps, Stack, StackProps };
|
|
42
|
+
//# sourceMappingURL=ScreenLayout.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenLayout.d.mts","names":[],"sources":["../../src/native/ScreenLayout.tsx"],"mappings":";;;;;UAMiB,iBAAA,SAA0B,qBAAA;EACzC,KAAA,GAAQ,SAAA,CAAU,SAAA;EADH;EAGf,UAAA;AAAA;;;;;;;;;;iBAYc,YAAA;EACd,MAAA;EACA,QAAA;EACA,MAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA;AAAA,GACC,iBAAA,mBAAiB,GAAA,CAAA,OAAA;AAAA,UAiDH,UAAA;EACf,QAAA,EAAU,SAAA;EACV,GAAA;EACA,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;iBAIJ,KAAA;EAAQ,QAAA;EAAU,GAAA;EAAuB;AAAA,GAAS,UAAA,mBAAU,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { LAYOUT } from "../tokens.mjs";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ScrollView, StyleSheet, View } from "react-native";
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
5
|
+
//#region src/native/ScreenLayout.tsx
|
|
6
|
+
/**
|
|
7
|
+
* 스크롤형 화면 골격 (RN) — 웹의 `ScreenLayout` 과 같은 prop 계약.
|
|
8
|
+
*
|
|
9
|
+
* 상단 safe-area 는 이 레이아웃이 직접 padding 으로 처리한다. `SafeAreaView` 를 쓰지 않는
|
|
10
|
+
* 이유는 하단 inset 을 `footer` 유무에 따라 다르게 줘야 하기 때문이다.
|
|
11
|
+
*
|
|
12
|
+
* NativeWind 없이 `StyleSheet` 만 쓰므로 NativeWind 를 설정하지 않은 앱
|
|
13
|
+
* (openiot-203-app · 203-karking-guest-app)에서도 그대로 동작한다.
|
|
14
|
+
*/
|
|
15
|
+
function ScreenLayout({ header, children, footer, banner, safeBottom = true, scrollable = true, style }) {
|
|
16
|
+
const insets = useSafeAreaInsets();
|
|
17
|
+
const contentPadding = {
|
|
18
|
+
paddingHorizontal: LAYOUT.content.paddingX,
|
|
19
|
+
paddingTop: LAYOUT.content.paddingTop,
|
|
20
|
+
paddingBottom: footer === void 0 && safeBottom ? LAYOUT.content.paddingBottom + insets.bottom : LAYOUT.content.paddingBottom,
|
|
21
|
+
gap: LAYOUT.content.gap
|
|
22
|
+
};
|
|
23
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
24
|
+
style: [
|
|
25
|
+
styles.root,
|
|
26
|
+
{ paddingTop: insets.top },
|
|
27
|
+
style
|
|
28
|
+
],
|
|
29
|
+
children: [
|
|
30
|
+
header !== void 0 && /* @__PURE__ */ jsx(View, {
|
|
31
|
+
style: styles.header,
|
|
32
|
+
children: header
|
|
33
|
+
}),
|
|
34
|
+
scrollable ? /* @__PURE__ */ jsx(ScrollView, {
|
|
35
|
+
style: styles.flex,
|
|
36
|
+
contentContainerStyle: contentPadding,
|
|
37
|
+
showsVerticalScrollIndicator: false,
|
|
38
|
+
children
|
|
39
|
+
}) : /* @__PURE__ */ jsx(View, {
|
|
40
|
+
style: [styles.flex, contentPadding],
|
|
41
|
+
children
|
|
42
|
+
}),
|
|
43
|
+
footer !== void 0 && /* @__PURE__ */ jsx(View, {
|
|
44
|
+
style: [styles.footer, { paddingBottom: safeBottom ? LAYOUT.footer.paddingY + insets.bottom : LAYOUT.footer.paddingY }],
|
|
45
|
+
children: footer
|
|
46
|
+
}),
|
|
47
|
+
banner !== void 0 && /* @__PURE__ */ jsx(View, {
|
|
48
|
+
style: styles.banner,
|
|
49
|
+
children: banner
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** 섹션을 일정 간격으로 쌓는 유틸 (구 `ContentLayout`). */
|
|
55
|
+
function Stack({ children, gap = LAYOUT.stackGap, style }) {
|
|
56
|
+
return /* @__PURE__ */ jsx(View, {
|
|
57
|
+
style: [{
|
|
58
|
+
flexDirection: "column",
|
|
59
|
+
gap
|
|
60
|
+
}, style],
|
|
61
|
+
children
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const styles = StyleSheet.create({
|
|
65
|
+
root: {
|
|
66
|
+
flex: 1,
|
|
67
|
+
width: "100%",
|
|
68
|
+
flexDirection: "column"
|
|
69
|
+
},
|
|
70
|
+
flex: {
|
|
71
|
+
flex: 1,
|
|
72
|
+
width: "100%"
|
|
73
|
+
},
|
|
74
|
+
header: {
|
|
75
|
+
width: "100%",
|
|
76
|
+
minHeight: LAYOUT.header.minHeight,
|
|
77
|
+
flexDirection: "column",
|
|
78
|
+
justifyContent: "center"
|
|
79
|
+
},
|
|
80
|
+
footer: {
|
|
81
|
+
width: "100%",
|
|
82
|
+
paddingHorizontal: LAYOUT.footer.paddingX,
|
|
83
|
+
paddingTop: LAYOUT.footer.paddingY
|
|
84
|
+
},
|
|
85
|
+
banner: { width: "100%" }
|
|
86
|
+
});
|
|
87
|
+
//#endregion
|
|
88
|
+
export { ScreenLayout, Stack };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=ScreenLayout.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenLayout.mjs","names":[],"sources":["../../src/native/ScreenLayout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { ScrollView, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { LAYOUT } from '../tokens.js'\nimport type { ScreenLayoutBaseProps } from '../types.js'\n\nexport interface ScreenLayoutProps extends ScreenLayoutBaseProps {\n style?: StyleProp<ViewStyle>\n /** 본문 스크롤을 끄고 싶을 때 (기본 true). */\n scrollable?: boolean\n}\n\n/**\n * 스크롤형 화면 골격 (RN) — 웹의 `ScreenLayout` 과 같은 prop 계약.\n *\n * 상단 safe-area 는 이 레이아웃이 직접 padding 으로 처리한다. `SafeAreaView` 를 쓰지 않는\n * 이유는 하단 inset 을 `footer` 유무에 따라 다르게 줘야 하기 때문이다.\n *\n * NativeWind 없이 `StyleSheet` 만 쓰므로 NativeWind 를 설정하지 않은 앱\n * (openiot-203-app · 203-karking-guest-app)에서도 그대로 동작한다.\n */\nexport function ScreenLayout({\n header,\n children,\n footer,\n banner,\n safeBottom = true,\n scrollable = true,\n style,\n}: ScreenLayoutProps) {\n const insets = useSafeAreaInsets()\n\n const contentPadding = {\n paddingHorizontal: LAYOUT.content.paddingX,\n paddingTop: LAYOUT.content.paddingTop,\n paddingBottom:\n footer === undefined && safeBottom\n ? LAYOUT.content.paddingBottom + insets.bottom\n : LAYOUT.content.paddingBottom,\n gap: LAYOUT.content.gap,\n }\n\n return (\n <View style={[styles.root, { paddingTop: insets.top }, style]}>\n {header !== undefined && <View style={styles.header}>{header}</View>}\n\n {scrollable ? (\n <ScrollView\n style={styles.flex}\n contentContainerStyle={contentPadding}\n showsVerticalScrollIndicator={false}\n >\n {children}\n </ScrollView>\n ) : (\n <View style={[styles.flex, contentPadding]}>{children}</View>\n )}\n\n {footer !== undefined && (\n <View\n style={[\n styles.footer,\n {\n paddingBottom: safeBottom\n ? LAYOUT.footer.paddingY + insets.bottom\n : LAYOUT.footer.paddingY,\n },\n ]}\n >\n {footer}\n </View>\n )}\n\n {banner !== undefined && <View style={styles.banner}>{banner}</View>}\n </View>\n )\n}\n\nexport interface StackProps {\n children: ReactNode\n gap?: number\n style?: StyleProp<ViewStyle>\n}\n\n/** 섹션을 일정 간격으로 쌓는 유틸 (구 `ContentLayout`). */\nexport function Stack({ children, gap = LAYOUT.stackGap, style }: StackProps) {\n return <View style={[{ flexDirection: 'column', gap }, style]}>{children}</View>\n}\n\nconst styles = StyleSheet.create({\n root: { flex: 1, width: '100%', flexDirection: 'column' },\n flex: { flex: 1, width: '100%' },\n header: {\n width: '100%',\n minHeight: LAYOUT.header.minHeight,\n flexDirection: 'column',\n justifyContent: 'center',\n },\n footer: {\n width: '100%',\n paddingHorizontal: LAYOUT.footer.paddingX,\n paddingTop: LAYOUT.footer.paddingY,\n },\n banner: { width: '100%' },\n})\n"],"mappings":";;;;;;;;;;;;;;AAqBA,SAAgB,aAAa,EAC3B,QACA,UACA,QACA,QACA,aAAa,MACb,aAAa,MACb,SACoB;CACpB,MAAM,SAAS,kBAAkB;CAEjC,MAAM,iBAAiB;EACrB,mBAAmB,OAAO,QAAQ;EAClC,YAAY,OAAO,QAAQ;EAC3B,eACE,WAAW,KAAA,KAAa,aACpB,OAAO,QAAQ,gBAAgB,OAAO,SACtC,OAAO,QAAQ;EACrB,KAAK,OAAO,QAAQ;CACtB;CAEA,OACE,qBAAC,MAAD;EAAM,OAAO;GAAC,OAAO;GAAM,EAAE,YAAY,OAAO,IAAI;GAAG;EAAK;YAA5D;GACG,WAAW,KAAA,KAAa,oBAAC,MAAD;IAAM,OAAO,OAAO;cAAS;GAAa,CAAA;GAElE,aACC,oBAAC,YAAD;IACE,OAAO,OAAO;IACd,uBAAuB;IACvB,8BAA8B;IAE7B;GACS,CAAA,IAEZ,oBAAC,MAAD;IAAM,OAAO,CAAC,OAAO,MAAM,cAAc;IAAI;GAAe,CAAA;GAG7D,WAAW,KAAA,KACV,oBAAC,MAAD;IACE,OAAO,CACL,OAAO,QACP,EACE,eAAe,aACX,OAAO,OAAO,WAAW,OAAO,SAChC,OAAO,OAAO,SACpB,CACF;cAEC;GACG,CAAA;GAGP,WAAW,KAAA,KAAa,oBAAC,MAAD;IAAM,OAAO,OAAO;cAAS;GAAa,CAAA;EAC/D;;AAEV;;AASA,SAAgB,MAAM,EAAE,UAAU,MAAM,OAAO,UAAU,SAAqB;CAC5E,OAAO,oBAAC,MAAD;EAAM,OAAO,CAAC;GAAE,eAAe;GAAU;EAAI,GAAG,KAAK;EAAI;CAAe,CAAA;AACjF;AAEA,MAAM,SAAS,WAAW,OAAO;CAC/B,MAAM;EAAE,MAAM;EAAG,OAAO;EAAQ,eAAe;CAAS;CACxD,MAAM;EAAE,MAAM;EAAG,OAAO;CAAO;CAC/B,QAAQ;EACN,OAAO;EACP,WAAW,OAAO,OAAO;EACzB,eAAe;EACf,gBAAgB;CAClB;CACA,QAAQ;EACN,OAAO;EACP,mBAAmB,OAAO,OAAO;EACjC,YAAY,OAAO,OAAO;CAC5B;CACA,QAAQ,EAAE,OAAO,OAAO;AAC1B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BottomSheetBaseProps, DialogBaseProps } from "../types.mjs";
|
|
2
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
//#region src/native/overlays.d.ts
|
|
5
|
+
interface BottomSheetProps extends BottomSheetBaseProps {
|
|
6
|
+
style?: StyleProp<ViewStyle>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 아래에서 올라오는 시트 (RN) — 웹의 `BottomSheet` 와 같은 prop 계약.
|
|
10
|
+
*
|
|
11
|
+
* 안드로이드 하드웨어 back 은 `onRequestClose` 로 처리된다.
|
|
12
|
+
*/
|
|
13
|
+
declare function BottomSheet({
|
|
14
|
+
open,
|
|
15
|
+
onOpenChange,
|
|
16
|
+
dismissible,
|
|
17
|
+
label,
|
|
18
|
+
children,
|
|
19
|
+
style
|
|
20
|
+
}: BottomSheetProps): import("react").JSX.Element;
|
|
21
|
+
interface DialogProps extends DialogBaseProps {
|
|
22
|
+
style?: StyleProp<ViewStyle>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 중앙 다이얼로그 (RN) — 웹의 `Dialog` 와 같은 prop 계약.
|
|
26
|
+
*
|
|
27
|
+
* 기본 버튼은 구조만 제공한다. 색·타이포는 앱의 버튼 컴포넌트를 `children` 으로 넣어
|
|
28
|
+
* 맞추는 것을 권장한다.
|
|
29
|
+
*/
|
|
30
|
+
declare function Dialog({
|
|
31
|
+
open,
|
|
32
|
+
onOpenChange,
|
|
33
|
+
dismissible,
|
|
34
|
+
title,
|
|
35
|
+
description,
|
|
36
|
+
cancel,
|
|
37
|
+
confirm,
|
|
38
|
+
children,
|
|
39
|
+
style
|
|
40
|
+
}: DialogProps): import("react").JSX.Element;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { BottomSheet, BottomSheetProps, Dialog, DialogProps };
|
|
43
|
+
//# sourceMappingURL=overlays.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlays.d.mts","names":[],"sources":["../../src/native/overlays.tsx"],"mappings":";;;;UA2BiB,gBAAA,SAAyB,oBAAA;EACxC,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;;;;;iBAQJ,WAAA;EACd,IAAA;EACA,YAAA;EACA,WAAA;EACA,KAAA;EACA,QAAA;EACA;AAAA,GACC,gBAAA,mBAAgB,GAAA,CAAA,OAAA;AAAA,UAgCF,WAAA,SAAoB,eAAA;EACnC,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;;;AAhDS;AAQ7B;;iBAiDgB,MAAA;EACd,IAAA;EACA,YAAA;EACA,WAAA;EACA,KAAA;EACA,WAAA;EACA,MAAA;EACA,OAAA;EACA,QAAA;EACA;AAAA,GACC,WAAA,mBAAW,GAAA,CAAA,OAAA"}
|