@alekstar79/draggable-resizable-container 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aleksey Tarasenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # Draggable and Resizable Container
2
+
3
+ [![npm version](https://img.shields.io/npm/v/draggable-resizable-container.svg)](https://www.npmjs.com/package/@alekstar79/draggable-resizable-container)
4
+ [![Coverage](https://img.shields.io/badge/coverage-80%25-brightgreen.svg)](https://github.com/alekstar79/utils/actions)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?style=flat-square)](https://www.typescriptlang.org)
6
+ [![Node](https://img.shields.io/badge/Node-18%2B-green?style=flat-square)](https://nodejs.org)
7
+ [![Browser](https://img.shields.io/badge/Browser-ES2018-green)]()
8
+ [![License MIT](https://img.shields.io/badge/License-MIT-blue)](LICENSE)
9
+
10
+ A modern, lightweight, and extensible TypeScript library for creating draggable and resizable containers (windows, dialogs) in your web applications. It features a reactive core, a powerful plugin system, and a clean API.
11
+
12
+ ![banner](banner.svg)
13
+
14
+ ## Features
15
+
16
+ - **Draggable & Resizable**: Smooth, performant dragging and resizing of containers with multiple handle directions.
17
+ - **Reactive Core**: Built with `@alekstar79/reactive-event-system` for efficient state management and event handling.
18
+ - **Extensible Plugin System**: Easily add new features like snapping, docking, or state persistence.
19
+ - **Rich Event System**: Subscribe to a wide range of events (`dragStart`, `drag`, `dragEnd`, `resize`, etc.).
20
+ - **Boundary Constraints**: Confine containers to the viewport or a parent element.
21
+ - **Customizable**: Control movement direction, resize handles, and more.
22
+ - **Touch Device Support**: Works on both desktop and mobile devices.
23
+ - **Template Loading**: A system for loading content from HTML templates.
24
+ - **State Persistence**: Save and restore container states using `localStorage`.
25
+ - **TypeScript First**: Written entirely in TypeScript for strong typing and better developer experience.
26
+
27
+ ## Installation
28
+
29
+ You can install the library using npm or yarn:
30
+
31
+ ```bash
32
+ npm install @alekstar79/draggable-resizable-container
33
+ ```
34
+
35
+ or
36
+
37
+ ```bash
38
+ yarn add @alekstar79/draggable-resizable-container
39
+ ```
40
+
41
+ You also need to import the base styles for the library to work correctly.
42
+
43
+ ```javascript
44
+ import '@alekstar79/draggable-resizable-container/styles';
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ Here's a simple example of how to create a draggable and resizable container.
50
+
51
+ **HTML:**
52
+
53
+ ```html
54
+ <div id="my-container" style="width: 300px; height: 200px; top: 50px; left: 50px;">
55
+ <div data-drag-handle>Drag Me</div>
56
+ <div class="content">
57
+ <p>This is a draggable and resizable container.</p>
58
+ </div>
59
+ </div>
60
+ ```
61
+
62
+ **TypeScript:**
63
+
64
+ ```typescript
65
+ import { ContainerManager } from '@alekstar79/draggable-resizable-container';
66
+ import '@alekstar79/draggable-resizable-container/styles';
67
+
68
+ const containerElement = document.getElementById('my-container');
69
+
70
+ if (containerElement) {
71
+ const manager = new ContainerManager(containerElement, {
72
+ // Optional configuration
73
+ constrainToViewport: true,
74
+ resize: {
75
+ enabled: true,
76
+ directions: ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'],
77
+ },
78
+ });
79
+
80
+ // Listen to events
81
+ manager.on('dragEnd', (event) => {
82
+ console.log('Drag ended at:', event.state);
83
+ });
84
+ }
85
+ ```
86
+
87
+ ## `ContainerManager` API
88
+
89
+ The `ContainerManager` is the core class of the library.
90
+
91
+ ### `new ContainerManager(element, config)`
92
+
93
+ Creates a new `ContainerManager` instance.
94
+
95
+ - `element`: The `HTMLElement` to be managed.
96
+ - `config` (optional): A `ContainerConfig` object for customization.
97
+
98
+ ### `ContainerConfig`
99
+
100
+ | Property | Type | Description |
101
+ |-----------------------|-----------------|--------------------------------------------------------------------------------|
102
+ | `mode` | `MovementMode` | `'smooth'` (default) or `'pinned'`. |
103
+ | `boundaries` | `Boundaries` | An object with `minWidth`, `minHeight`, `maxWidth`, `maxHeight`. |
104
+ | `draggingDirection` | `DirectionMode` | `'all'` (default), `'horizontal'`, or `'vertical'`. |
105
+ | `constrainToViewport` | `boolean` | If `true`, constrains the container to the viewport. Default is `false`. |
106
+ | `constrainToParent` | `boolean` | If `true`, constrains the container to its parent element. Default is `false`. |
107
+ | `resize` | `ResizeConfig` | Configuration for resizing. |
108
+
109
+ ### Methods
110
+
111
+ - `getState(): ContainerState`: Returns the current state (`x`, `y`, `width`, `height`) of the container.
112
+ - `setState(state: Partial<ContainerState>)`: Sets the state of the container.
113
+ - `getMode(): MovementMode`: Returns the current movement mode.
114
+ - `setMode(mode: MovementMode)`: Sets the movement mode.
115
+ - `getDirection(): DirectionMode`: Returns the current dragging direction.
116
+ - `setDirection(direction: DirectionMode)`: Sets the dragging direction.
117
+ - `on(event: string, callback: (data: ContainerEvent) => void)`: Subscribes to an event.
118
+ - `off(event: string, callback: (data: ContainerEvent) => void)`: Unsubscribes from an event.
119
+ - `destroy()`: Cleans up the `ContainerManager` instance and removes event listeners.
120
+
121
+ ### Events
122
+
123
+ You can subscribe to the following events using the `on` method:
124
+
125
+ - `dragStart`, `drag`, `dragEnd`
126
+ - `resizeStart`, `resize`, `resizeEnd`
127
+ - `modeChange`
128
+ - `stateChange`
129
+ - `viewportResize`
130
+
131
+ ## Plugin System
132
+
133
+ The library has a powerful plugin system that allows you to extend its functionality.
134
+
135
+ ### Using a Plugin
136
+
137
+ To use a plugin, simply import it and pass it to the `use` method of your `ContainerManager` instance.
138
+
139
+ ```typescript
140
+ import { ContainerManager } from '@alekstar79/draggable-resizable-container';
141
+ import { SnappingPlugin } from '@alekstar79/draggable-resizable-container/plugins';
142
+
143
+ const manager = new ContainerManager(containerElement);
144
+
145
+ manager.use(new SnappingPlugin({
146
+ snapStep: 20,
147
+ enabled: true,
148
+ }));
149
+ ```
150
+
151
+ ### Included Plugins
152
+
153
+ #### `SnappingPlugin`
154
+
155
+ Adds snapping functionality to the container.
156
+
157
+ **Options:**
158
+
159
+ - `snapStep`: The size of the grid to snap to (in pixels). Default is `10`.
160
+ - `enabled`: Whether snapping is enabled. Default is `true`.
161
+
162
+ **Methods added to `ContainerManager`:**
163
+
164
+ - `setSnapStep(step: number)`
165
+ - `setSnappingEnabled(enabled: boolean)`
166
+ - `getSnappingConfig(): SnappingPluginOptions`
167
+
168
+ #### `EdgeDockingPlugin`
169
+
170
+ Allows containers to be "docked" to the edges of the screen.
171
+
172
+ **Options:**
173
+
174
+ - `edgeThreshold`: The distance from the edge (in pixels) at which docking is triggered. Default is `30`.
175
+ - `visiblePeek`: The amount of the container (in pixels) that remains visible when docked. Default is `20`.
176
+
177
+ **Methods added to `ContainerManager`:**
178
+
179
+ - `isContainerDocked(element: HTMLElement): boolean`
180
+ - `getContainerDockEdge(element: HTMLElement): Edge | null`
181
+
182
+ #### `StatePersistencePlugin`
183
+
184
+ Saves the state of containers to `localStorage` and restores it on page load.
185
+
186
+ **Options:**
187
+
188
+ - `containerId`: A unique ID for the container, required for persistence.
189
+ - `isDemo`: A flag to indicate if the container is part of the demo (for demo-specific logic).
190
+
191
+ **Example:**
192
+
193
+ ```typescript
194
+ import { StatePersistencePlugin } from '@alekstar79/draggable-resizable-container/plugins';
195
+
196
+ manager.use(new StatePersistencePlugin({
197
+ containerId: 'my-unique-container-id',
198
+ }));
199
+ ```
200
+
201
+ ## Utilities
202
+
203
+ The library also exports several utility classes that you can use.
204
+
205
+ ### `ContainerInitializer`
206
+
207
+ A simple utility for creating a container element.
208
+
209
+ ```typescript
210
+ import { ContainerInitializer } from '@alekstar79/draggable-resizable-container';
211
+
212
+ const newContainer = ContainerInitializer.createContainerElement(400, 250, 100, 100);
213
+ document.body.appendChild(newContainer);
214
+ ```
215
+
216
+ ### `ContentCreator` and `TemplateLoader`
217
+
218
+ These utilities help with managing the content of your containers, including loading HTML templates.
219
+
220
+ ```typescript
221
+ import { ContentCreator, getTemplateLoader, initializeTemplateSystem } from '@alekstar79/draggable-resizable-container';
222
+
223
+ // Initialize the template system once in your app
224
+ await initializeTemplateSystem();
225
+
226
+ const templateLoader = getTemplateLoader();
227
+ const contentCreator = new ContentCreator(templateLoader);
228
+
229
+ // Load content from a template
230
+ await contentCreator.createContent({ template: 'my-template-name' }, containerElement);
231
+ ```
232
+
233
+ ## Development
234
+
235
+ ```bash
236
+ # Install dependencies
237
+ npm install
238
+
239
+ # Start development server
240
+ npm run dev
241
+
242
+ # Build library
243
+ npm run build:lib
244
+
245
+ # Build demo
246
+ npm run build
247
+
248
+ # Type checking
249
+ npm run type-check
250
+ ```
251
+
252
+ ## Browser Support
253
+
254
+ - Chrome 88+
255
+ - Firefox 78+
256
+ - Safari 14+
257
+ - Edge 88+
258
+
259
+ ## Contributing
260
+
261
+ Contributions are welcome! Please feel free to submit a pull request.
262
+
263
+ ## License
264
+
265
+ This project is licensed under the [MIT License](LICENSE).
package/dist/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aleksey Tarasenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # Draggable and Resizable Container
2
+
3
+ [![npm version](https://img.shields.io/npm/v/draggable-resizable-container.svg)](https://www.npmjs.com/package/@alekstar79/draggable-resizable-container)
4
+ [![Coverage](https://img.shields.io/badge/coverage-80%25-brightgreen.svg)](https://github.com/alekstar79/utils/actions)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?style=flat-square)](https://www.typescriptlang.org)
6
+ [![Node](https://img.shields.io/badge/Node-18%2B-green?style=flat-square)](https://nodejs.org)
7
+ [![Browser](https://img.shields.io/badge/Browser-ES2018-green)]()
8
+ [![License MIT](https://img.shields.io/badge/License-MIT-blue)](LICENSE)
9
+
10
+ A modern, lightweight, and extensible TypeScript library for creating draggable and resizable containers (windows, dialogs) in your web applications. It features a reactive core, a powerful plugin system, and a clean API.
11
+
12
+ ![banner](banner.svg)
13
+
14
+ ## Features
15
+
16
+ - **Draggable & Resizable**: Smooth, performant dragging and resizing of containers with multiple handle directions.
17
+ - **Reactive Core**: Built with `@alekstar79/reactive-event-system` for efficient state management and event handling.
18
+ - **Extensible Plugin System**: Easily add new features like snapping, docking, or state persistence.
19
+ - **Rich Event System**: Subscribe to a wide range of events (`dragStart`, `drag`, `dragEnd`, `resize`, etc.).
20
+ - **Boundary Constraints**: Confine containers to the viewport or a parent element.
21
+ - **Customizable**: Control movement direction, resize handles, and more.
22
+ - **Touch Device Support**: Works on both desktop and mobile devices.
23
+ - **Template Loading**: A system for loading content from HTML templates.
24
+ - **State Persistence**: Save and restore container states using `localStorage`.
25
+ - **TypeScript First**: Written entirely in TypeScript for strong typing and better developer experience.
26
+
27
+ ## Installation
28
+
29
+ You can install the library using npm or yarn:
30
+
31
+ ```bash
32
+ npm install @alekstar79/draggable-resizable-container
33
+ ```
34
+
35
+ or
36
+
37
+ ```bash
38
+ yarn add @alekstar79/draggable-resizable-container
39
+ ```
40
+
41
+ You also need to import the base styles for the library to work correctly.
42
+
43
+ ```javascript
44
+ import '@alekstar79/draggable-resizable-container/styles';
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ Here's a simple example of how to create a draggable and resizable container.
50
+
51
+ **HTML:**
52
+
53
+ ```html
54
+ <div id="my-container" style="width: 300px; height: 200px; top: 50px; left: 50px;">
55
+ <div data-drag-handle>Drag Me</div>
56
+ <div class="content">
57
+ <p>This is a draggable and resizable container.</p>
58
+ </div>
59
+ </div>
60
+ ```
61
+
62
+ **TypeScript:**
63
+
64
+ ```typescript
65
+ import { ContainerManager } from '@alekstar79/draggable-resizable-container';
66
+ import '@alekstar79/draggable-resizable-container/styles';
67
+
68
+ const containerElement = document.getElementById('my-container');
69
+
70
+ if (containerElement) {
71
+ const manager = new ContainerManager(containerElement, {
72
+ // Optional configuration
73
+ constrainToViewport: true,
74
+ resize: {
75
+ enabled: true,
76
+ directions: ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'],
77
+ },
78
+ });
79
+
80
+ // Listen to events
81
+ manager.on('dragEnd', (event) => {
82
+ console.log('Drag ended at:', event.state);
83
+ });
84
+ }
85
+ ```
86
+
87
+ ## `ContainerManager` API
88
+
89
+ The `ContainerManager` is the core class of the library.
90
+
91
+ ### `new ContainerManager(element, config)`
92
+
93
+ Creates a new `ContainerManager` instance.
94
+
95
+ - `element`: The `HTMLElement` to be managed.
96
+ - `config` (optional): A `ContainerConfig` object for customization.
97
+
98
+ ### `ContainerConfig`
99
+
100
+ | Property | Type | Description |
101
+ |-----------------------|-----------------|--------------------------------------------------------------------------------|
102
+ | `mode` | `MovementMode` | `'smooth'` (default) or `'pinned'`. |
103
+ | `boundaries` | `Boundaries` | An object with `minWidth`, `minHeight`, `maxWidth`, `maxHeight`. |
104
+ | `draggingDirection` | `DirectionMode` | `'all'` (default), `'horizontal'`, or `'vertical'`. |
105
+ | `constrainToViewport` | `boolean` | If `true`, constrains the container to the viewport. Default is `false`. |
106
+ | `constrainToParent` | `boolean` | If `true`, constrains the container to its parent element. Default is `false`. |
107
+ | `resize` | `ResizeConfig` | Configuration for resizing. |
108
+
109
+ ### Methods
110
+
111
+ - `getState(): ContainerState`: Returns the current state (`x`, `y`, `width`, `height`) of the container.
112
+ - `setState(state: Partial<ContainerState>)`: Sets the state of the container.
113
+ - `getMode(): MovementMode`: Returns the current movement mode.
114
+ - `setMode(mode: MovementMode)`: Sets the movement mode.
115
+ - `getDirection(): DirectionMode`: Returns the current dragging direction.
116
+ - `setDirection(direction: DirectionMode)`: Sets the dragging direction.
117
+ - `on(event: string, callback: (data: ContainerEvent) => void)`: Subscribes to an event.
118
+ - `off(event: string, callback: (data: ContainerEvent) => void)`: Unsubscribes from an event.
119
+ - `destroy()`: Cleans up the `ContainerManager` instance and removes event listeners.
120
+
121
+ ### Events
122
+
123
+ You can subscribe to the following events using the `on` method:
124
+
125
+ - `dragStart`, `drag`, `dragEnd`
126
+ - `resizeStart`, `resize`, `resizeEnd`
127
+ - `modeChange`
128
+ - `stateChange`
129
+ - `viewportResize`
130
+
131
+ ## Plugin System
132
+
133
+ The library has a powerful plugin system that allows you to extend its functionality.
134
+
135
+ ### Using a Plugin
136
+
137
+ To use a plugin, simply import it and pass it to the `use` method of your `ContainerManager` instance.
138
+
139
+ ```typescript
140
+ import { ContainerManager } from '@alekstar79/draggable-resizable-container';
141
+ import { SnappingPlugin } from '@alekstar79/draggable-resizable-container/plugins';
142
+
143
+ const manager = new ContainerManager(containerElement);
144
+
145
+ manager.use(new SnappingPlugin({
146
+ snapStep: 20,
147
+ enabled: true,
148
+ }));
149
+ ```
150
+
151
+ ### Included Plugins
152
+
153
+ #### `SnappingPlugin`
154
+
155
+ Adds snapping functionality to the container.
156
+
157
+ **Options:**
158
+
159
+ - `snapStep`: The size of the grid to snap to (in pixels). Default is `10`.
160
+ - `enabled`: Whether snapping is enabled. Default is `true`.
161
+
162
+ **Methods added to `ContainerManager`:**
163
+
164
+ - `setSnapStep(step: number)`
165
+ - `setSnappingEnabled(enabled: boolean)`
166
+ - `getSnappingConfig(): SnappingPluginOptions`
167
+
168
+ #### `EdgeDockingPlugin`
169
+
170
+ Allows containers to be "docked" to the edges of the screen.
171
+
172
+ **Options:**
173
+
174
+ - `edgeThreshold`: The distance from the edge (in pixels) at which docking is triggered. Default is `30`.
175
+ - `visiblePeek`: The amount of the container (in pixels) that remains visible when docked. Default is `20`.
176
+
177
+ **Methods added to `ContainerManager`:**
178
+
179
+ - `isContainerDocked(element: HTMLElement): boolean`
180
+ - `getContainerDockEdge(element: HTMLElement): Edge | null`
181
+
182
+ #### `StatePersistencePlugin`
183
+
184
+ Saves the state of containers to `localStorage` and restores it on page load.
185
+
186
+ **Options:**
187
+
188
+ - `containerId`: A unique ID for the container, required for persistence.
189
+ - `isDemo`: A flag to indicate if the container is part of the demo (for demo-specific logic).
190
+
191
+ **Example:**
192
+
193
+ ```typescript
194
+ import { StatePersistencePlugin } from '@alekstar79/draggable-resizable-container/plugins';
195
+
196
+ manager.use(new StatePersistencePlugin({
197
+ containerId: 'my-unique-container-id',
198
+ }));
199
+ ```
200
+
201
+ ## Utilities
202
+
203
+ The library also exports several utility classes that you can use.
204
+
205
+ ### `ContainerInitializer`
206
+
207
+ A simple utility for creating a container element.
208
+
209
+ ```typescript
210
+ import { ContainerInitializer } from '@alekstar79/draggable-resizable-container';
211
+
212
+ const newContainer = ContainerInitializer.createContainerElement(400, 250, 100, 100);
213
+ document.body.appendChild(newContainer);
214
+ ```
215
+
216
+ ### `ContentCreator` and `TemplateLoader`
217
+
218
+ These utilities help with managing the content of your containers, including loading HTML templates.
219
+
220
+ ```typescript
221
+ import { ContentCreator, getTemplateLoader, initializeTemplateSystem } from '@alekstar79/draggable-resizable-container';
222
+
223
+ // Initialize the template system once in your app
224
+ await initializeTemplateSystem();
225
+
226
+ const templateLoader = getTemplateLoader();
227
+ const contentCreator = new ContentCreator(templateLoader);
228
+
229
+ // Load content from a template
230
+ await contentCreator.createContent({ template: 'my-template-name' }, containerElement);
231
+ ```
232
+
233
+ ## Development
234
+
235
+ ```bash
236
+ # Install dependencies
237
+ npm install
238
+
239
+ # Start development server
240
+ npm run dev
241
+
242
+ # Build library
243
+ npm run build:lib
244
+
245
+ # Build demo
246
+ npm run build
247
+
248
+ # Type checking
249
+ npm run type-check
250
+ ```
251
+
252
+ ## Browser Support
253
+
254
+ - Chrome 88+
255
+ - Firefox 78+
256
+ - Safari 14+
257
+ - Edge 88+
258
+
259
+ ## Contributing
260
+
261
+ Contributions are welcome! Please feel free to submit a pull request.
262
+
263
+ ## License
264
+
265
+ This project is licensed under the [MIT License](LICENSE).