@byeolnaerim/flex-layout 0.0.5 → 0.0.7

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.
Files changed (173) hide show
  1. package/README.en.md +314 -0
  2. package/README.ko.md +312 -0
  3. package/README.md +314 -0
  4. package/dist/flex-layout/components/FlexLayout.cjs +76 -0
  5. package/dist/flex-layout/components/FlexLayout.cjs.map +1 -0
  6. package/dist/flex-layout/components/FlexLayout.d.ts +2 -0
  7. package/dist/flex-layout/components/FlexLayout.js +70 -0
  8. package/dist/flex-layout/components/FlexLayout.js.map +1 -0
  9. package/dist/flex-layout/components/FlexLayoutContainer.cjs +196 -0
  10. package/dist/flex-layout/components/FlexLayoutContainer.cjs.map +1 -0
  11. package/dist/flex-layout/components/FlexLayoutContainer.d.ts +2 -0
  12. package/dist/flex-layout/components/FlexLayoutContainer.js +189 -0
  13. package/dist/flex-layout/components/FlexLayoutContainer.js.map +1 -0
  14. package/dist/flex-layout/components/FlexLayoutResizePanel.cjs +181 -0
  15. package/dist/flex-layout/components/FlexLayoutResizePanel.cjs.map +1 -0
  16. package/dist/flex-layout/components/FlexLayoutResizePanel.d.ts +2 -0
  17. package/dist/flex-layout/components/FlexLayoutResizePanel.js +175 -0
  18. package/dist/flex-layout/components/FlexLayoutResizePanel.js.map +1 -0
  19. package/dist/flex-layout/components/FlexLayoutSplitScreen.cjs +1211 -0
  20. package/dist/flex-layout/components/FlexLayoutSplitScreen.cjs.map +1 -0
  21. package/dist/flex-layout/components/FlexLayoutSplitScreen.d.ts +11 -0
  22. package/dist/flex-layout/components/FlexLayoutSplitScreen.js +1197 -0
  23. package/dist/flex-layout/components/FlexLayoutSplitScreen.js.map +1 -0
  24. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBox.cjs +339 -0
  25. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBox.cjs.map +1 -0
  26. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBox.d.ts +27 -0
  27. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBox.js +333 -0
  28. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBox.js.map +1 -0
  29. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxContainer.cjs +32 -0
  30. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxContainer.cjs.map +1 -0
  31. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxContainer.d.ts +5 -0
  32. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxContainer.js +25 -0
  33. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxContainer.js.map +1 -0
  34. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxItem.cjs +40 -0
  35. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxItem.cjs.map +1 -0
  36. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxItem.d.ts +8 -0
  37. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxItem.js +34 -0
  38. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxItem.js.map +1 -0
  39. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxTitleMore.cjs +30 -0
  40. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxTitleMore.cjs.map +1 -0
  41. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxTitleMore.d.ts +4 -0
  42. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxTitleMore.js +24 -0
  43. package/dist/flex-layout/components/FlexLayoutSplitScreenDragBoxTitleMore.js.map +1 -0
  44. package/dist/flex-layout/components/FlexLayoutSplitScreenScrollBox.cjs +109 -0
  45. package/dist/flex-layout/components/FlexLayoutSplitScreenScrollBox.cjs.map +1 -0
  46. package/dist/flex-layout/components/FlexLayoutSplitScreenScrollBox.d.ts +9 -0
  47. package/dist/flex-layout/components/FlexLayoutSplitScreenScrollBox.js +103 -0
  48. package/dist/flex-layout/components/FlexLayoutSplitScreenScrollBox.js.map +1 -0
  49. package/dist/flex-layout/components/FlexLayoutStickyBox.cjs +226 -0
  50. package/dist/flex-layout/components/FlexLayoutStickyBox.cjs.map +1 -0
  51. package/dist/flex-layout/components/FlexLayoutStickyBox.d.ts +29 -0
  52. package/dist/flex-layout/components/FlexLayoutStickyBox.js +224 -0
  53. package/dist/flex-layout/components/FlexLayoutStickyBox.js.map +1 -0
  54. package/dist/flex-layout/components/index.cjs +52 -0
  55. package/dist/flex-layout/components/index.cjs.map +1 -0
  56. package/dist/flex-layout/components/index.d.ts +7 -0
  57. package/dist/flex-layout/components/index.js +9 -0
  58. package/dist/flex-layout/components/index.js.map +1 -0
  59. package/dist/flex-layout/hooks/index.cjs +21 -0
  60. package/dist/flex-layout/hooks/index.cjs.map +1 -0
  61. package/dist/flex-layout/hooks/index.d.ts +2 -0
  62. package/dist/flex-layout/hooks/index.js +4 -0
  63. package/dist/flex-layout/hooks/index.js.map +1 -0
  64. package/dist/{hooks.cjs → flex-layout/hooks/useDrag.cjs} +15 -208
  65. package/dist/flex-layout/hooks/useDrag.cjs.map +1 -0
  66. package/dist/{useDrag-DR01Ob3s.d.ts → flex-layout/hooks/useDrag.d.ts} +22 -25
  67. package/dist/{hooks.js → flex-layout/hooks/useDrag.js} +13 -203
  68. package/dist/flex-layout/hooks/useDrag.js.map +1 -0
  69. package/dist/flex-layout/hooks/useFlexLayoutSplitScreen.cjs +118 -0
  70. package/dist/flex-layout/hooks/useFlexLayoutSplitScreen.cjs.map +1 -0
  71. package/dist/flex-layout/hooks/useFlexLayoutSplitScreen.d.ts +28 -0
  72. package/dist/flex-layout/hooks/useFlexLayoutSplitScreen.js +116 -0
  73. package/dist/flex-layout/hooks/useFlexLayoutSplitScreen.js.map +1 -0
  74. package/dist/flex-layout/hooks/useListPaging.cjs +179 -0
  75. package/dist/flex-layout/hooks/useListPaging.cjs.map +1 -0
  76. package/dist/{hooks.d.ts → flex-layout/hooks/useListPaging.d.ts} +6 -12
  77. package/dist/flex-layout/hooks/useListPaging.js +175 -0
  78. package/dist/flex-layout/hooks/useListPaging.js.map +1 -0
  79. package/dist/flex-layout/hooks/useSizes.cjs +104 -0
  80. package/dist/flex-layout/hooks/useSizes.cjs.map +1 -0
  81. package/dist/flex-layout/hooks/useSizes.d.ts +8 -0
  82. package/dist/flex-layout/hooks/useSizes.js +101 -0
  83. package/dist/flex-layout/hooks/useSizes.js.map +1 -0
  84. package/dist/flex-layout/index.cjs +42 -0
  85. package/dist/flex-layout/index.cjs.map +1 -0
  86. package/dist/flex-layout/index.d.ts +5 -0
  87. package/dist/flex-layout/index.js +7 -0
  88. package/dist/flex-layout/index.js.map +1 -0
  89. package/dist/flex-layout/providers/FlexLayoutContext.cjs +26 -0
  90. package/dist/flex-layout/providers/FlexLayoutContext.cjs.map +1 -0
  91. package/dist/flex-layout/providers/FlexLayoutContext.d.ts +9 -0
  92. package/dist/flex-layout/providers/FlexLayoutContext.js +23 -0
  93. package/dist/flex-layout/providers/FlexLayoutContext.js.map +1 -0
  94. package/dist/{providers.cjs → flex-layout/providers/FlexLayoutHooks.cjs} +22 -186
  95. package/dist/flex-layout/providers/FlexLayoutHooks.cjs.map +1 -0
  96. package/dist/flex-layout/providers/FlexLayoutHooks.d.ts +51 -0
  97. package/dist/{providers.js → flex-layout/providers/FlexLayoutHooks.js} +14 -178
  98. package/dist/flex-layout/providers/FlexLayoutHooks.js.map +1 -0
  99. package/dist/flex-layout/providers/index.cjs +14 -0
  100. package/dist/flex-layout/providers/index.cjs.map +1 -0
  101. package/dist/flex-layout/providers/index.d.ts +1 -0
  102. package/dist/flex-layout/providers/index.js +3 -0
  103. package/dist/flex-layout/providers/index.js.map +1 -0
  104. package/dist/{store.cjs → flex-layout/store/FlexLayoutContainerStore.cjs} +20 -21
  105. package/dist/flex-layout/store/FlexLayoutContainerStore.cjs.map +1 -0
  106. package/dist/flex-layout/store/FlexLayoutContainerStore.d.ts +62 -0
  107. package/dist/{store.js → flex-layout/store/FlexLayoutContainerStore.js} +20 -21
  108. package/dist/flex-layout/store/FlexLayoutContainerStore.js.map +1 -0
  109. package/dist/flex-layout/store/index.cjs +14 -0
  110. package/dist/flex-layout/store/index.cjs.map +1 -0
  111. package/dist/flex-layout/store/index.d.ts +1 -0
  112. package/dist/flex-layout/store/index.js +3 -0
  113. package/dist/flex-layout/store/index.js.map +1 -0
  114. package/dist/flex-layout/styles/FlexLayout.module.css +416 -0
  115. package/dist/flex-layout/styles/listScroll.module.css +85 -0
  116. package/dist/flex-layout/styles/shake.module.css +41 -0
  117. package/dist/flex-layout/types/FlexDirectionTypes.cjs +4 -0
  118. package/dist/flex-layout/types/FlexDirectionTypes.cjs.map +1 -0
  119. package/dist/flex-layout/types/FlexDirectionTypes.d.ts +6 -0
  120. package/dist/flex-layout/types/FlexDirectionTypes.js +3 -0
  121. package/dist/flex-layout/types/FlexDirectionTypes.js.map +1 -0
  122. package/dist/flex-layout/types/FlexLayoutTypes.cjs +4 -0
  123. package/dist/flex-layout/types/FlexLayoutTypes.cjs.map +1 -0
  124. package/dist/flex-layout/types/FlexLayoutTypes.d.ts +53 -0
  125. package/dist/flex-layout/types/FlexLayoutTypes.js +3 -0
  126. package/dist/flex-layout/types/FlexLayoutTypes.js.map +1 -0
  127. package/dist/{utils.cjs → flex-layout/utils/FlexLayoutUtils.cjs} +3 -4
  128. package/dist/flex-layout/utils/FlexLayoutUtils.cjs.map +1 -0
  129. package/dist/flex-layout/utils/FlexLayoutUtils.d.ts +26 -0
  130. package/dist/{utils.js → flex-layout/utils/FlexLayoutUtils.js} +3 -4
  131. package/dist/flex-layout/utils/FlexLayoutUtils.js.map +1 -0
  132. package/dist/flex-layout/utils/index.cjs +14 -0
  133. package/dist/flex-layout/utils/index.cjs.map +1 -0
  134. package/dist/flex-layout/utils/index.d.ts +1 -0
  135. package/dist/flex-layout/utils/index.js +3 -0
  136. package/dist/flex-layout/utils/index.js.map +1 -0
  137. package/dist/index.cjs +10 -0
  138. package/dist/index.cjs.map +1 -1
  139. package/dist/index.d.ts +1 -2
  140. package/dist/index.js +1 -1
  141. package/dist/index.js.map +1 -1
  142. package/dist/types/css.d.cjs +4 -0
  143. package/dist/types/css.d.cjs.map +1 -0
  144. package/dist/types/css.d.js +3 -0
  145. package/dist/types/css.d.js.map +1 -0
  146. package/package.json +27 -44
  147. package/dist/FlexLayoutSplitScreenDragBox-eCtq4kLd.d.cts +0 -31
  148. package/dist/FlexLayoutSplitScreenDragBox-eCtq4kLd.d.ts +0 -31
  149. package/dist/components.cjs +0 -3048
  150. package/dist/components.cjs.map +0 -1
  151. package/dist/components.css +0 -471
  152. package/dist/components.css.map +0 -1
  153. package/dist/components.d.cts +0 -122
  154. package/dist/components.d.ts +0 -122
  155. package/dist/components.js +0 -3036
  156. package/dist/components.js.map +0 -1
  157. package/dist/hooks.cjs.map +0 -1
  158. package/dist/hooks.d.cts +0 -37
  159. package/dist/hooks.js.map +0 -1
  160. package/dist/index.d.cts +0 -2
  161. package/dist/providers.cjs.map +0 -1
  162. package/dist/providers.d.cts +0 -54
  163. package/dist/providers.d.ts +0 -54
  164. package/dist/providers.js.map +0 -1
  165. package/dist/store.cjs.map +0 -1
  166. package/dist/store.d.cts +0 -67
  167. package/dist/store.d.ts +0 -67
  168. package/dist/store.js.map +0 -1
  169. package/dist/useDrag-CYQnhUFk.d.cts +0 -108
  170. package/dist/utils.cjs.map +0 -1
  171. package/dist/utils.d.cts +0 -28
  172. package/dist/utils.d.ts +0 -28
  173. package/dist/utils.js.map +0 -1
package/README.en.md ADDED
@@ -0,0 +1,314 @@
1
+ # @byeolnaerim/flex-layout
2
+
3
+ > This document was drafted by ChatGPT using the codebase and real-world usage examples provided by the FlexLayout developer. It may contain inaccuracies, and the developer will verify and update it after review.
4
+
5
+ A set of components to quickly build **flex-based resizable panels + split screen + Drag & Drop** UI in React (Next.js).
6
+
7
+ The core of this library is **`<FlexLayout />`**.
8
+ With `FlexLayout` + `FlexLayoutContainer`, you can build layouts where panels are split (row/column), resized by dragging, and optionally opened/closed.
9
+ On top of that, it provides **Split Screen** (dynamic multi-pane views) and Drag & Drop based on **`FlexLayoutSplitScreenDragBox`** / **`useDragCapture`**.
10
+
11
+ > ⚠️ Many components rely on `window`, `ResizeObserver`, etc. For Next.js (App Router), using them as **Client Components** is recommended. (`"use client"`)
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ # npm
19
+ npm i @byeolnaerim/flex-layout
20
+
21
+ # yarn
22
+ yarn add @byeolnaerim/flex-layout
23
+
24
+ # pnpm
25
+ pnpm add @byeolnaerim/flex-layout
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quick Start
31
+
32
+ ### 1) FlexLayout + FlexLayoutContainer (basic resizable layout)
33
+
34
+ ```tsx
35
+ "use client";
36
+
37
+ import { FlexLayout, FlexLayoutContainer } from "@byeolnaerim/flex-layout";
38
+
39
+ export default function Basic() {
40
+ return (
41
+ <div style={{ height: 500 }}>
42
+ <FlexLayout layoutName="basic" direction="row">
43
+ <>
44
+ <FlexLayoutContainer
45
+ containerName="left"
46
+ grow={1}
47
+ isResizePanel
48
+ >
49
+ <div>Left</div>
50
+ </FlexLayoutContainer>
51
+
52
+ <FlexLayoutContainer containerName="right" grow={1}>
53
+ <div>Right</div>
54
+ </FlexLayoutContainer>
55
+ </>
56
+ </FlexLayout>
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ - `direction="row"`: left/right split
63
+ - `direction="column"`: top/bottom split
64
+ - A container with `isResizePanel={true}` will render a **resize panel** after it.
65
+
66
+ > **Important:** `layoutName` and `containerName` are used as keys in internal Store/Subjects.
67
+ > If multiple instances of the same layout can appear on the screen, use a stable unique value (e.g. `useId()`) to avoid collisions.
68
+
69
+ ---
70
+
71
+ ## FlexLayout
72
+
73
+ ### import
74
+
75
+ ```ts
76
+ import { FlexLayout } from "@byeolnaerim/flex-layout";
77
+ ```
78
+
79
+ ### Props
80
+
81
+ - `layoutName: string`
82
+ A key to identify the layout instance.
83
+ - `direction: "row" | "column"`
84
+ Flex direction (horizontal/vertical split).
85
+ - `children: ReactNode`
86
+ - `className?: string`
87
+ - `panelClassName?: string`
88
+ Class name for customizing the resize panel style.
89
+ - `panelMovementMode?: "default" | "bulldozer"`
90
+ How adjacent panels are pushed during resizing.
91
+
92
+ ---
93
+
94
+ ## FlexLayoutContainer (paired with FlexLayout)
95
+
96
+ ### import
97
+
98
+ ```ts
99
+ import { FlexLayoutContainer } from "@byeolnaerim/flex-layout";
100
+ ```
101
+
102
+ ### Props
103
+
104
+ - `containerName: string` _(required)_
105
+ Panel/container key.
106
+ - `children: ReactNode`
107
+ - `grow?: number`
108
+ Flex-grow ratio (e.g. left 2, right 1).
109
+ - `className?: string`
110
+ - `style?: React.CSSProperties`
111
+ - `isResizePanel?: boolean`
112
+ Whether to place a resize panel after this container.
113
+ - `panelMode?: "default" | "left-cylinder" | "right-cylinder" | "top-cylinder" | "bottom-cylinder"`
114
+ Controls the **visual orientation/anchor** of the resize panel (and the open/close motion).
115
+ - `isFitContent?: boolean`
116
+ Fit based on content size.
117
+
118
+ ---
119
+
120
+ ## (Advanced) Open/Close panels + dynamic grow control
121
+
122
+ The library provides an RxJS Subject map keyed by `containerName` to send **open/close** events to panels.
123
+
124
+ ### Open/Close with containerOpenCloseSubjectMap
125
+
126
+ ```ts
127
+ import { containerOpenCloseSubjectMap } from "@byeolnaerim/flex-layout/providers";
128
+
129
+ // Example: open right-panel
130
+ containerOpenCloseSubjectMap["right-panel"].next({
131
+ mode: "open",
132
+ openOption: { isPrevSizeOpen: true }, // restore previous size
133
+ });
134
+
135
+ // Example: close right-panel
136
+ containerOpenCloseSubjectMap["right-panel"].next({
137
+ mode: "close",
138
+ });
139
+ ```
140
+
141
+ - `mode: "toggle" | "open" | "close"`
142
+ - `openOption.isPrevSizeOpen?: boolean`: restore previous opened size
143
+ - Optional callbacks: `onOpen?`, `onClose?`
144
+
145
+ ### Control grow directly with useContainers
146
+
147
+ `useContainers(layoutName)` returns the actual DOM containers for that layout.
148
+ It’s useful for cases like: “only the selected tab container has grow=1, the others have grow=0”, with transitions.
149
+
150
+ ```ts
151
+ import { useContainers } from "@byeolnaerim/flex-layout/providers";
152
+
153
+ const containers = useContainers(layoutName);
154
+ // e.g. containers.forEach(el => el.style.flex = "1 1 0%");
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Split Screen
160
+
161
+ Split Screen supports the pattern:
162
+ “drag and drop to left/right/top/bottom/center → dynamically create a new split view at that position.”
163
+
164
+ ⚠️ Note: `FlexLayoutSplitScreen` has not been thoroughly validated for stability in real-world usage. It may not behave as you expect.
165
+
166
+ ### 1) FlexLayoutSplitScreen (split root)
167
+
168
+ ```tsx
169
+ "use client";
170
+
171
+ import { FlexLayoutSplitScreen } from "@byeolnaerim/flex-layout";
172
+
173
+ export default function Page() {
174
+ return (
175
+ <FlexLayoutSplitScreen
176
+ layoutName="rootSplitScreen"
177
+ containerName="dashboard"
178
+ navigationTitle="Dashboard"
179
+ dropDocumentOutsideOption={{
180
+ openUrl: "/",
181
+ widthRatio: 0.7,
182
+ heightRatio: 0.5,
183
+ }}
184
+ >
185
+ <div>Dashboard content</div>
186
+ </FlexLayoutSplitScreen>
187
+ );
188
+ }
189
+ ```
190
+
191
+ **Props (summary)**
192
+
193
+ - `layoutName: string`: root key of the split-screen tree
194
+ - `containerName: string`: key for this screen/container
195
+ - `children: ReactNode`
196
+ - `navigationTitle?: string`: title for tabs/navigation
197
+ - `dropDocumentOutsideOption?: { openUrl: string; widthRatio?: number; heightRatio?: number }`
198
+ If dropped “outside the screen”, open it as a new window/document.
199
+ - `screenKey?: string`: a unique value used to identify a screen inside `FlexLayoutSplitScreen`. If empty, a 32-character random default is generated. For dynamic split-screen views you can’t control, leaving it empty is recommended.
200
+
201
+ ---
202
+
203
+ ## FlexLayoutSplitScreenDragBox (Split Screen drag source)
204
+
205
+ `FlexLayoutSplitScreenDragBox` is a **draggable source component**.
206
+ When you drag it and drop on a Split Screen boundary, it renders `targetComponent` at the drop position and creates a new split view.
207
+
208
+ ```tsx
209
+ import { FlexLayoutSplitScreenDragBox } from "@byeolnaerim/flex-layout";
210
+
211
+ <FlexLayoutSplitScreenDragBox
212
+ containerName="menu:users"
213
+ navigationTitle="Users"
214
+ targetComponent={<UsersPage />}
215
+ dropDocumentOutsideOption={{
216
+ openUrl: "/admin/users",
217
+ widthRatio: 0.7,
218
+ heightRatio: 0.5,
219
+ }}
220
+ >
221
+ <button>Open Users</button>
222
+ </FlexLayoutSplitScreenDragBox>;
223
+ ```
224
+
225
+ **Props (summary)**
226
+
227
+ - `containerName: string` _(required)_: unique key for the draggable item
228
+ - `children: ReactNode`: the visible UI
229
+ - `targetComponent?: ReactNode`: component to render in the new split pane
230
+ - `navigationTitle?: string`
231
+ - `dropDocumentOutsideOption?: { openUrl: string; widthRatio?: number; heightRatio?: number }`
232
+ - `customData?: any`: arbitrary data passed along on drop
233
+ - `scrollTargetRef?: RefObject<HTMLElement>`: scroll target while dragging (optional)
234
+
235
+ ---
236
+
237
+ ## (Advanced) Use Drag & Drop only with FlexLayoutSplitScreenDragBox + useDragCapture
238
+
239
+ You can use it as **pure Drag & Drop**, without creating Split Screen.
240
+
241
+ - Drag source: `FlexLayoutSplitScreenDragBox`
242
+ - Drop target: `useDragCapture(ref)`
243
+
244
+ ### Example: drop unitCard → slotCard to insert info
245
+
246
+ ```tsx
247
+ import { useDragCapture } from "@byeolnaerim/flex-layout";
248
+
249
+ const dropRef = useRef<HTMLDivElement>(null);
250
+ const dragState = useDragCapture(dropRef);
251
+
252
+ useEffect(() => {
253
+ if (!dragState) return;
254
+ const {
255
+ isDrop,
256
+ containerName, // containerName of the dragged item
257
+ positionName, // boundary position (left/top/right/bottom/center)
258
+ customData, // customData passed from DragBox
259
+ } = dragState;
260
+
261
+ if (isDrop) {
262
+ // TODO: handle “equip/insert” logic based on containerName/customData
263
+ }
264
+ }, [dragState]);
265
+ ```
266
+
267
+ `dragState` includes `isDrop`, `isDragging`, `isOver`, `positionName`, and coordinates (`x`, `y`).
268
+
269
+ ---
270
+
271
+ ## Practical patterns (ideas)
272
+
273
+ - **Tabs + FlexLayout**
274
+ Control container `flex` values via `useContainers(layoutName)` and animate
275
+ “selected tab grow=1, others grow=0”.
276
+ - **Master–Detail (left list / right detail)**
277
+ Open/close the detail panel with
278
+ `containerOpenCloseSubjectMap["right"].next({ mode: selected ? "open" : "close" })`.
279
+ - **Admin Split Screen**
280
+ Drag sidebar items (`FlexLayoutSplitScreenDragBox`) → create a new split view at the desired position.
281
+
282
+ ---
283
+
284
+ ## Export paths
285
+
286
+ Use whichever import style you prefer.
287
+
288
+ ```ts
289
+ // 1) unified imports from root
290
+ import {
291
+ FlexLayout,
292
+ FlexLayoutContainer,
293
+ FlexLayoutSplitScreen,
294
+ FlexLayoutSplitScreenDragBox,
295
+ } from "@byeolnaerim/flex-layout";
296
+
297
+ // 2) components subpath (if preferred)
298
+ import {
299
+ FlexLayout,
300
+ FlexLayoutContainer,
301
+ } from "@byeolnaerim/flex-layout/components";
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Tips
307
+
308
+ - Use a meaningful prefix for `containerName` (e.g. `left-container-${id}`, `menu:${identifierId}`)
309
+ This makes debugging and preventing collisions much easier in Split Screen.
310
+ - In Next.js, add `"use client"` at the top of files that use these layout components.
311
+
312
+ ---
313
+
314
+ ## The internal implementation/style structure is still evolving, so the API may change over time.
package/README.ko.md ADDED
@@ -0,0 +1,312 @@
1
+ # @byeolnaerim/flex-layout
2
+
3
+ > 이 문서는 코드베이스와 사용 사례들을 제공받은 ChatGPT가 작성하였습니다. 문서의 내용이 정확하지 않을 수 있으며, FlexLayout 개발자가 검토 후 재수정할 예정입니다.
4
+
5
+ React(Next.js)에서 **flex 기반 리사이즈 패널 + 스플릿 스크린 + Drag & Drop** UI를 빠르게 만들기 위한 컴포넌트 모음입니다.
6
+
7
+ 이 라이브러리의 핵심은 **`<FlexLayout />`** 입니다.
8
+ `FlexLayout` + `FlexLayoutContainer`로 “패널이 나뉘고(가로/세로), 드래그로 크기를 조절하고, 필요하면 열고/닫는” 레이아웃을 구성합니다.
9
+ 그 위에 **Split Screen**(동적 분할 화면)과, 이를 위한 **`FlexLayoutSplitScreenDragBox`** / **`useDragCapture`** 기반 Drag & Drop을 제공합니다.
10
+
11
+ > ⚠️ 대부분의 컴포넌트가 `window`, `ResizeObserver` 등을 사용합니다. **Next.js(App Router)에서는 Client Component** 사용을 권장합니다. (`"use client"`)
12
+
13
+ ---
14
+
15
+ ## 설치
16
+
17
+ ```bash
18
+ # npm
19
+ npm i @byeolnaerim/flex-layout
20
+
21
+ # yarn
22
+ yarn add @byeolnaerim/flex-layout
23
+
24
+ # pnpm
25
+ pnpm add @byeolnaerim/flex-layout
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 빠른 시작
31
+
32
+ ### 1) FlexLayout + FlexLayoutContainer (기본 리사이즈 레이아웃)
33
+
34
+ ```tsx
35
+ "use client";
36
+
37
+ import { FlexLayout, FlexLayoutContainer } from "@byeolnaerim/flex-layout";
38
+
39
+ export default function Basic() {
40
+ return (
41
+ <div style={{ height: 500 }}>
42
+ <FlexLayout layoutName="basic" direction="row">
43
+ <>
44
+ <FlexLayoutContainer
45
+ containerName="left"
46
+ grow={1}
47
+ isResizePanel
48
+ >
49
+ <div>Left</div>
50
+ </FlexLayoutContainer>
51
+
52
+ <FlexLayoutContainer containerName="right" grow={1}>
53
+ <div>Right</div>
54
+ </FlexLayoutContainer>
55
+ </>
56
+ </FlexLayout>
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ - `direction="row"`: 좌/우 분할
63
+ - `direction="column"`: 상/하 분할
64
+ - `FlexLayoutContainer`의 `isResizePanel`이 `true`인 컨테이너 뒤에 **리사이즈 패널**이 붙습니다.
65
+
66
+ > **중요:** `layoutName`, `containerName`은 내부 Store/Subject의 키로 쓰입니다.
67
+ > 화면에 동일한 레이아웃이 여러 개 생길 수 있다면 `useId()` 같은 안정적인 값을 써서 유니크하게 관리하는 걸 권장합니다.
68
+
69
+ ---
70
+
71
+ ## FlexLayout
72
+
73
+ ### import
74
+
75
+ ```ts
76
+ import { FlexLayout } from "@byeolnaerim/flex-layout";
77
+ ```
78
+
79
+ ### Props
80
+
81
+ - `layoutName: string`
82
+ 레이아웃 인스턴스를 구분하는 이름(키).
83
+ - `direction: "row" | "column"`
84
+ flex 방향(가로/세로 분할).
85
+ - `children: ReactNode`
86
+ - `className?: string`
87
+ - `panelClassName?: string`
88
+ 리사이즈 패널 커스텀 스타일을 위한 클래스.
89
+ - `panelMovementMode?: "default" | "bulldozer"`
90
+ 패널 이동(리사이즈) 시 인접 패널들을 어떻게 밀어낼지에 대한 모드.
91
+
92
+ ---
93
+
94
+ ## FlexLayoutContainer (FlexLayout과 세트)
95
+
96
+ ### import
97
+
98
+ ```ts
99
+ import { FlexLayoutContainer } from "@byeolnaerim/flex-layout";
100
+ ```
101
+
102
+ ### Props
103
+
104
+ - `containerName: string` _(필수)_
105
+ 컨테이너(패널) 이름(키).
106
+ - `children: ReactNode`
107
+ - `grow?: number`
108
+ flex-grow 기반 비율. (예: 좌 2, 우 1)
109
+ - `className?: string`
110
+ - `style?: React.CSSProperties`
111
+ - `isResizePanel?: boolean`
112
+ 이 컨테이너 뒤에 리사이즈 패널을 붙일지 여부.
113
+ - `panelMode?: "default" | "left-cylinder" | "right-cylinder" | "top-cylinder" | "bottom-cylinder"`
114
+ 리사이즈 패널(또는 open/close 모션)의 **UI 방향/앵커(기준)** 를 결정하는 옵션입니다.
115
+ - `isFitContent?: boolean`
116
+ 콘텐츠 높이/너비를 기준으로 fit 하게 처리.
117
+
118
+ ---
119
+
120
+ ## (응용) 패널 열고/닫기 + grow 동적 제어
121
+
122
+ 라이브러리는 `containerName`을 키로 **패널 open/close** 이벤트를 보낼 수 있도록 RxJS Subject 맵을 제공합니다.
123
+
124
+ ### containerOpenCloseSubjectMap으로 열고 닫기
125
+
126
+ ```ts
127
+ import { containerOpenCloseSubjectMap } from "@byeolnaerim/flex-layout/providers";
128
+
129
+ // 예: right-panel 열기
130
+ containerOpenCloseSubjectMap["right-panel"].next({
131
+ mode: "open",
132
+ openOption: { isPrevSizeOpen: true }, // 이전 사이즈로 열기
133
+ });
134
+
135
+ // 예: right-panel 닫기
136
+ containerOpenCloseSubjectMap["right-panel"].next({
137
+ mode: "close",
138
+ });
139
+ ```
140
+
141
+ - `mode: "toggle" | "open" | "close"`
142
+ - `openOption.isPrevSizeOpen?: boolean` : 이전에 열려있던 크기 복원 여부
143
+ - `onOpen?`, `onClose?` 콜백 제공
144
+
145
+ ### useContainers로 grow를 직접 조절하기
146
+
147
+ `useContainers(layoutName)`은 해당 레이아웃의 실제 DOM 컨테이너 배열을 줍니다.
148
+ 질문에 주신 예시처럼 **탭에 따라 특정 컨테이너만 grow=1**, 나머지는 grow=0으로 애니메이션 처리할 때 유용합니다.
149
+
150
+ ```ts
151
+ import { useContainers } from "@byeolnaerim/flex-layout/providers";
152
+
153
+ const containers = useContainers(layoutName);
154
+ // containers.forEach(el => el.style.flex = "1 1 0%"); 같은 방식으로 제어
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Split Screen
160
+
161
+ Split Screen은 “드래그로 화면을 좌/우/상/하/중앙에 드롭 → 해당 위치에 새 화면을 동적으로 분할 생성”하는 패턴을 제공합니다.
162
+ ⚠️ 주의 : FlexLayoutSplitScreen은 실제 사용 환경에서의 안정성을 제대로 확인하지 않았습니다. 당신이 의도한 대로 동작하지 않을 수도 있습니다.
163
+
164
+ ### 1) FlexLayoutSplitScreen (스플릿 루트)
165
+
166
+ ```tsx
167
+ "use client";
168
+
169
+ import { FlexLayoutSplitScreen } from "@byeolnaerim/flex-layout";
170
+
171
+ export default function Page() {
172
+ return (
173
+ <FlexLayoutSplitScreen
174
+ layoutName="rootSplitScreen"
175
+ containerName="dashboard"
176
+ navigationTitle="대시보드"
177
+ dropDocumentOutsideOption={{
178
+ openUrl: "/",
179
+ widthRatio: 0.7,
180
+ heightRatio: 0.5,
181
+ }}
182
+ >
183
+ <div>대시보드 콘텐츠</div>
184
+ </FlexLayoutSplitScreen>
185
+ );
186
+ }
187
+ ```
188
+
189
+ **Props (요약)**
190
+
191
+ - `layoutName: string` : 스플릿 화면 트리의 루트 키
192
+ - `containerName: string` : 이 화면(컨테이너)의 키
193
+ - `children: ReactNode`
194
+ - `navigationTitle?: string` : 탭/내비게이션용 타이틀
195
+ - `dropDocumentOutsideOption?: { openUrl: string; widthRatio?: number; heightRatio?: number }`
196
+ 드롭을 “화면 밖”으로 했을 때 새 창/문서로 열기 옵션
197
+ - `screenKey?: string` : FlexLayoutSplitScreen내부에서 screen을 판별할 때 사용하는 유니크한 값입니다. 빈값일 경우 default 값으로 32자리의 랜덤 값을 생성합니다. 개발자가 제어할 수 없는 동적 분할 화면 뷰라면 가급적 빈값으로 이용하는 것을 권장합니다.
198
+
199
+ ---
200
+
201
+ ## FlexLayoutSplitScreenDragBox (스플릿 스크린 드래그 소스)
202
+
203
+ `FlexLayoutSplitScreenDragBox`는 **드래그 가능한 소스 컴포넌트**입니다.
204
+ 이걸 끌어서 Split Screen 경계에 드롭하면, drop 대상 위치에 `targetComponent`를 렌더링하며 분할 화면이 만들어집니다.
205
+
206
+ ```tsx
207
+ import { FlexLayoutSplitScreenDragBox } from "@byeolnaerim/flex-layout";
208
+
209
+ <FlexLayoutSplitScreenDragBox
210
+ containerName="menu:users"
211
+ navigationTitle="유저 목록"
212
+ targetComponent={<UsersPage />}
213
+ dropDocumentOutsideOption={{
214
+ openUrl: "/admin/users",
215
+ widthRatio: 0.7,
216
+ heightRatio: 0.5,
217
+ }}
218
+ >
219
+ <button>유저 목록 열기</button>
220
+ </FlexLayoutSplitScreenDragBox>;
221
+ ```
222
+
223
+ **Props (요약)**
224
+
225
+ - `containerName: string` _(필수)_ : 드래그 항목 고유 키
226
+ - `children: ReactNode` : 실제 렌더링될 UI
227
+ - `targetComponent?: ReactNode` : 분할 화면에 새로 띄울 컴포넌트
228
+ - `navigationTitle?: string`
229
+ - `dropDocumentOutsideOption?: { openUrl: string; widthRatio?: number; heightRatio?: number }`
230
+ - `customData?: any` : 드롭 시 함께 전달할 임의 데이터
231
+ - `scrollTargetRef?: RefObject<HTMLElement>` : 드래그 중 스크롤 타겟(옵션)
232
+
233
+ ---
234
+
235
+ ## (응용) FlexLayoutSplitScreenDragBox + useDragCapture로 Drag & Drop만 쓰기
236
+
237
+ Split Screen을 만들지 않고, **순수 Drag & Drop**으로도 활용할 수 있습니다.
238
+
239
+ - 드래그 소스: `FlexLayoutSplitScreenDragBox`
240
+ - 드롭 타겟: `useDragCapture(ref)`
241
+
242
+ ### 예: unitCard → slotCard로 드롭해서 정보 삽입
243
+
244
+ ```tsx
245
+ import { useDragCapture } from "@byeolnaerim/flex-layout";
246
+
247
+ const dropRef = useRef<HTMLDivElement>(null);
248
+ const dragState = useDragCapture(dropRef);
249
+
250
+ useEffect(() => {
251
+ if (!dragState) return;
252
+ const {
253
+ isDrop,
254
+ containerName, // 드래그된 item의 containerName
255
+ positionName, // 어느 경계에 놓였는지 (left/top/right/bottom/center)
256
+ customData, // DragBox에서 넘긴 customData
257
+ } = dragState;
258
+
259
+ if (isDrop) {
260
+ // TODO: containerName/customData 기반으로 “장착/삽입” 처리
261
+ }
262
+ }, [dragState]);
263
+ ```
264
+
265
+ `dragState`에는 드롭 여부(`isDrop`), 드래그 중 여부(`isDragging`), 오버 여부(`isOver`), 위치(`positionName`), 좌표(`x`,`y`) 등이 포함됩니다.
266
+
267
+ ---
268
+
269
+ ## 실사용 패턴 모음 (아이디어)
270
+
271
+ - **탭 UI + FlexLayout**
272
+ `useContainers(layoutName)`로 DOM 컨테이너의 `flex`를 직접 제어해서
273
+ “선택된 탭만 grow=1, 나머지 grow=0” 전환 애니메이션 구현.
274
+ - **마스터-디테일(좌 리스트 / 우 상세)**
275
+ `containerOpenCloseSubjectMap["right"].next({ mode: selected ? "open" : "close" })`로
276
+ 상세 패널을 상황에 따라 열고 닫기.
277
+ - **어드민 화면 Split Screen**
278
+ 사이드바 메뉴(`FlexLayoutSplitScreenDragBox`)를 드래그 → 원하는 위치에 새 화면 분할.
279
+
280
+ ---
281
+
282
+ ## Export 경로
283
+
284
+ 일반적으로 아래 둘 중 편한 방식으로 import 하면 됩니다.
285
+
286
+ ```ts
287
+ // 1) 루트에서 통합 import
288
+ import {
289
+ FlexLayout,
290
+ FlexLayoutContainer,
291
+ FlexLayoutSplitScreen,
292
+ FlexLayoutSplitScreenDragBox,
293
+ } from "@byeolnaerim/flex-layout";
294
+
295
+ // 2) components 서브패스 (선호 시)
296
+ import {
297
+ FlexLayout,
298
+ FlexLayoutContainer,
299
+ } from "@byeolnaerim/flex-layout/components";
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Tips
305
+
306
+ - **containerName은 가능한 한 “의미 있는 prefix”**를 붙이세요. (예: `left-container-${id}`, `menu:${identifierId}`)
307
+ Split Screen에서 중복 방지/트리 구성 시 디버깅이 훨씬 쉬워집니다.
308
+ - Next.js에서 서버 컴포넌트로 쓰면 오류가 날 수 있으니, 레이아웃 관련 파일 상단에 `"use client"`를 붙이세요.
309
+
310
+ ---
311
+
312
+ ## 내부 구현/스타일 구조는 계속 발전 중이라 API는 조금씩 바뀔 수 있습니다.