@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.
Files changed (64) hide show
  1. package/dist/GlobalDebugOverlay.d.ts +4 -0
  2. package/dist/Panel.d.ts +13 -0
  3. package/dist/{src/PanelDebugInfo.d.ts → PanelDebugInfo.d.ts} +2 -14
  4. package/dist/PanelGroup.d.ts +2 -0
  5. package/dist/PanelResizeHandle.d.ts +2 -0
  6. package/dist/allocateLayout.d.ts +12 -0
  7. package/dist/context.d.ts +3 -0
  8. package/dist/debugOverlayStore.d.ts +32 -0
  9. package/dist/{src/hooks.d.ts → hooks.d.ts} +8 -23
  10. package/dist/index.d.ts +13 -2
  11. package/dist/reducer.d.ts +8 -0
  12. package/dist/roundHalfToEven.d.ts +1 -0
  13. package/dist/types.d.ts +183 -0
  14. package/dist/utils/simple-logger.d.ts +37 -0
  15. package/dist/utils.d.ts +16 -0
  16. package/package.json +2 -3
  17. package/dist/src/GlobalDebugOverlay.d.ts +0 -21
  18. package/dist/src/GlobalDebugOverlay.d.ts.map +0 -1
  19. package/dist/src/Panel.d.ts +0 -46
  20. package/dist/src/Panel.d.ts.map +0 -1
  21. package/dist/src/PanelDebugInfo.d.ts.map +0 -1
  22. package/dist/src/PanelGroup.d.ts +0 -7
  23. package/dist/src/PanelGroup.d.ts.map +0 -1
  24. package/dist/src/PanelResizeHandle.d.ts +0 -7
  25. package/dist/src/PanelResizeHandle.d.ts.map +0 -1
  26. package/dist/src/allocateLayout.d.ts +0 -60
  27. package/dist/src/allocateLayout.d.ts.map +0 -1
  28. package/dist/src/context.d.ts +0 -12
  29. package/dist/src/context.d.ts.map +0 -1
  30. package/dist/src/debugOverlayStore.d.ts +0 -69
  31. package/dist/src/debugOverlayStore.d.ts.map +0 -1
  32. package/dist/src/hooks.d.ts.map +0 -1
  33. package/dist/src/index.d.ts +0 -32
  34. package/dist/src/index.d.ts.map +0 -1
  35. package/dist/src/reducer.d.ts +0 -49
  36. package/dist/src/reducer.d.ts.map +0 -1
  37. package/dist/src/roundHalfToEven.d.ts +0 -10
  38. package/dist/src/roundHalfToEven.d.ts.map +0 -1
  39. package/dist/src/types.d.ts +0 -481
  40. package/dist/src/types.d.ts.map +0 -1
  41. package/dist/src/utils/simple-logger.d.ts +0 -111
  42. package/dist/src/utils/simple-logger.d.ts.map +0 -1
  43. package/dist/src/utils.d.ts +0 -164
  44. package/dist/src/utils.d.ts.map +0 -1
  45. package/dist/tests/support/dom-harness.d.ts +0 -89
  46. package/dist/tests/support/dom-harness.d.ts.map +0 -1
  47. package/src/GlobalDebugOverlay.tsx +0 -284
  48. package/src/Panel.tsx +0 -297
  49. package/src/PanelDebugInfo.tsx +0 -94
  50. package/src/PanelGroup.tsx +0 -245
  51. package/src/PanelResizeHandle.tsx +0 -758
  52. package/src/allocateLayout.ts +0 -412
  53. package/src/context.ts +0 -25
  54. package/src/debugOverlayStore.ts +0 -355
  55. package/src/hooks.ts +0 -376
  56. package/src/index.ts +0 -93
  57. package/src/reducer.ts +0 -472
  58. package/src/roundHalfToEven.ts +0 -40
  59. package/src/styles/components.entry.css +0 -10
  60. package/src/styles/resize-panels.css +0 -1
  61. package/src/styles/standalone.entry.css +0 -12
  62. package/src/types.ts +0 -505
  63. package/src/utils/simple-logger.ts +0 -186
  64. package/src/utils.ts +0 -320
@@ -1,245 +0,0 @@
1
- /**
2
- * @file PanelGroup component for custom resizable panels
3
- * カスタムリサイズ可能パネルのための PanelGroup コンポーネント
4
- */
5
-
6
- import { lazy, Suspense, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
7
- import { twMerge } from "tailwind-merge"
8
- import { PanelGroupContext } from "./context"
9
- import type { DebugPanelSnapshot } from "./debugOverlayStore"
10
- import { useResizablePanels } from "./hooks"
11
- import type { PanelGroupProps, PanelLayoutData } from "./types"
12
- import { getContainerSize } from "./utils"
13
-
14
- // デバッグオーバーレイ (UI とストア) は dynamic import で遅延読み込みする。
15
- // showDebugInfo を使わないアプリのバンドルへオーバーレイ一式を含めず、ストア購読も発生させないための分離
16
- const LazyDebugOverlayGate = lazy(() => import("./GlobalDebugOverlay").then((module) => ({ default: module.GlobalDebugOverlayGate })))
17
-
18
- type DebugOverlayStoreModule = typeof import("./debugOverlayStore")
19
-
20
- /** Stable empty collections used while the debug overlay is off. デバッグ表示が無効な間に使う不変の空コレクション。 */
21
- const EMPTY_PANELS: ReadonlyArray<PanelLayoutData> = []
22
- const EMPTY_MEASUREMENTS: Record<string, never> = {}
23
-
24
- let debugGroupIdCounter = 0
25
-
26
- /**
27
- * Generate unique debug group identifier for panel groups without explicit IDs.
28
- * 明示的な ID を持たないパネルグループ用の一意なデバッググループ識別子を生成。
29
- */
30
- const generateDebugGroupId = () => {
31
- debugGroupIdCounter += 1
32
- return `panel-group-${debugGroupIdCounter}`
33
- }
34
-
35
- type ResizablePanelsContextValue = ReturnType<typeof useResizablePanels>["contextValue"]
36
- type LayoutConstraintViolation = NonNullable<ResizablePanelsContextValue["layoutConstraintViolation"]>
37
- type DebugPanelMeasurementMap = ResizablePanelsContextValue["panelMeasurements"]
38
-
39
- /**
40
- * Builds summary and detail labels for layout constraint placeholders.
41
- * レイアウト制約プレースホルダー用のサマリーと詳細ラベルを生成。
42
- */
43
- const buildConstraintCopy = (violation: LayoutConstraintViolation) => {
44
- const isMinimum = violation.reason === "minimum-exceeded"
45
- const summary = isMinimum ? "Layout unavailable: minimum panel sizes exceed the container." : "Layout unavailable: panels cannot fill the container with their maximum sizes."
46
- const detail = isMinimum ? `Min required: ${Math.ceil(violation.totalMinimumSize)}px | Available: ${Math.floor(violation.availableContainerSize)}px` : `Max total: ${Math.floor(violation.totalMaximumSize)}px | Needed: ${Math.floor(violation.availableContainerSize)}px`
47
- return { summary, detail }
48
- }
49
-
50
- /**
51
- * Synchronizes measured panel dimensions into overlay panel descriptors.
52
- * 測定済みパネル寸法をオーバーレイ用パネル情報へ同期。
53
- */
54
- const mergePanelMeasurements = (panels: ReadonlyArray<PanelLayoutData>, measurementMap: DebugPanelMeasurementMap): DebugPanelSnapshot[] =>
55
- panels.map((panel) => {
56
- const measurement = measurementMap[panel.id]
57
- if (!measurement) {
58
- return panel
59
- }
60
- return { ...panel, measuredPixelSize: measurement.pixelSize, measuredPercentageSize: measurement.percentageSize }
61
- })
62
-
63
- /**
64
- * Measures overlay container dimensions with graceful fallbacks.
65
- * フォールバックを考慮しつつオーバーレイ用コンテナ寸法を計測。
66
- */
67
- const measureDebugOverlayContainerSize = (element: HTMLElement, fallbackWidth?: number, fallbackHeight?: number) => {
68
- const horizontal = getContainerSize(element, "horizontal")
69
- const vertical = getContainerSize(element, "vertical")
70
- const rect = element.getBoundingClientRect()
71
- const width = horizontal.content > 0 ? horizontal.content : (fallbackWidth ?? rect.width)
72
- const height = vertical.content > 0 ? vertical.content : (fallbackHeight ?? rect.height)
73
- return { width, height }
74
- }
75
-
76
- /**
77
- * Provide layout context and container for coordinated panels.
78
- * 連動するパネルのためのレイアウトコンテキストとコンテナを提供するコンポーネント。
79
- */
80
- export const PanelGroup = (props: PanelGroupProps) => {
81
- const { id, className, style, children, direction, onLayout, autoSaveId, showDebugInfo, ...elementProps } = props
82
- const { groupRef, contextValue, groupStyle } = useResizablePanels(props)
83
-
84
- const [debugOverlayContainerSize, setDebugOverlayContainerSize] = useState({ width: 0, height: 0 })
85
-
86
- const constraintViolation = contextValue.layoutConstraintViolation
87
- const shouldRenderPlaceholder = Boolean(constraintViolation)
88
- const placeholderInner = useMemo(() => {
89
- if (!constraintViolation) {
90
- return null
91
- }
92
- const { summary, detail } = buildConstraintCopy(constraintViolation)
93
- return (
94
- <div
95
- className="flex w-full flex-1 flex-col items-center justify-center gap-2 rounded-lg border border-slate-300 border-dashed bg-slate-100/70 px-6 py-8 text-center text-slate-600 text-sm dark:border-slate-600 dark:bg-slate-800/50 dark:text-slate-200"
96
- data-panel-group-placeholder="constraint-violation">
97
- <span>{summary}</span>
98
- <span className="text-slate-500 text-xs dark:text-slate-400">{detail}</span>
99
- </div>
100
- )
101
- }, [constraintViolation])
102
-
103
- // useRef の引数は毎レンダー評価されるため、そこで採番するとレンダーが純粋でなくなる
104
- const debugGroupIdRef = useRef<string | null>(null)
105
- if (debugGroupIdRef.current === null) {
106
- debugGroupIdRef.current = id ?? generateDebugGroupId()
107
- }
108
- const debugGroupId = debugGroupIdRef.current
109
- const debugDisplayName = id ?? debugGroupId
110
-
111
- const shouldShowDebugOverlay = contextValue.showDebugInfo && contextValue.panels.length > 0
112
- // 無効時に空のリテラルを作ると参照が毎レンダー変わり、下流の useMemo が無駄に再計算される
113
- const debugOverlayPanels = shouldShowDebugOverlay ? contextValue.panels : EMPTY_PANELS
114
- const debugOverlayMeasurementMap = shouldShowDebugOverlay ? contextValue.panelMeasurements : EMPTY_MEASUREMENTS
115
- const debugOverlayHandles = useMemo(() => {
116
- if (!shouldShowDebugOverlay) {
117
- return []
118
- }
119
- const handles = Object.values(contextValue.handleMeasurements)
120
- if (handles.length <= 1) {
121
- return handles
122
- }
123
- return handles.slice().sort((a, b) => a.id.localeCompare(b.id))
124
- }, [contextValue.handleMeasurements, shouldShowDebugOverlay])
125
- const debugOverlayContainerWidth = debugOverlayContainerSize.width
126
- const debugOverlayContainerHeight = debugOverlayContainerSize.height
127
-
128
- useLayoutEffect(() => {
129
- // shouldShowDebugOverlay と groupRef に応じてデバッグオーバーレイ用コンテナ寸法を監視
130
- if (!shouldShowDebugOverlay) {
131
- setDebugOverlayContainerSize({ width: 0, height: 0 })
132
- return
133
- }
134
- if (typeof window === "undefined" || typeof ResizeObserver === "undefined") {
135
- return
136
- }
137
- const element = groupRef.current
138
- if (!element) {
139
- return
140
- }
141
- const updateSize = (nextSize: { width: number; height: number }) => {
142
- setDebugOverlayContainerSize((previous) => (previous.width === nextSize.width && previous.height === nextSize.height ? previous : nextSize))
143
- }
144
- const observer = new ResizeObserver((entries) => {
145
- for (const entry of entries) {
146
- if (entry.target !== element) {
147
- continue
148
- }
149
- const nextSize = measureDebugOverlayContainerSize(element, entry.contentRect.width, entry.contentRect.height)
150
- updateSize(nextSize)
151
- }
152
- })
153
- observer.observe(element)
154
- updateSize(measureDebugOverlayContainerSize(element))
155
- return () => {
156
- observer.disconnect()
157
- }
158
- }, [groupRef, shouldShowDebugOverlay])
159
-
160
- const debugOverlayPanelsWithMeasurements = useMemo(() => mergePanelMeasurements(debugOverlayPanels, debugOverlayMeasurementMap), [debugOverlayPanels, debugOverlayMeasurementMap])
161
-
162
- useEffect(() => {
163
- // shouldShowDebugOverlay と debugGroupId に応じてデバッグオーバーレイ有効状態を同期
164
- // ストアは遅延読み込みのため、有効化されるまで import しない (未読込なら解除処理も不要)
165
- if (!shouldShowDebugOverlay) {
166
- return
167
- }
168
-
169
- let cancelled = false
170
- let loadedStore: DebugOverlayStoreModule | null = null
171
- import("./debugOverlayStore").then((storeModule) => {
172
- if (cancelled) {
173
- return
174
- }
175
- loadedStore = storeModule
176
- storeModule.enableDebugOverlayGroup(debugGroupId)
177
- })
178
-
179
- return () => {
180
- cancelled = true
181
- if (loadedStore) {
182
- loadedStore.disableDebugOverlayGroup(debugGroupId)
183
- loadedStore.removeDebugOverlayGroup(debugGroupId)
184
- }
185
- }
186
- }, [shouldShowDebugOverlay, debugGroupId])
187
-
188
- useEffect(() => {
189
- // 依存配列の変化ごとに最新のオーバーレイ集計をストアへ送出
190
- if (!shouldShowDebugOverlay) {
191
- return
192
- }
193
-
194
- let cancelled = false
195
- import("./debugOverlayStore").then((storeModule) => {
196
- if (cancelled) {
197
- return
198
- }
199
- storeModule.updateDebugOverlayGroup(debugGroupId, {
200
- displayName: debugDisplayName,
201
- direction,
202
- containerSize: {
203
- width: debugOverlayContainerWidth,
204
- height: debugOverlayContainerHeight,
205
- },
206
- panels: debugOverlayPanelsWithMeasurements,
207
- handles: debugOverlayHandles,
208
- })
209
- })
210
- return () => {
211
- cancelled = true
212
- }
213
- }, [shouldShowDebugOverlay, debugGroupId, debugDisplayName, direction, debugOverlayContainerWidth, debugOverlayContainerHeight, debugOverlayPanelsWithMeasurements, debugOverlayHandles])
214
-
215
- return (
216
- <PanelGroupContext.Provider value={contextValue}>
217
- <div {...elementProps} ref={groupRef} className={twMerge("panel-group", direction === "horizontal" ? "flex-row" : "flex-col", className)} style={groupStyle} data-panel-group-id={id} data-panel-group-direction={direction}>
218
- {children}
219
- {shouldRenderPlaceholder && placeholderInner ? (
220
- <div
221
- className="pointer-events-auto"
222
- style={{
223
- position: "absolute",
224
- inset: 0,
225
- // パネル内部要素 (VirtualScroll のスクロールバー z-50 等) を完全に隠蔽するため zIndex を 60 に設定
226
- zIndex: 60,
227
- display: "flex",
228
- flexDirection: "column",
229
- alignItems: "center",
230
- justifyContent: "center",
231
- backgroundColor: "rgba(248, 250, 252, 0.82)",
232
- backdropFilter: "blur(2px)",
233
- }}>
234
- {placeholderInner}
235
- </div>
236
- ) : null}
237
- </div>
238
- {shouldShowDebugOverlay && (
239
- <Suspense fallback={null}>
240
- <LazyDebugOverlayGate groupId={debugGroupId} />
241
- </Suspense>
242
- )}
243
- </PanelGroupContext.Provider>
244
- )
245
- }