@aiquants/drag-drop-panels 0.7.2 → 0.8.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.
Files changed (33) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -10
  3. package/dist/drag-drop/hooks/useCustomDragHandlers.d.ts.map +1 -1
  4. package/dist/index.es.js +88 -88
  5. package/dist/index.umd.js +2 -2
  6. package/dist/styles/drag-drop-panels.standalone.css +3 -0
  7. package/package.json +11 -4
  8. package/src/DragDropLayout.tsx +751 -0
  9. package/src/drag-drop/ColumnControlPanel.tsx +123 -0
  10. package/src/drag-drop/ColumnInsertPanel.tsx +106 -0
  11. package/src/drag-drop/DebugComponents.tsx +222 -0
  12. package/src/drag-drop/DebugControlPanel.tsx +200 -0
  13. package/src/drag-drop/DebugOverlay.tsx +250 -0
  14. package/src/drag-drop/DragDropLayout.css +130 -0
  15. package/src/drag-drop/ResizeHandle.tsx +208 -0
  16. package/src/drag-drop/ResponsiveControl.tsx +33 -0
  17. package/src/drag-drop/hooks/dragGhostScale.spec.tsx +153 -0
  18. package/src/drag-drop/hooks/useColumnLayout.ts +457 -0
  19. package/src/drag-drop/hooks/useCustomDragHandlers.tsx +333 -0
  20. package/src/drag-drop/hooks/useDragDropColumns.tsx +446 -0
  21. package/src/drag-drop/hooks/useDragDropState.tsx +200 -0
  22. package/src/drag-drop/hooks/useFitScale.ts +48 -0
  23. package/src/drag-drop/hooks/useMouseTracking.tsx +102 -0
  24. package/src/drag-drop/hooks/useNormalDragHandlers.tsx +427 -0
  25. package/src/drag-drop/hooks/usePanelManagement.tsx +238 -0
  26. package/src/drag-drop/hooks/useResponsiveColumns.ts +210 -0
  27. package/src/drag-drop/resize-handle.css +71 -0
  28. package/src/drag-drop/types.ts +248 -0
  29. package/src/drag-drop/utils/columnIdUtils.ts +104 -0
  30. package/src/drag-drop/utils/edgeScrollUtils.ts +124 -0
  31. package/src/drag-drop/utils/simple-logger.ts +162 -0
  32. package/src/index.ts +60 -0
  33. package/src/styles/standalone.entry.css +27 -0
@@ -0,0 +1,248 @@
1
+ /**
2
+ * ドラッグ&ドロップ機能の型定義
3
+ * DragDropLayout と useDragDropColumns で共通で使用される型を統合して定義
4
+ */
5
+
6
+ import type { ComponentType, DragEvent, MouseEvent, RefObject, TouchEvent } from "react"
7
+
8
+ export interface ElementWithResizeObserver extends HTMLElement {
9
+ __resizeObserver?: ResizeObserver
10
+ }
11
+
12
+ export type ReactMouseEvent = import("react").MouseEvent<Element>
13
+ export type ReactDragEvent = import("react").DragEvent<Element>
14
+ export type ReactTouchEvent = import("react").TouchEvent<Element>
15
+
16
+ export type DOMMouseEvent = globalThis.MouseEvent
17
+ export type DOMDragEvent = globalThis.DragEvent
18
+ export type DOMTouchEvent = globalThis.TouchEvent
19
+
20
+ export interface DebugConfig {
21
+ showDebugPanel?: boolean
22
+ showMousePosition?: boolean
23
+ showPanelSizes?: boolean
24
+ showPlaceholderInfo?: boolean
25
+ showDropZoneOutlines?: boolean
26
+ logLevel?: 0 | 1 | 2
27
+ }
28
+
29
+ export const DEFAULT_DEBUG_CONFIG: Required<DebugConfig> = {
30
+ showDebugPanel: false,
31
+ showMousePosition: false,
32
+ showPanelSizes: false,
33
+ showPlaceholderInfo: false,
34
+ showDropZoneOutlines: false,
35
+ logLevel: 0,
36
+ }
37
+
38
+ export interface DragOverPosition {
39
+ columnIndex: number
40
+ insertIndex: number
41
+ }
42
+
43
+ export interface OriginalPanelPosition {
44
+ columnIndex: number
45
+ panelIndex: number
46
+ }
47
+
48
+ export interface DragState {
49
+ isDragging: boolean
50
+ draggedPanel: string | null
51
+ dragOverColumn: number | null
52
+ }
53
+
54
+ export interface ColumnConfig {
55
+ id: string
56
+ key: string
57
+ minWidth?: number
58
+ maxWidth?: number
59
+ className?: string
60
+ label?: string
61
+ title?: string
62
+ initialWidth?: number
63
+ resizable?: boolean
64
+ }
65
+
66
+ export interface PanelConfig {
67
+ id: string
68
+ component: ComponentType<Record<string, unknown>>
69
+ title: string
70
+ props?: Record<string, unknown>
71
+ dragMode?: "normal" | "custom"
72
+ minHeight?: string
73
+ maxHeight?: string
74
+ }
75
+
76
+ export interface PanelSizeInfo {
77
+ width: number
78
+ height: number
79
+ x: number
80
+ y: number
81
+ minHeight: string
82
+ maxHeight: string
83
+ }
84
+
85
+ export interface TouchDragState {
86
+ isTouchDragging: boolean
87
+ panelId?: string | null
88
+ startX: number
89
+ startY: number
90
+ currentX: number
91
+ currentY: number
92
+ draggedElement: HTMLElement | null
93
+ }
94
+
95
+ export interface ClickState {
96
+ isClicked: boolean
97
+ panelId: string | null
98
+ }
99
+
100
+ export interface MousePosition {
101
+ x: number
102
+ y: number
103
+ isVisible: boolean
104
+ }
105
+
106
+ export interface CustomDragState {
107
+ isActive: boolean
108
+ panelId: string
109
+ startX: number
110
+ startY: number
111
+ }
112
+
113
+ export interface DragDropHookReturn {
114
+ dragState: DragState
115
+ dragOverPosition: DragOverPosition | null
116
+ originalPanelPosition: OriginalPanelPosition | null
117
+ touchDragState: TouchDragState
118
+ customDrag: CustomDragState
119
+ clickState: ClickState
120
+ mousePosition: MousePosition
121
+ dragModes: Record<string, "normal" | "custom">
122
+ panelSizes: Record<string, PanelSizeInfo>
123
+ handleDragStart: (e: ReactDragEvent, panelId: string) => void
124
+ handleDragEnd: (e: ReactDragEvent) => void
125
+ handleClick: (e: ReactMouseEvent, panelId: string) => void
126
+ handleMouseDown: (e: ReactMouseEvent, panelId: string) => void
127
+ handleTouchStart: (e: ReactTouchEvent, panelId: string) => void
128
+ handleTouchMove: (e: ReactTouchEvent) => void
129
+ handleTouchEnd: (e: ReactTouchEvent) => void
130
+ handlePlaceholderDragEnter: (columnIndex: number, insertIndex: number) => void
131
+ handlePlaceholderDragLeave: (e: ReactDragEvent, columnIndex: number, insertIndex: number) => void
132
+ toggleDragMode: (panelId: string) => void
133
+ setDragOverPosition: (position: DragOverPosition | null) => void
134
+ setPanelRef: (panelId: string, el: ElementWithResizeObserver | null) => void
135
+ findPanelPosition: (panelId: string) => OriginalPanelPosition | null
136
+ dragOverPositionRef: RefObject<DragOverPosition | null>
137
+ }
138
+
139
+ export interface DragDropEventHandlers {
140
+ onDragStart: (e: DragEvent<Element>, panelId: string) => void
141
+ onDragEnd: () => void
142
+ onPlaceholderDragEnter: (columnIndex: number, insertIndex: number) => void
143
+ onPlaceholderDragLeave: (e?: DragEvent<Element>, columnIndex?: number, insertIndex?: number) => void
144
+ onDragOverWithInsert: (e: DragEvent<Element>, columnIndex: number) => void
145
+ onDropWithInsert: (e: DragEvent<Element>, targetColumn: string) => void
146
+ onColumnDragLeave: (e: DragEvent<Element>) => void
147
+ onPanelClick?: (e: MouseEvent<Element>, panelId: string) => void
148
+ onPanelMouseDown?: (e: MouseEvent<Element>, panelId: string) => void
149
+ onTouchStart?: (e: TouchEvent<Element>, panelId: string) => void
150
+ onTouchMove?: (e: TouchEvent<Element>) => void
151
+ onTouchEnd?: (e: TouchEvent<Element>) => void
152
+ onPanelSizeInfoClick?: (e: MouseEvent<Element> | TouchEvent<Element>, panelId: string) => void
153
+ onToggleDragMode?: (panelId: string) => void
154
+ /**
155
+ * Optional close handler. When provided, the panel header shows an X button that the
156
+ * consumer uses to REMOVE the panel (unlike the EyeOff button, which only hides the
157
+ * panel into the restore bar).
158
+ *
159
+ * 指定時のみパネルヘッダに ✕(完全クローズ)ボタンを表示する。
160
+ * EyeOff(非表示 + 復元バー)とは別の「パネルを取り除く」意味論。
161
+ */
162
+ onPanelClose?: (panelId: string) => void
163
+ /**
164
+ * Optional maximize handler (controlled). When provided, the panel header shows a
165
+ * maximize/restore button and the panel whose id equals `maximizedPanel` is rendered
166
+ * as a viewport-filling fixed overlay (OS-window-like maximize). Called with the
167
+ * panelId to maximize, or null to restore. Escape and header double-click also restore.
168
+ *
169
+ * 指定時のみパネルヘッダに最大化/復元ボタンを表示する (制御型)。`maximizedPanel` に
170
+ * 一致するパネルはビューポート全面の fixed オーバーレイとして描画される (OS ウインドウの
171
+ * 最大化と同様)。最大化するときは panelId、復元するときは null で呼ばれる。
172
+ * Escape キーとヘッダのダブルクリックでも復元/最大化をトグルする。
173
+ */
174
+ onPanelMaximizeChange?: (panelId: string | null) => void
175
+ }
176
+
177
+ /**
178
+ * Where the HTML5 drag can be initiated from (dragMode "normal" only).
179
+ * - "panel" (default): the whole panel is draggable — current behavior.
180
+ * - "header": only the panel header is draggable, so text inside the panel body
181
+ * can be selected/copied (essential for document-viewer panels).
182
+ *
183
+ * HTML5 ドラッグの開始領域。"header" 指定でパネル本文のテキスト選択が可能になる
184
+ * (ドキュメントビューア用途で必須)。既定は従来どおり "panel" 全体。
185
+ */
186
+ export type PanelDragHandle = "panel" | "header"
187
+
188
+ export interface DragDropState {
189
+ columnPanels: Record<string, string[]>
190
+ panelVisibility: Record<string, boolean>
191
+ dragModes: Record<string, "normal" | "custom">
192
+ dragState: DragState
193
+ dragOverPosition: DragOverPosition | null
194
+ originalPanelPosition: OriginalPanelPosition | null
195
+ panelSizes: Record<string, PanelSizeInfo>
196
+ customDrag?: CustomDragState
197
+ }
198
+
199
+ export interface DragDropStateUpdaters {
200
+ onColumnPanelsChange: (newColumnPanels: Record<string, string[]>) => void
201
+ onPanelVisibilityChange: (newVisibility: Record<string, boolean>) => void
202
+ setPanelRef?: (panelId: string, el: HTMLDivElement | null) => void
203
+ }
204
+
205
+ export interface UseDragDropColumnsReturn {
206
+ columnPanels: Record<string, string[]>
207
+ panelVisibility: Record<string, boolean>
208
+ dragModes: Record<string, "normal" | "custom">
209
+ dragState: DragState
210
+ dragOverPosition: DragOverPosition | null
211
+ originalPanelPosition: OriginalPanelPosition | null
212
+ touchDragState: TouchDragState
213
+ customDrag: CustomDragState
214
+ clickState: ClickState
215
+ mousePosition: MousePosition
216
+ panelSizes: Record<string, PanelSizeInfo>
217
+ setColumnPanels: (newColumnPanels: Record<string, string[]>) => void
218
+ setPanelVisibility: (newVisibility: Record<string, boolean>) => void
219
+ setDragModes: (newDragModes: Record<string, "normal" | "custom">) => void
220
+ setPanelRef: (panelId: string, el: HTMLDivElement | null) => void
221
+ handleDragStart: (e: DragEvent<Element>, panelId: string) => void
222
+ handleDragEnd: () => void
223
+ handleMouseDown: (e: MouseEvent<Element>, panelId: string) => void
224
+ handleTouchStart: (e: TouchEvent<Element>, panelId: string) => void
225
+ handleTouchMove: (e: TouchEvent) => void
226
+ handleTouchEnd: (e: TouchEvent) => void
227
+ handlePlaceholderDragEnter: (columnIndex: number, insertIndex: number) => void
228
+ handlePlaceholderDragLeave: (e?: DragEvent<Element>, columnIndex?: number, insertIndex?: number) => void
229
+ handleDragOverWithInsert: (e: DragEvent<Element>, columnIndex: number) => void
230
+ handleDropWithInsert: (e: DragEvent<Element>, targetColumn: string) => void
231
+ handleColumnDragLeave: (e: DragEvent<Element>) => void
232
+ handlePanelSizeInfoClick: (e: MouseEvent<Element> | TouchEvent<Element>, panelId: string) => void
233
+ toggleDragMode: (panelId: string) => void
234
+ findPanelPosition: (panelId: string) => OriginalPanelPosition | null
235
+ }
236
+
237
+ export interface ResizeConfig {
238
+ enableResize?: boolean
239
+ columnWidths?: Record<string, number>
240
+ onColumnWidthChange?: (columnId: string, width: number) => void
241
+ onResizeStart?: (columnId: string, startX: number) => void
242
+ onResize?: (currentX: number) => void
243
+ onResizeEnd?: () => void
244
+ isResizing?: boolean
245
+ resizingColumn?: string | null
246
+ }
247
+
248
+ export type DragMode = "normal" | "custom"
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @fileoverview Column ID management utilities for consistent column identification across the application.
3
+ * カラムID管理ユーティリティ - アプリケーション全体でのカラム識別の一貫性を保つ。
4
+ */
5
+
6
+ export interface ColumnIdConfig {
7
+ prefix: string
8
+ startIndex: number
9
+ separator: string
10
+ }
11
+
12
+ export const DEFAULT_COLUMN_ID_CONFIG: ColumnIdConfig = {
13
+ prefix: "column",
14
+ startIndex: 1,
15
+ separator: "_",
16
+ }
17
+
18
+ export const generateColumnId = (index: number, config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): string => {
19
+ const { prefix, startIndex, separator } = config
20
+ const columnNumber = index + startIndex
21
+ return `${prefix}${separator}${columnNumber}`
22
+ }
23
+
24
+ export const generateColumnIds = (count: number, config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): string[] => {
25
+ return Array.from({ length: count }, (_, index) => generateColumnId(index, config))
26
+ }
27
+
28
+ export const parseColumnId = (columnId: string, config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): number | null => {
29
+ const { prefix, startIndex, separator } = config
30
+ const expectedPrefix = `${prefix}${separator}`
31
+
32
+ if (!columnId.startsWith(expectedPrefix)) {
33
+ return null
34
+ }
35
+
36
+ const numberPart = columnId.slice(expectedPrefix.length)
37
+ const columnNumber = parseInt(numberPart, 10)
38
+
39
+ if (Number.isNaN(columnNumber) || columnNumber < startIndex) {
40
+ return null
41
+ }
42
+
43
+ return columnNumber - startIndex
44
+ }
45
+
46
+ export const isValidColumnId = (columnId: string, config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): boolean => {
47
+ return parseColumnId(columnId, config) !== null
48
+ }
49
+
50
+ export const getNextColumnId = (existingIds: string[], config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): string => {
51
+ const indices = existingIds
52
+ .map((id) => parseColumnId(id, config))
53
+ .filter((index): index is number => index !== null)
54
+ .sort((a, b) => a - b)
55
+
56
+ for (let i = 0; i < indices.length; i++) {
57
+ if (indices[i] !== i) {
58
+ return generateColumnId(i, config)
59
+ }
60
+ }
61
+
62
+ return generateColumnId(indices.length, config)
63
+ }
64
+
65
+ export const sortColumnIds = (columnIds: string[], config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): string[] => {
66
+ return columnIds.sort((a, b) => {
67
+ const indexA = parseColumnId(a, config) ?? -1
68
+ const indexB = parseColumnId(b, config) ?? -1
69
+ return indexA - indexB
70
+ })
71
+ }
72
+
73
+ export const createColumnIdMapping = (oldIds: string[], config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): Record<string, string> => {
74
+ const mapping: Record<string, string> = {}
75
+
76
+ oldIds.forEach((oldId, index) => {
77
+ const newId = generateColumnId(index, config)
78
+ mapping[oldId] = newId
79
+ })
80
+
81
+ return mapping
82
+ }
83
+
84
+ export const normalizeColumnPanels = (columnPanels: Record<string, string[]>, newColumnCount: number, config: ColumnIdConfig = DEFAULT_COLUMN_ID_CONFIG): Record<string, string[]> => {
85
+ const allPanels: string[] = []
86
+ Object.values(columnPanels).forEach((panels) => {
87
+ allPanels.push(...panels)
88
+ })
89
+
90
+ const newColumnPanels: Record<string, string[]> = {}
91
+ const newColumnIds = generateColumnIds(newColumnCount, config)
92
+
93
+ newColumnIds.forEach((columnId) => {
94
+ newColumnPanels[columnId] = []
95
+ })
96
+
97
+ allPanels.forEach((panelId, index) => {
98
+ const targetColumnIndex = index % newColumnCount
99
+ const targetColumnId = newColumnIds[targetColumnIndex]
100
+ newColumnPanels[targetColumnId].push(panelId)
101
+ })
102
+
103
+ return newColumnPanels
104
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @fileoverview Utility functions for implementing edge scrolling during drag operations.
3
+ * This provides auto-scrolling functionality when the cursor reaches the edge of the viewport.
4
+ *
5
+ * ドラッグ操作中のエッジスクロール機能を実装するためのユーティリティ関数。
6
+ * カーソルがビューポートの端に到達した際の自動スクロール機能を提供します。
7
+ */
8
+
9
+ export interface EdgeScrollConfig {
10
+ triggerDistance: number
11
+ scrollSpeed: number
12
+ maxScrollSpeed: number
13
+ }
14
+
15
+ export const DEFAULT_EDGE_SCROLL_CONFIG: EdgeScrollConfig = {
16
+ triggerDistance: 80,
17
+ scrollSpeed: 5,
18
+ maxScrollSpeed: 20,
19
+ }
20
+
21
+ export interface ScrollVector {
22
+ x: number
23
+ y: number
24
+ }
25
+
26
+ export const calculateScrollVector = (clientX: number, clientY: number, config: EdgeScrollConfig = DEFAULT_EDGE_SCROLL_CONFIG, scrollElement?: HTMLElement): ScrollVector => {
27
+ const { triggerDistance, scrollSpeed, maxScrollSpeed } = config
28
+
29
+ let elementBounds: DOMRect
30
+ if (scrollElement) {
31
+ elementBounds = scrollElement.getBoundingClientRect()
32
+ } else {
33
+ elementBounds = new DOMRect(0, 0, window.innerWidth, window.innerHeight)
34
+ }
35
+
36
+ const { left, top, right, bottom } = elementBounds
37
+
38
+ let scrollX = 0
39
+ let scrollY = 0
40
+
41
+ if (clientX >= left && clientX <= right && clientY >= top && clientY <= bottom) {
42
+ if (clientX < left + triggerDistance) {
43
+ const intensity = Math.max(0, (left + triggerDistance - clientX) / triggerDistance)
44
+ scrollX = -Math.min(maxScrollSpeed, scrollSpeed + intensity * (maxScrollSpeed - scrollSpeed))
45
+ } else if (clientX > right - triggerDistance) {
46
+ const intensity = Math.max(0, (clientX - (right - triggerDistance)) / triggerDistance)
47
+ scrollX = Math.min(maxScrollSpeed, scrollSpeed + intensity * (maxScrollSpeed - scrollSpeed))
48
+ }
49
+
50
+ if (clientY < top + triggerDistance) {
51
+ const intensity = Math.max(0, (top + triggerDistance - clientY) / triggerDistance)
52
+ scrollY = -Math.min(maxScrollSpeed, scrollSpeed + intensity * (maxScrollSpeed - scrollSpeed))
53
+ } else if (clientY > bottom - triggerDistance) {
54
+ const intensity = Math.max(0, (clientY - (bottom - triggerDistance)) / triggerDistance)
55
+ scrollY = Math.min(maxScrollSpeed, scrollSpeed + intensity * (maxScrollSpeed - scrollSpeed))
56
+ }
57
+ }
58
+
59
+ return { x: scrollX, y: scrollY }
60
+ }
61
+
62
+ export const performScroll = (scrollVector: ScrollVector, scrollElement?: HTMLElement): void => {
63
+ if (scrollVector.x !== 0 || scrollVector.y !== 0) {
64
+ if (scrollElement) {
65
+ scrollElement.scrollBy(scrollVector.x, scrollVector.y)
66
+ } else {
67
+ window.scrollBy(scrollVector.x, scrollVector.y)
68
+ }
69
+ }
70
+ }
71
+
72
+ export class EdgeScrollManager {
73
+ private intervalId: number | null = null
74
+ private config: EdgeScrollConfig
75
+ private isActive = false
76
+ private scrollElement?: HTMLElement
77
+
78
+ constructor(config: EdgeScrollConfig = DEFAULT_EDGE_SCROLL_CONFIG, scrollElement?: HTMLElement) {
79
+ this.config = config
80
+ this.scrollElement = scrollElement
81
+ }
82
+
83
+ setScrollElement(element?: HTMLElement): void {
84
+ this.scrollElement = element
85
+ }
86
+
87
+ start(clientX: number, clientY: number): void {
88
+ if (this.isActive) {
89
+ return
90
+ }
91
+
92
+ this.isActive = true
93
+ this.intervalId = window.setInterval(() => {
94
+ const scrollVector = calculateScrollVector(clientX, clientY, this.config, this.scrollElement)
95
+ performScroll(scrollVector, this.scrollElement)
96
+ }, 16)
97
+ }
98
+
99
+ update(clientX: number, clientY: number): void {
100
+ const scrollVector = calculateScrollVector(clientX, clientY, this.config, this.scrollElement)
101
+
102
+ if ((scrollVector.x !== 0 || scrollVector.y !== 0) && !this.isActive) {
103
+ this.start(clientX, clientY)
104
+ } else if (scrollVector.x === 0 && scrollVector.y === 0 && this.isActive) {
105
+ this.stop()
106
+ }
107
+ }
108
+
109
+ stop(): void {
110
+ if (this.intervalId !== null) {
111
+ clearInterval(this.intervalId)
112
+ this.intervalId = null
113
+ }
114
+ this.isActive = false
115
+ }
116
+
117
+ isScrolling(): boolean {
118
+ return this.isActive
119
+ }
120
+
121
+ updateConfig(newConfig: EdgeScrollConfig): void {
122
+ this.config = newConfig
123
+ }
124
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @module utils/logger
3
+ * @description Logger utility for consistent log management across the library.
4
+ * @description ライブラリ全体で一貫したログ管理を行うためのロガーユーティリティ。
5
+ */
6
+
7
+ /**
8
+ * @enum LogLevel
9
+ * @description Log levels for filtering output.
10
+ * @description 出力をフィルタリングするためのログレベル。
11
+ */
12
+ export enum LogLevel {
13
+ DEBUG = 0,
14
+ INFO = 1,
15
+ WARN = 2,
16
+ ERROR = 3,
17
+ NONE = 4,
18
+ }
19
+
20
+ /**
21
+ * @interface ILogger
22
+ * @description Interface for a logger object compatible with Console.
23
+ * @description Console と互換性のあるロガーオブジェクトのインターフェース。
24
+ */
25
+ export interface ILogger {
26
+ debug(message?: unknown, ...optionalParams: unknown[]): void
27
+ info(message?: unknown, ...optionalParams: unknown[]): void
28
+ warn(message?: unknown, ...optionalParams: unknown[]): void
29
+ error(message?: unknown, ...optionalParams: unknown[]): void
30
+ }
31
+
32
+ /**
33
+ * @class Logger
34
+ * @description A wrapper class for handling logging with levels and prefixes.
35
+ * @description レベルとプレフィックスを使用したログ記録を処理するためのラッパークラス。
36
+ */
37
+ export class Logger implements ILogger {
38
+ private level: LogLevel
39
+ private prefix: string
40
+ private impl: ILogger
41
+
42
+ /**
43
+ * @constructor
44
+ * @param {LogLevel} [level=LogLevel.WARN] - The minimum log level to output.
45
+ * @param {string} [prefix="[drag-drop-panels]"] - The prefix to add to all log messages.
46
+ * @param {ILogger} [impl=console] - The implementation to use for logging.
47
+ */
48
+ constructor(level: LogLevel = LogLevel.WARN, prefix: string = "[drag-drop-panels]", impl: ILogger = console) {
49
+ this.level = level
50
+ this.prefix = prefix
51
+ this.impl = impl
52
+ }
53
+
54
+ private static instance: Logger = new Logger(LogLevel.WARN, "[drag-drop-panels]")
55
+
56
+ /**
57
+ * @method setLevel
58
+ * @description Updates the current log level for the static instance.
59
+ * @description 静的インスタンスの現在のログレベルを更新します。
60
+ * @param {LogLevel} level - The new log level.
61
+ */
62
+ static setLevel(level: LogLevel): void {
63
+ Logger.instance.setLevel(level)
64
+ }
65
+
66
+ /**
67
+ * @method setLevel
68
+ * @description Updates the current log level.
69
+ * @description 現在のログレベルを更新します。
70
+ * @param {LogLevel} level - The new log level.
71
+ */
72
+ setLevel(level: LogLevel): void {
73
+ this.level = level
74
+ }
75
+
76
+ /**
77
+ * @method setImplementation
78
+ * @description Updates the logger implementation for the static instance.
79
+ * @description 静的インスタンスのロガーの実装を更新します。
80
+ * @param {ILogger} impl - The new logger implementation.
81
+ */
82
+ static setImplementation(impl: ILogger): void {
83
+ Logger.instance.setImplementation(impl)
84
+ }
85
+
86
+ /**
87
+ * @method setImplementation
88
+ * @description Updates the logger implementation.
89
+ * @description ロガーの実装を更新します。
90
+ * @param {ILogger} impl - The new logger implementation.
91
+ */
92
+ setImplementation(impl: ILogger): void {
93
+ this.impl = impl
94
+ }
95
+
96
+ /**
97
+ * @method setPrefix
98
+ * @description Updates the log prefix for the static instance.
99
+ * @description 静的インスタンスのログのプレフィックスを更新します。
100
+ * @param {string} prefix - The new prefix.
101
+ */
102
+ static setPrefix(prefix: string): void {
103
+ Logger.instance.setPrefix(prefix)
104
+ }
105
+
106
+ /**
107
+ * @method setPrefix
108
+ * @description Updates the log prefix.
109
+ * @description ログのプレフィックスを更新します。
110
+ * @param {string} prefix - The new prefix.
111
+ */
112
+ setPrefix(prefix: string): void {
113
+ this.prefix = prefix
114
+ }
115
+
116
+ private formatMessage(message: unknown): unknown[] {
117
+ if (typeof message === "string") {
118
+ return [`${this.prefix} ${message}`]
119
+ }
120
+ return [this.prefix, message]
121
+ }
122
+
123
+ static debug(message?: unknown, ...optionalParams: unknown[]): void {
124
+ Logger.instance.debug(message, ...optionalParams)
125
+ }
126
+
127
+ debug(message?: unknown, ...optionalParams: unknown[]): void {
128
+ if (this.level <= LogLevel.DEBUG) {
129
+ this.impl.debug(...this.formatMessage(message), ...optionalParams)
130
+ }
131
+ }
132
+
133
+ static info(message?: unknown, ...optionalParams: unknown[]): void {
134
+ Logger.instance.info(message, ...optionalParams)
135
+ }
136
+
137
+ info(message?: unknown, ...optionalParams: unknown[]): void {
138
+ if (this.level <= LogLevel.INFO) {
139
+ this.impl.info(...this.formatMessage(message), ...optionalParams)
140
+ }
141
+ }
142
+
143
+ static warn(message?: unknown, ...optionalParams: unknown[]): void {
144
+ Logger.instance.warn(message, ...optionalParams)
145
+ }
146
+
147
+ warn(message?: unknown, ...optionalParams: unknown[]): void {
148
+ if (this.level <= LogLevel.WARN) {
149
+ this.impl.warn(...this.formatMessage(message), ...optionalParams)
150
+ }
151
+ }
152
+
153
+ static error(message?: unknown, ...optionalParams: unknown[]): void {
154
+ Logger.instance.error(message, ...optionalParams)
155
+ }
156
+
157
+ error(message?: unknown, ...optionalParams: unknown[]): void {
158
+ if (this.level <= LogLevel.ERROR) {
159
+ this.impl.error(...this.formatMessage(message), ...optionalParams)
160
+ }
161
+ }
162
+ }
package/src/index.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @package @aiquants/drag-drop-panels
3
+ * @description Reusable drag-and-drop panel layout components and utilities
4
+ *
5
+ * 再利用可能なドラッグ&ドロップパネルレイアウトコンポーネントとユーティリティ
6
+ */
7
+
8
+ export type { DragDropLayoutProps } from "./DragDropLayout"
9
+ export { DragDropLayout } from "./DragDropLayout"
10
+ export { ColumnControlPanel } from "./drag-drop/ColumnControlPanel"
11
+ export { ColumnInsertPanel } from "./drag-drop/ColumnInsertPanel"
12
+ export { debugLog, PanelSizeDisplay } from "./drag-drop/DebugComponents"
13
+ export { DebugControlPanel } from "./drag-drop/DebugControlPanel"
14
+ export { DropZoneDebugOverlay, InsertPlaceholder } from "./drag-drop/DebugOverlay"
15
+ export type { ColumnConfig, ColumnLayoutState, UseColumnLayoutProps, UseColumnLayoutReturn } from "./drag-drop/hooks/useColumnLayout"
16
+ export { useColumnLayout } from "./drag-drop/hooks/useColumnLayout"
17
+ export { useCustomDragHandlers } from "./drag-drop/hooks/useCustomDragHandlers"
18
+ export type { UseDragDropColumnsProps } from "./drag-drop/hooks/useDragDropColumns"
19
+ export { useDragDropColumns } from "./drag-drop/hooks/useDragDropColumns"
20
+ export { useDragDropState } from "./drag-drop/hooks/useDragDropState"
21
+ export { useMouseTracking } from "./drag-drop/hooks/useMouseTracking"
22
+ export { useNormalDragHandlers } from "./drag-drop/hooks/useNormalDragHandlers"
23
+ export { usePanelManagement } from "./drag-drop/hooks/usePanelManagement"
24
+ export type { UseResponsiveColumnsProps, UseResponsiveColumnsReturn } from "./drag-drop/hooks/useResponsiveColumns"
25
+ export { useResponsiveColumns } from "./drag-drop/hooks/useResponsiveColumns"
26
+ export type { ResizableColumnProps, ResizeHandleProps } from "./drag-drop/ResizeHandle"
27
+ export { ResizableColumn, ResizeHandle } from "./drag-drop/ResizeHandle"
28
+ export { ResponsiveControl } from "./drag-drop/ResponsiveControl"
29
+ export type {
30
+ ClickState,
31
+ ColumnConfig as ColumnConfigType,
32
+ CustomDragState,
33
+ DebugConfig,
34
+ DOMDragEvent,
35
+ DOMMouseEvent,
36
+ DOMTouchEvent,
37
+ DragDropEventHandlers,
38
+ DragDropHookReturn,
39
+ DragDropState,
40
+ DragDropStateUpdaters,
41
+ DragMode,
42
+ DragOverPosition,
43
+ DragState,
44
+ ElementWithResizeObserver,
45
+ MousePosition,
46
+ OriginalPanelPosition,
47
+ PanelConfig,
48
+ PanelSizeInfo,
49
+ ReactDragEvent,
50
+ ReactMouseEvent,
51
+ ReactTouchEvent,
52
+ ResizeConfig,
53
+ TouchDragState,
54
+ UseDragDropColumnsReturn,
55
+ } from "./drag-drop/types"
56
+ export { DEFAULT_DEBUG_CONFIG } from "./drag-drop/types"
57
+ export type { ColumnIdConfig } from "./drag-drop/utils/columnIdUtils"
58
+ export { createColumnIdMapping, DEFAULT_COLUMN_ID_CONFIG, generateColumnId, generateColumnIds, getNextColumnId, isValidColumnId, normalizeColumnPanels, parseColumnId, sortColumnIds } from "./drag-drop/utils/columnIdUtils"
59
+ export type { EdgeScrollConfig, ScrollVector } from "./drag-drop/utils/edgeScrollUtils"
60
+ export { calculateScrollVector, DEFAULT_EDGE_SCROLL_CONFIG, EdgeScrollManager, performScroll } from "./drag-drop/utils/edgeScrollUtils"