@aiquants/resize-panels 2.0.0 → 2.0.1
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/dist/GlobalDebugOverlay.d.ts +4 -0
- package/dist/Panel.d.ts +13 -0
- package/dist/{src/PanelDebugInfo.d.ts → PanelDebugInfo.d.ts} +2 -14
- package/dist/PanelGroup.d.ts +2 -0
- package/dist/PanelResizeHandle.d.ts +2 -0
- package/dist/allocateLayout.d.ts +12 -0
- package/dist/context.d.ts +3 -0
- package/dist/debugOverlayStore.d.ts +32 -0
- package/dist/{src/hooks.d.ts → hooks.d.ts} +8 -23
- package/dist/index.d.ts +13 -2
- package/dist/reducer.d.ts +8 -0
- package/dist/roundHalfToEven.d.ts +1 -0
- package/dist/types.d.ts +183 -0
- package/dist/utils/simple-logger.d.ts +37 -0
- package/dist/utils.d.ts +16 -0
- package/package.json +2 -3
- package/dist/src/GlobalDebugOverlay.d.ts +0 -21
- package/dist/src/GlobalDebugOverlay.d.ts.map +0 -1
- package/dist/src/Panel.d.ts +0 -46
- package/dist/src/Panel.d.ts.map +0 -1
- package/dist/src/PanelDebugInfo.d.ts.map +0 -1
- package/dist/src/PanelGroup.d.ts +0 -7
- package/dist/src/PanelGroup.d.ts.map +0 -1
- package/dist/src/PanelResizeHandle.d.ts +0 -7
- package/dist/src/PanelResizeHandle.d.ts.map +0 -1
- package/dist/src/allocateLayout.d.ts +0 -60
- package/dist/src/allocateLayout.d.ts.map +0 -1
- package/dist/src/context.d.ts +0 -12
- package/dist/src/context.d.ts.map +0 -1
- package/dist/src/debugOverlayStore.d.ts +0 -69
- package/dist/src/debugOverlayStore.d.ts.map +0 -1
- package/dist/src/hooks.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -32
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/reducer.d.ts +0 -49
- package/dist/src/reducer.d.ts.map +0 -1
- package/dist/src/roundHalfToEven.d.ts +0 -10
- package/dist/src/roundHalfToEven.d.ts.map +0 -1
- package/dist/src/types.d.ts +0 -481
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils/simple-logger.d.ts +0 -111
- package/dist/src/utils/simple-logger.d.ts.map +0 -1
- package/dist/src/utils.d.ts +0 -164
- package/dist/src/utils.d.ts.map +0 -1
- package/dist/tests/support/dom-harness.d.ts +0 -89
- package/dist/tests/support/dom-harness.d.ts.map +0 -1
- package/src/GlobalDebugOverlay.tsx +0 -284
- package/src/Panel.tsx +0 -297
- package/src/PanelDebugInfo.tsx +0 -94
- package/src/PanelGroup.tsx +0 -245
- package/src/PanelResizeHandle.tsx +0 -758
- package/src/allocateLayout.ts +0 -412
- package/src/context.ts +0 -25
- package/src/debugOverlayStore.ts +0 -355
- package/src/hooks.ts +0 -376
- package/src/index.ts +0 -93
- package/src/reducer.ts +0 -472
- package/src/roundHalfToEven.ts +0 -40
- package/src/styles/components.entry.css +0 -10
- package/src/styles/resize-panels.css +0 -1
- package/src/styles/standalone.entry.css +0 -12
- package/src/types.ts +0 -505
- package/src/utils/simple-logger.ts +0 -186
- package/src/utils.ts +0 -320
package/src/hooks.ts
DELETED
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Custom hooks for resizable panels logic
|
|
3
|
-
* リサイズ可能パネルのロジックのためのカスタムフック
|
|
4
|
-
*
|
|
5
|
-
* The hook owns everything the reducer cannot: it measures the container, keeps the panel order in step
|
|
6
|
-
* with the DOM, and forwards user intent as actions. It never computes a panel size itself.
|
|
7
|
-
* フックはリデューサーが担えない役割だけを持つ: コンテナの計測、DOM 順との同期、利用者の意図のアクション化。
|
|
8
|
-
* パネルサイズ自体はここでは一切計算しない。
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { type CSSProperties, useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react"
|
|
12
|
-
import { usePanelGroup } from "./context"
|
|
13
|
-
import { getPanelPreferenceInPixels, initialPanelGroupLayoutState, panelReducer } from "./reducer"
|
|
14
|
-
import type { PanelCollapseDirection, PanelGroupProps, PanelMeasurement, PanelRegistration, PersistedPanelSize, ResizeHandleLayoutData } from "./types"
|
|
15
|
-
import { getContainerSize, getGroupLayoutElements, loadLayout, saveLayout, touchesLayoutElements } from "./utils"
|
|
16
|
-
import { Logger, LogLevel } from "./utils/simple-logger"
|
|
17
|
-
|
|
18
|
-
const logger = new Logger(LogLevel.INFO, "[resize-panels]")
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Delay before the layout is written to storage, in milliseconds.
|
|
22
|
-
* レイアウトを保存領域へ書き出すまでの待機時間 (ms)。
|
|
23
|
-
*/
|
|
24
|
-
const AUTO_SAVE_DELAY_MS = 200
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Placeholder that stands for a handle anchor in the group's DOM-order key.
|
|
28
|
-
* グループの DOM 順を表す鍵の中で、ハンドルのアンカーを表す標識。
|
|
29
|
-
*/
|
|
30
|
-
const HANDLE_ANCHOR_ORDER_MARK = "\u0000handle"
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Orchestrate measurement, ordering, persistence and user intent for one panel group.
|
|
34
|
-
* 1 つのパネルグループにおける計測・順序同期・永続化・利用者操作の統括。
|
|
35
|
-
*
|
|
36
|
-
* @param props - Panel group props / パネルグループのプロパティ
|
|
37
|
-
* @returns Group ref, context value and the group's base style / グループ ref・コンテキスト値・基準スタイル
|
|
38
|
-
*/
|
|
39
|
-
export const useResizablePanels = ({ direction, style, onLayout, autoSaveId, showDebugInfo = false }: PanelGroupProps) => {
|
|
40
|
-
const [layout, dispatch] = useReducer(panelReducer, initialPanelGroupLayoutState)
|
|
41
|
-
const [panelMeasurements, setPanelMeasurements] = useState<Record<string, PanelMeasurement>>({})
|
|
42
|
-
const [handleMeasurements, setHandleMeasurements] = useState<Record<string, ResizeHandleLayoutData>>({})
|
|
43
|
-
|
|
44
|
-
const groupRef = useRef<HTMLDivElement>(null)
|
|
45
|
-
const [layoutOrderKey, setLayoutOrderKey] = useState("")
|
|
46
|
-
const registrationSignaturesRef = useRef<Record<string, string>>({})
|
|
47
|
-
const layoutCallbackRef = useRef(onLayout)
|
|
48
|
-
layoutCallbackRef.current = onLayout
|
|
49
|
-
|
|
50
|
-
useLayoutEffect(() => {
|
|
51
|
-
// ResizeObserver でグループの内容領域長を追跡する。観測値は丸めも遅延もせずそのまま確定させる:
|
|
52
|
-
// 端数を落とすと、状態が持つ長さと描画される長さがずれたままになる。
|
|
53
|
-
// 主軸の長さが動かないフレーム (交差軸だけのリサイズ) はここで捨てる。reducer は同一状態を
|
|
54
|
-
// 返すものの、dispatch 自体がレンダーを予約してしまうため
|
|
55
|
-
const element = groupRef.current
|
|
56
|
-
if (!element || typeof ResizeObserver === "undefined") {
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let lastContent = Number.NaN
|
|
61
|
-
const commitContentLength = (content: number) => {
|
|
62
|
-
if (content === lastContent) {
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
lastContent = content
|
|
66
|
-
dispatch({ type: "SET_CONTAINER_SIZE", containerSize: content })
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const observer = new ResizeObserver((entries) => {
|
|
70
|
-
commitContentLength(getContainerSize(element, direction, entries[0]).content)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
observer.observe(element)
|
|
74
|
-
// 初回描画を正しい配分で塗るための種。観測が届いた時点で厳密値へ置き換わる
|
|
75
|
-
commitContentLength(getContainerSize(element, direction).content)
|
|
76
|
-
|
|
77
|
-
return () => {
|
|
78
|
-
observer.disconnect()
|
|
79
|
-
}
|
|
80
|
-
}, [direction])
|
|
81
|
-
|
|
82
|
-
const panels = layout.panels
|
|
83
|
-
const panelsRef = useRef(panels)
|
|
84
|
-
panelsRef.current = panels
|
|
85
|
-
|
|
86
|
-
const syncPanelOrder = useCallback(() => {
|
|
87
|
-
// パネルは DOM 順に並んでいることが前提の状態 (保存・onLayout・優先度の同順位比較) なので、
|
|
88
|
-
// 登録順と DOM 順がずれたら DOM 側へ合わせ直す
|
|
89
|
-
const element = groupRef.current
|
|
90
|
-
const currentPanels = panelsRef.current
|
|
91
|
-
if (!element) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
const layoutElements = getGroupLayoutElements(element)
|
|
95
|
-
// ハンドルが別の境界へ移っただけの並べ替えはパネルの id 列を変えない。
|
|
96
|
-
// アンカーの位置も含めた並びを鍵にして、ハンドル側の再検出も同じ変化で起こす
|
|
97
|
-
setLayoutOrderKey((previous) => {
|
|
98
|
-
const next = layoutElements.map((layoutElement) => layoutElement.dataset.panelId ?? HANDLE_ANCHOR_ORDER_MARK).join("\u0000")
|
|
99
|
-
return previous === next ? previous : next
|
|
100
|
-
})
|
|
101
|
-
if (currentPanels.length === 0) {
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
const ids: string[] = []
|
|
105
|
-
for (const layoutElement of layoutElements) {
|
|
106
|
-
const id = layoutElement.dataset.panelId
|
|
107
|
-
if (id !== undefined) {
|
|
108
|
-
ids.push(id)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (new Set(ids).size !== ids.length) {
|
|
112
|
-
// 同じ id のパネルが同時に存在すると 1 つの状態を 2 枚が描画し、合計がコンテナを超える
|
|
113
|
-
logger.error("Duplicate panel id in one group.", { ids })
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
if (ids.length !== currentPanels.length || ids.every((id, index) => id === currentPanels[index].id)) {
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
dispatch({ type: "REORDER_PANELS", ids })
|
|
120
|
-
}, [])
|
|
121
|
-
|
|
122
|
-
useLayoutEffect(() => {
|
|
123
|
-
// 並べ替えは登録・解除を伴わないことがある (JSX 上の順序だけを入れ替えた場合など)。
|
|
124
|
-
// 状態の変化を待つと取りこぼすため、DOM の子要素の変化そのものを監視する
|
|
125
|
-
const element = groupRef.current
|
|
126
|
-
if (!element) {
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
syncPanelOrder()
|
|
130
|
-
if (typeof MutationObserver === "undefined") {
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
const observer = new MutationObserver((records) => {
|
|
134
|
-
// 配置要素に触れない変更は無視する。パネルの内容 (仮想化リストの行など) は毎フレーム
|
|
135
|
-
// 入れ替わるため、すべての変更で走査するとグループ全体に比例した費用を払い続ける
|
|
136
|
-
if (touchesLayoutElements(records)) {
|
|
137
|
-
syncPanelOrder()
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
// 中間要素の中での並べ替えも拾うため subtree ごと監視する
|
|
141
|
-
observer.observe(element, { childList: true, subtree: true })
|
|
142
|
-
return () => {
|
|
143
|
-
observer.disconnect()
|
|
144
|
-
}
|
|
145
|
-
}, [syncPanelOrder])
|
|
146
|
-
|
|
147
|
-
useLayoutEffect(() => {
|
|
148
|
-
syncPanelOrder()
|
|
149
|
-
}, [syncPanelOrder, panels])
|
|
150
|
-
|
|
151
|
-
const panelSizes = useMemo(() => panels.map((panel) => panel.size), [panels])
|
|
152
|
-
const hasMeasuredContainer = layout.containerSize > 0
|
|
153
|
-
|
|
154
|
-
useLayoutEffect(() => {
|
|
155
|
-
// 未計測の 0 配列を通知しない。配分はコンテナ計測後に一度で確定するため、通知は常に確定値になる
|
|
156
|
-
if (!hasMeasuredContainer || panelSizes.length === 0) {
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
layoutCallbackRef.current?.(panelSizes)
|
|
160
|
-
}, [panelSizes, hasMeasuredContainer])
|
|
161
|
-
|
|
162
|
-
const restoredKeyRef = useRef<string | null>(null)
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
// 保存済みレイアウトは識別子ごとに一度だけ適用する
|
|
165
|
-
// (識別子が変われば、その識別子で保存された配置を読み直す)
|
|
166
|
-
if (!autoSaveId || restoredKeyRef.current === autoSaveId || !hasMeasuredContainer || panels.length === 0) {
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
restoredKeyRef.current = autoSaveId
|
|
170
|
-
const entries = loadLayout(autoSaveId)
|
|
171
|
-
if (entries) {
|
|
172
|
-
dispatch({ type: "RESTORE_LAYOUT", entries })
|
|
173
|
-
}
|
|
174
|
-
}, [autoSaveId, hasMeasuredContainer, panels.length])
|
|
175
|
-
|
|
176
|
-
const pendingSaveRef = useRef<{ id: string; entries: PersistedPanelSize[] } | null>(null)
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
if (!(autoSaveId && restoredKeyRef.current === autoSaveId && hasMeasuredContainer) || panels.length === 0) {
|
|
179
|
-
return
|
|
180
|
-
}
|
|
181
|
-
const entries = panels.map((panel) => ({ id: panel.id, size: getPanelPreferenceInPixels(panel, layout.containerSize), collapsed: panel.collapsed }))
|
|
182
|
-
pendingSaveRef.current = { id: autoSaveId, entries }
|
|
183
|
-
const timer = setTimeout(() => {
|
|
184
|
-
pendingSaveRef.current = null
|
|
185
|
-
saveLayout(autoSaveId, entries)
|
|
186
|
-
}, AUTO_SAVE_DELAY_MS)
|
|
187
|
-
// ここで保存まで行うと、ドラッグやリサイズの 1 フレームごとに同期 I/O が走り、待機時間が無意味になる
|
|
188
|
-
return () => {
|
|
189
|
-
clearTimeout(timer)
|
|
190
|
-
}
|
|
191
|
-
}, [autoSaveId, panels, layout.containerSize, hasMeasuredContainer])
|
|
192
|
-
|
|
193
|
-
useEffect(() => {
|
|
194
|
-
// 書き出し前に画面を離れた場合でも最後の配置を残す (遷移直前に動かした幅が消えないように)
|
|
195
|
-
return () => {
|
|
196
|
-
const pending = pendingSaveRef.current
|
|
197
|
-
if (pending) {
|
|
198
|
-
pendingSaveRef.current = null
|
|
199
|
-
saveLayout(pending.id, pending.entries)
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}, [])
|
|
203
|
-
|
|
204
|
-
const registerPanel = useCallback((panel: PanelRegistration) => {
|
|
205
|
-
// 同一内容の再登録は状態を触らない。props が変わっていないのに希望値を配り直すと、
|
|
206
|
-
// 直前のドラッグ結果を巻き戻してしまう
|
|
207
|
-
const signature = JSON.stringify(panel)
|
|
208
|
-
if (registrationSignaturesRef.current[panel.id] === signature) {
|
|
209
|
-
return
|
|
210
|
-
}
|
|
211
|
-
registrationSignaturesRef.current[panel.id] = signature
|
|
212
|
-
dispatch({ type: "REGISTER_PANEL", panel })
|
|
213
|
-
}, [])
|
|
214
|
-
|
|
215
|
-
const unregisterPanel = useCallback((id: string) => {
|
|
216
|
-
delete registrationSignaturesRef.current[id]
|
|
217
|
-
dispatch({ type: "UNREGISTER_PANEL", id })
|
|
218
|
-
setPanelMeasurements((previous) => {
|
|
219
|
-
if (!(id in previous)) {
|
|
220
|
-
return previous
|
|
221
|
-
}
|
|
222
|
-
const next = { ...previous }
|
|
223
|
-
delete next[id]
|
|
224
|
-
return next
|
|
225
|
-
})
|
|
226
|
-
}, [])
|
|
227
|
-
|
|
228
|
-
const resizePanels = useCallback((startId: string, endId: string, startSize: number) => {
|
|
229
|
-
dispatch({ type: "RESIZE_PANELS", startId, endId, startSize })
|
|
230
|
-
}, [])
|
|
231
|
-
|
|
232
|
-
const collapsePanel = useCallback((id: string, from: PanelCollapseDirection) => {
|
|
233
|
-
dispatch({ type: "COLLAPSE_PANEL", id, from })
|
|
234
|
-
}, [])
|
|
235
|
-
|
|
236
|
-
const expandPanel = useCallback((id: string, from: PanelCollapseDirection, targetSize?: number) => {
|
|
237
|
-
dispatch({ type: "EXPAND_PANEL", id, from, targetSize })
|
|
238
|
-
}, [])
|
|
239
|
-
|
|
240
|
-
const getPanel = useCallback((id: string) => panels.find((panel) => panel.id === id), [panels])
|
|
241
|
-
|
|
242
|
-
const reportPanelMeasurement = useCallback((panelId: string, measurement: PanelMeasurement | null) => {
|
|
243
|
-
setPanelMeasurements((previous) => {
|
|
244
|
-
if (measurement === null) {
|
|
245
|
-
if (!(panelId in previous)) {
|
|
246
|
-
return previous
|
|
247
|
-
}
|
|
248
|
-
const next = { ...previous }
|
|
249
|
-
delete next[panelId]
|
|
250
|
-
return next
|
|
251
|
-
}
|
|
252
|
-
const current = previous[panelId]
|
|
253
|
-
if (current && current.pixelSize === measurement.pixelSize && current.percentageSize === measurement.percentageSize) {
|
|
254
|
-
return previous
|
|
255
|
-
}
|
|
256
|
-
return { ...previous, [panelId]: measurement }
|
|
257
|
-
})
|
|
258
|
-
}, [])
|
|
259
|
-
|
|
260
|
-
const reportHandleMeasurement = useCallback((handleId: string, measurement: ResizeHandleLayoutData | null) => {
|
|
261
|
-
setHandleMeasurements((previous) => {
|
|
262
|
-
if (measurement === null) {
|
|
263
|
-
if (!(handleId in previous)) {
|
|
264
|
-
return previous
|
|
265
|
-
}
|
|
266
|
-
const next = { ...previous }
|
|
267
|
-
delete next[handleId]
|
|
268
|
-
return next
|
|
269
|
-
}
|
|
270
|
-
const current = previous[handleId]
|
|
271
|
-
if (current && current.thickness === measurement.thickness && current.visible === measurement.visible && current.direction === measurement.direction && current.startPanelId === measurement.startPanelId && current.endPanelId === measurement.endPanelId) {
|
|
272
|
-
return previous
|
|
273
|
-
}
|
|
274
|
-
return { ...previous, [handleId]: measurement }
|
|
275
|
-
})
|
|
276
|
-
}, [])
|
|
277
|
-
|
|
278
|
-
const contextValue = useMemo(
|
|
279
|
-
() => ({
|
|
280
|
-
direction,
|
|
281
|
-
panels,
|
|
282
|
-
containerSize: layout.containerSize,
|
|
283
|
-
layoutOrderKey,
|
|
284
|
-
showDebugInfo,
|
|
285
|
-
registerPanel,
|
|
286
|
-
unregisterPanel,
|
|
287
|
-
resizePanels,
|
|
288
|
-
collapsePanel,
|
|
289
|
-
expandPanel,
|
|
290
|
-
getPanel,
|
|
291
|
-
reportPanelMeasurement,
|
|
292
|
-
panelMeasurements,
|
|
293
|
-
reportHandleMeasurement,
|
|
294
|
-
handleMeasurements,
|
|
295
|
-
layoutConstraintViolation: layout.violation,
|
|
296
|
-
}),
|
|
297
|
-
[direction, panels, layout.containerSize, layoutOrderKey, layout.violation, showDebugInfo, registerPanel, unregisterPanel, resizePanels, collapsePanel, expandPanel, getPanel, reportPanelMeasurement, panelMeasurements, reportHandleMeasurement, handleMeasurements],
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
const groupStyle: CSSProperties = useMemo(
|
|
301
|
-
() => ({
|
|
302
|
-
// 見た目に関わる既定値は利用者が上書きできる
|
|
303
|
-
width: "100%",
|
|
304
|
-
height: "100%",
|
|
305
|
-
minWidth: "0px",
|
|
306
|
-
minHeight: "0px",
|
|
307
|
-
// ハンドルは境界をまたいで描かれるため、その張り出しでスクロールバーを出さない
|
|
308
|
-
overflow: "hidden",
|
|
309
|
-
...style,
|
|
310
|
-
// ここから下はレイアウトの前提そのもの。利用者のスタイルやクラスで変わると
|
|
311
|
-
// 配分結果と描画が一致しなくなるため、最後に適用して上書きを受け付けない:
|
|
312
|
-
// gap はパネルの合計に含まれない隙間を作り、flex-direction の反転は DOM 順と視覚順をずらし、
|
|
313
|
-
// writing-mode は主軸の向きそのものを変えてしまう
|
|
314
|
-
display: "flex",
|
|
315
|
-
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
316
|
-
alignItems: "stretch",
|
|
317
|
-
gap: "0px",
|
|
318
|
-
position: "relative",
|
|
319
|
-
boxSizing: "border-box",
|
|
320
|
-
writingMode: "horizontal-tb",
|
|
321
|
-
}),
|
|
322
|
-
[direction, style],
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
return { groupRef, contextValue, groupStyle }
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Provide imperative helpers for toggling a specific panel while preserving its stored preference.
|
|
330
|
-
* 特定パネルの希望値を保ったまま開閉を制御する命令型ユーティリティを提供するカスタムフック。
|
|
331
|
-
*
|
|
332
|
-
* @param panelId - Identifier of the panel to control / 操作対象パネルの識別子
|
|
333
|
-
* @returns Panel state and collapse/expand/toggle helpers / パネル状態と開閉ヘルパー
|
|
334
|
-
*/
|
|
335
|
-
export const usePanelControls = (panelId: string) => {
|
|
336
|
-
const { getPanel, collapsePanel, expandPanel } = usePanelGroup()
|
|
337
|
-
const panel = getPanel(panelId)
|
|
338
|
-
|
|
339
|
-
const collapse = useCallback(
|
|
340
|
-
(from: PanelCollapseDirection) => {
|
|
341
|
-
collapsePanel(panelId, from)
|
|
342
|
-
},
|
|
343
|
-
[collapsePanel, panelId],
|
|
344
|
-
)
|
|
345
|
-
|
|
346
|
-
const expand = useCallback(
|
|
347
|
-
(from: PanelCollapseDirection, targetSize?: number) => {
|
|
348
|
-
expandPanel(panelId, from, targetSize)
|
|
349
|
-
},
|
|
350
|
-
[expandPanel, panelId],
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
const toggle = useCallback(
|
|
354
|
-
(from: PanelCollapseDirection, targetSize?: number) => {
|
|
355
|
-
if (panel?.collapsed) {
|
|
356
|
-
expand(from, targetSize)
|
|
357
|
-
} else {
|
|
358
|
-
collapse(from)
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
[panel?.collapsed, collapse, expand],
|
|
362
|
-
)
|
|
363
|
-
|
|
364
|
-
return useMemo(
|
|
365
|
-
() => ({
|
|
366
|
-
panel,
|
|
367
|
-
isCollapsed: panel?.collapsed ?? false,
|
|
368
|
-
canCollapseFromStart: panel?.collapseFromStart ?? false,
|
|
369
|
-
canCollapseFromEnd: panel?.collapseFromEnd ?? false,
|
|
370
|
-
collapse,
|
|
371
|
-
expand,
|
|
372
|
-
toggle,
|
|
373
|
-
}),
|
|
374
|
-
[panel, collapse, expand, toggle],
|
|
375
|
-
)
|
|
376
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @package @aiquants/resize-panels
|
|
3
|
-
* @description Reusable resizable panel components and utilities for React
|
|
4
|
-
*
|
|
5
|
-
* 再利用可能なリサイズパネルコンポーネントとユーティリティ
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export type { LayoutAllocation, PanelBounds } from "./allocateLayout"
|
|
9
|
-
export { allocatePanelSizes, isPixelPanel, resolvePanelBounds } from "./allocateLayout"
|
|
10
|
-
export { PanelGroupContext, usePanelGroup } from "./context"
|
|
11
|
-
export { usePanelControls, useResizablePanels } from "./hooks"
|
|
12
|
-
export { Panel } from "./Panel"
|
|
13
|
-
export { PanelGroup } from "./PanelGroup"
|
|
14
|
-
export { PanelResizeHandle } from "./PanelResizeHandle"
|
|
15
|
-
export { findLayoutInvariantBreach, getPanelPreferenceInPixels, initialPanelGroupLayoutState, panelReducer } from "./reducer"
|
|
16
|
-
export type {
|
|
17
|
-
CollapsibleConfig,
|
|
18
|
-
CollapsibleDirection,
|
|
19
|
-
ContainerAxisMeasurement,
|
|
20
|
-
FlexibleSize,
|
|
21
|
-
LayoutConstraintViolation,
|
|
22
|
-
LayoutConstraintViolationReason,
|
|
23
|
-
PanelAction,
|
|
24
|
-
PanelCollapseDirection,
|
|
25
|
-
PanelDirection,
|
|
26
|
-
PanelGroupContextValue,
|
|
27
|
-
PanelGroupLayoutState,
|
|
28
|
-
PanelGroupProps,
|
|
29
|
-
PanelLayoutData,
|
|
30
|
-
PanelMeasurement,
|
|
31
|
-
PanelProps,
|
|
32
|
-
PanelRegistration,
|
|
33
|
-
PanelResizeHandleIndicatorConfig,
|
|
34
|
-
PanelResizeHandleProps,
|
|
35
|
-
PersistedPanelSize,
|
|
36
|
-
ResizeHandleLayoutData,
|
|
37
|
-
SizeConfig,
|
|
38
|
-
SizeUnit,
|
|
39
|
-
} from "./types"
|
|
40
|
-
export {
|
|
41
|
-
calculateSnapThreshold,
|
|
42
|
-
clamp,
|
|
43
|
-
findOwningGroup,
|
|
44
|
-
getConstraintInPixels,
|
|
45
|
-
getContainerSize,
|
|
46
|
-
getGroupLayoutElements,
|
|
47
|
-
loadLayout,
|
|
48
|
-
normalizeSizeConfig,
|
|
49
|
-
percentageToPixels,
|
|
50
|
-
saveLayout,
|
|
51
|
-
toRoundedPercentage,
|
|
52
|
-
} from "./utils"
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Safely escape a selector identifier for use in CSS query selectors.
|
|
56
|
-
* セレクタ文字列を安全にエスケープする補助関数。
|
|
57
|
-
*/
|
|
58
|
-
const escapeIdentifier = (id: string): string => {
|
|
59
|
-
return typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(id) : id.replace(/["\\]/g, "\\$&")
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Locate a panel element in the DOM by its data attribute.
|
|
64
|
-
* data 属性を手がかりにパネル要素を DOM から取得する補助関数。
|
|
65
|
-
*/
|
|
66
|
-
export const getPanelElement = (id: string): HTMLElement | null => {
|
|
67
|
-
if (typeof document === "undefined") {
|
|
68
|
-
return null
|
|
69
|
-
}
|
|
70
|
-
return document.querySelector(`[data-panel-id="${escapeIdentifier(id)}"]`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Locate a panel group element in the DOM by its data attribute.
|
|
75
|
-
* data 属性を手がかりにパネルグループ要素を DOM から取得する補助関数。
|
|
76
|
-
*/
|
|
77
|
-
export const getPanelGroupElement = (id: string): HTMLElement | null => {
|
|
78
|
-
if (typeof document === "undefined") {
|
|
79
|
-
return null
|
|
80
|
-
}
|
|
81
|
-
return document.querySelector(`[data-panel-group-id="${escapeIdentifier(id)}"]`)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Locate a resize handle element in the DOM by its data attribute.
|
|
86
|
-
* data 属性を手がかりにリサイズハンドル要素を DOM から取得する補助関数。
|
|
87
|
-
*/
|
|
88
|
-
export const getResizeHandleElement = (id: string): HTMLElement | null => {
|
|
89
|
-
if (typeof document === "undefined") {
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
92
|
-
return document.querySelector(`[data-resize-handle-id="${escapeIdentifier(id)}"]`)
|
|
93
|
-
}
|