ywana-core8 0.2.5 → 0.2.8

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.
@@ -25,14 +25,21 @@ export const Window = ({
25
25
  const headerRef = useRef(null)
26
26
 
27
27
  // Get window data from WindowManager
28
- const { getWindow, updateWindowPosition, closeWindow, minimizeWindow, maximizeWindow, focusWindow } = useWindows()
28
+ const { getWindow, updateWindowPosition, updateWindowSize, closeWindow, minimizeWindow, maximizeWindow, focusWindow } = useWindows()
29
29
  const windowData = getWindow(id)
30
-
30
+
31
31
  // Local state for dragging
32
32
  const [isDragging, setIsDragging] = useState(false)
33
33
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 })
34
34
  const [dragStartPosition, setDragStartPosition] = useState({ x: 0, y: 0 })
35
35
 
36
+ // Local state for resizing
37
+ const [isResizing, setIsResizing] = useState(false)
38
+ const [resizeDirection, setResizeDirection] = useState('')
39
+ const [resizeStartSize, setResizeStartSize] = useState({ width: 0, height: 0 })
40
+ const [resizeStartPosition, setResizeStartPosition] = useState({ x: 0, y: 0 })
41
+ const [resizeStartMouse, setResizeStartMouse] = useState({ x: 0, y: 0 })
42
+
36
43
  // If window doesn't exist in WindowManager, don't render
37
44
  if (!windowData) {
38
45
  return null
@@ -123,14 +130,119 @@ export const Window = ({
123
130
  updateWindowPosition(id, finalPosition)
124
131
  }
125
132
 
126
- // Setup drag event listeners
133
+ // Handle resize start
134
+ const handleResizeStart = (e, direction) => {
135
+ if (!resizable || maximized) return
136
+
137
+ e.preventDefault()
138
+ e.stopPropagation()
139
+
140
+ setIsResizing(true)
141
+ setResizeDirection(direction)
142
+ setResizeStartSize(size)
143
+ setResizeStartPosition(position)
144
+ setResizeStartMouse({ x: e.clientX, y: e.clientY })
145
+
146
+ // Focus window
147
+ focusWindow(id)
148
+ }
149
+
150
+ // Handle resize move
151
+ const handleResizeMove = (e) => {
152
+ if (!isResizing) return
153
+
154
+ e.preventDefault()
155
+
156
+ const deltaX = e.clientX - resizeStartMouse.x
157
+ const deltaY = e.clientY - resizeStartMouse.y
158
+
159
+ let newSize = { ...resizeStartSize }
160
+ let newPosition = { ...resizeStartPosition }
161
+
162
+ // Calculate new size and position based on resize direction
163
+ switch (resizeDirection) {
164
+ case 'n': // North
165
+ newSize.height = Math.max(150, resizeStartSize.height - deltaY)
166
+ newPosition.y = resizeStartPosition.y + (resizeStartSize.height - newSize.height)
167
+ break
168
+ case 's': // South
169
+ newSize.height = Math.max(150, resizeStartSize.height + deltaY)
170
+ break
171
+ case 'e': // East
172
+ newSize.width = Math.max(200, resizeStartSize.width + deltaX)
173
+ break
174
+ case 'w': // West
175
+ newSize.width = Math.max(200, resizeStartSize.width - deltaX)
176
+ newPosition.x = resizeStartPosition.x + (resizeStartSize.width - newSize.width)
177
+ break
178
+ case 'ne': // Northeast
179
+ newSize.width = Math.max(200, resizeStartSize.width + deltaX)
180
+ newSize.height = Math.max(150, resizeStartSize.height - deltaY)
181
+ newPosition.y = resizeStartPosition.y + (resizeStartSize.height - newSize.height)
182
+ break
183
+ case 'nw': // Northwest
184
+ newSize.width = Math.max(200, resizeStartSize.width - deltaX)
185
+ newSize.height = Math.max(150, resizeStartSize.height - deltaY)
186
+ newPosition.x = resizeStartPosition.x + (resizeStartSize.width - newSize.width)
187
+ newPosition.y = resizeStartPosition.y + (resizeStartSize.height - newSize.height)
188
+ break
189
+ case 'se': // Southeast
190
+ newSize.width = Math.max(200, resizeStartSize.width + deltaX)
191
+ newSize.height = Math.max(150, resizeStartSize.height + deltaY)
192
+ break
193
+ case 'sw': // Southwest
194
+ newSize.width = Math.max(200, resizeStartSize.width - deltaX)
195
+ newSize.height = Math.max(150, resizeStartSize.height + deltaY)
196
+ newPosition.x = resizeStartPosition.x + (resizeStartSize.width - newSize.width)
197
+ break
198
+ }
199
+
200
+ // Apply changes visually
201
+ if (windowRef.current) {
202
+ windowRef.current.style.width = `${newSize.width}px`
203
+ windowRef.current.style.height = `${newSize.height}px`
204
+ windowRef.current.style.left = `${newPosition.x}px`
205
+ windowRef.current.style.top = `${newPosition.y}px`
206
+ }
207
+ }
208
+
209
+ // Handle resize end
210
+ const handleResizeEnd = () => {
211
+ if (!isResizing) return
212
+
213
+ setIsResizing(false)
214
+ setResizeDirection('')
215
+
216
+ // Get final size and position
217
+ const desktopContainer = windowRef.current?.parentElement
218
+ if (!desktopContainer) return
219
+
220
+ const windowRect = windowRef.current.getBoundingClientRect()
221
+ const desktopRect = desktopContainer.getBoundingClientRect()
222
+
223
+ const finalSize = {
224
+ width: windowRect.width,
225
+ height: windowRect.height
226
+ }
227
+
228
+ const finalPosition = {
229
+ x: windowRect.left - desktopRect.left,
230
+ y: windowRect.top - desktopRect.top
231
+ }
232
+
233
+ // Update WindowManager
234
+ updateWindowSize(id, finalSize)
235
+ updateWindowPosition(id, finalPosition)
236
+ }
237
+
238
+ // Setup drag and resize event listeners
127
239
  useEffect(() => {
128
240
  if (isDragging) {
129
241
  document.addEventListener('mousemove', handleMouseMove)
130
242
  document.addEventListener('mouseup', handleMouseUp)
131
243
  document.body.style.userSelect = 'none'
132
244
  document.body.style.cursor = 'move'
133
-
245
+
134
246
  return () => {
135
247
  document.removeEventListener('mousemove', handleMouseMove)
136
248
  document.removeEventListener('mouseup', handleMouseUp)
@@ -140,6 +252,20 @@ export const Window = ({
140
252
  }
141
253
  }, [isDragging])
142
254
 
255
+ useEffect(() => {
256
+ if (isResizing) {
257
+ document.addEventListener('mousemove', handleResizeMove)
258
+ document.addEventListener('mouseup', handleResizeEnd)
259
+ document.body.style.userSelect = 'none'
260
+
261
+ return () => {
262
+ document.removeEventListener('mousemove', handleResizeMove)
263
+ document.removeEventListener('mouseup', handleResizeEnd)
264
+ document.body.style.userSelect = ''
265
+ }
266
+ }
267
+ }, [isResizing])
268
+
143
269
  // Window control handlers
144
270
  const handleMinimize = (e) => {
145
271
  e.stopPropagation()
@@ -182,6 +308,7 @@ export const Window = ({
182
308
  'window',
183
309
  maximized && 'window--maximized',
184
310
  isDragging && 'window--dragging',
311
+ isResizing && 'window--resizing',
185
312
  className
186
313
  ].filter(Boolean).join(' ')
187
314
 
@@ -257,6 +384,47 @@ export const Window = ({
257
384
  {statusBar}
258
385
  </div>
259
386
  )}
387
+
388
+ {/* Resize Handles */}
389
+ {resizable && !maximized && (
390
+ <>
391
+ {/* Edge handles */}
392
+ <div
393
+ className="window__resize-handle window__resize-handle--n"
394
+ onMouseDown={(e) => handleResizeStart(e, 'n')}
395
+ />
396
+ <div
397
+ className="window__resize-handle window__resize-handle--s"
398
+ onMouseDown={(e) => handleResizeStart(e, 's')}
399
+ />
400
+ <div
401
+ className="window__resize-handle window__resize-handle--e"
402
+ onMouseDown={(e) => handleResizeStart(e, 'e')}
403
+ />
404
+ <div
405
+ className="window__resize-handle window__resize-handle--w"
406
+ onMouseDown={(e) => handleResizeStart(e, 'w')}
407
+ />
408
+
409
+ {/* Corner handles */}
410
+ <div
411
+ className="window__resize-handle window__resize-handle--ne"
412
+ onMouseDown={(e) => handleResizeStart(e, 'ne')}
413
+ />
414
+ <div
415
+ className="window__resize-handle window__resize-handle--nw"
416
+ onMouseDown={(e) => handleResizeStart(e, 'nw')}
417
+ />
418
+ <div
419
+ className="window__resize-handle window__resize-handle--se"
420
+ onMouseDown={(e) => handleResizeStart(e, 'se')}
421
+ />
422
+ <div
423
+ className="window__resize-handle window__resize-handle--sw"
424
+ onMouseDown={(e) => handleResizeStart(e, 'sw')}
425
+ />
426
+ </>
427
+ )}
260
428
  </div>
261
429
  )
262
430
  }
@@ -20,6 +20,11 @@
20
20
  white-space: nowrap;
21
21
  }
22
22
 
23
+ /* Ensure icons inside buttons don't block clicks */
24
+ .btn .icon {
25
+ pointer-events: none;
26
+ }
27
+
23
28
  .btn.outlined {
24
29
  color: var(--primary-color);
25
30
  border: solid 1px var(--primary-color);
@@ -111,7 +111,8 @@ export const Button = (props) => {
111
111
  icon: loading ? 'hourglass_empty' : icon,
112
112
  size: size === 'small' ? 'small' : size === 'large' ? 'normal' : 'small',
113
113
  disabled: disabled || loading,
114
- className: loading ? 'loading-icon' : ''
114
+ className: loading ? 'loading-icon' : '',
115
+ eventPropagation: true, // Allow click events to bubble up to button
115
116
  }
116
117
 
117
118
  return (