@@ -15,12 +15,12 @@ import {
15
15
type Size ,
16
16
} from "@zag-js/rect-utils"
17
17
import { subscribe } from "@zag-js/store"
18
- import { ensureProps , invariant , match , pick } from "@zag-js/utils"
18
+ import { clampValue , ensureProps , invariant , match , pick } from "@zag-js/utils"
19
19
import * as dom from "./floating-panel.dom"
20
20
import { panelStack } from "./floating-panel.store"
21
21
import type { FloatingPanelSchema , IntlTranslations , Stage } from "./floating-panel.types"
22
22
23
- const { not } = createGuards < FloatingPanelSchema > ( )
23
+ const { not, and } = createGuards < FloatingPanelSchema > ( )
24
24
25
25
const defaultTranslations : IntlTranslations = {
26
26
minimize : "Minimize window" ,
@@ -32,7 +32,7 @@ export const machine = createMachine<FloatingPanelSchema>({
32
32
props ( { props } ) {
33
33
ensureProps ( props , [ "id" ] , "floating-panel" )
34
34
return {
35
- strategy : "absolute " ,
35
+ strategy : "fixed " ,
36
36
gridSize : 1 ,
37
37
defaultSize : { width : 320 , height : 240 } ,
38
38
defaultPosition : { x : 300 , y : 100 } ,
@@ -140,10 +140,20 @@ export const machine = createMachine<FloatingPanelSchema>({
140
140
closed : {
141
141
tags : [ "closed" ] ,
142
142
on : {
143
- OPEN : {
143
+ "CONTROLLED. OPEN" : {
144
144
target : "open" ,
145
- actions : [ "invokeOnOpen" , " setAnchorPosition", "setPositionStyle" , "setSizeStyle" , "focusContentEl" ] ,
145
+ actions : [ "setAnchorPosition" , "setPositionStyle" , "setSizeStyle" , "focusContentEl" ] ,
146
146
} ,
147
+ OPEN : [
148
+ {
149
+ guard : "isOpenControlled" ,
150
+ actions : [ "invokeOnOpen" ] ,
151
+ } ,
152
+ {
153
+ target : "open" ,
154
+ actions : [ "invokeOnOpen" , "setAnchorPosition" , "setPositionStyle" , "setSizeStyle" , "focusContentEl" ] ,
155
+ } ,
156
+ ] ,
147
157
} ,
148
158
} ,
149
159
@@ -162,15 +172,32 @@ export const machine = createMachine<FloatingPanelSchema>({
162
172
target : "open.resizing" ,
163
173
actions : [ "setPrevSize" ] ,
164
174
} ,
165
- CLOSE : {
166
- target : "closed" ,
167
- actions : [ "invokeOnClose" , "resetRect" , "focusTriggerEl" ] ,
168
- } ,
169
- ESCAPE : {
170
- guard : "closeOnEsc" ,
175
+ "CONTROLLED.CLOSE" : {
171
176
target : "closed" ,
172
- actions : [ "invokeOnClose" , " resetRect", "focusTriggerEl" ] ,
177
+ actions : [ "resetRect" , "focusTriggerEl" ] ,
173
178
} ,
179
+ CLOSE : [
180
+ {
181
+ guard : "isOpenControlled" ,
182
+ target : "closed" ,
183
+ actions : [ "invokeOnClose" ] ,
184
+ } ,
185
+ {
186
+ target : "closed" ,
187
+ actions : [ "invokeOnClose" , "resetRect" , "focusTriggerEl" ] ,
188
+ } ,
189
+ ] ,
190
+ ESCAPE : [
191
+ {
192
+ guard : and ( "isOpenControlled" , "closeOnEsc" ) ,
193
+ actions : [ "invokeOnClose" ] ,
194
+ } ,
195
+ {
196
+ guard : "closeOnEsc" ,
197
+ target : "closed" ,
198
+ actions : [ "invokeOnClose" , "resetRect" , "focusTriggerEl" ] ,
199
+ } ,
200
+ ] ,
174
201
MINIMIZE : {
175
202
actions : [ "setMinimized" ] ,
176
203
} ,
@@ -198,10 +225,21 @@ export const machine = createMachine<FloatingPanelSchema>({
198
225
target : "open" ,
199
226
actions : [ "invokeOnDragEnd" ] ,
200
227
} ,
201
- CLOSE : {
228
+ "CONTROLLED. CLOSE" : {
202
229
target : "closed" ,
203
- actions : [ "invokeOnClose" , " resetRect"] ,
230
+ actions : [ "resetRect" ] ,
204
231
} ,
232
+ CLOSE : [
233
+ {
234
+ guard : "isOpenControlled" ,
235
+ target : "closed" ,
236
+ actions : [ "invokeOnClose" ] ,
237
+ } ,
238
+ {
239
+ target : "closed" ,
240
+ actions : [ "invokeOnClose" , "resetRect" ] ,
241
+ } ,
242
+ ] ,
205
243
ESCAPE : {
206
244
target : "open" ,
207
245
} ,
@@ -220,10 +258,21 @@ export const machine = createMachine<FloatingPanelSchema>({
220
258
target : "open" ,
221
259
actions : [ "invokeOnResizeEnd" ] ,
222
260
} ,
223
- CLOSE : {
261
+ "CONTROLLED. CLOSE" : {
224
262
target : "closed" ,
225
- actions : [ "invokeOnClose" , " resetRect"] ,
263
+ actions : [ "resetRect" ] ,
226
264
} ,
265
+ CLOSE : [
266
+ {
267
+ guard : "isOpenControlled" ,
268
+ target : "closed" ,
269
+ actions : [ "invokeOnClose" ] ,
270
+ } ,
271
+ {
272
+ target : "closed" ,
273
+ actions : [ "invokeOnClose" , "resetRect" ] ,
274
+ } ,
275
+ ] ,
227
276
ESCAPE : {
228
277
target : "open" ,
229
278
} ,
@@ -236,15 +285,20 @@ export const machine = createMachine<FloatingPanelSchema>({
236
285
closeOnEsc : ( { prop } ) => ! ! prop ( "closeOnEscape" ) ,
237
286
isMaximized : ( { context } ) => context . get ( "stage" ) === "maximized" ,
238
287
isMinimized : ( { context } ) => context . get ( "stage" ) === "minimized" ,
288
+ isOpenControlled : ( { prop } ) => prop ( "open" ) != undefined ,
239
289
} ,
240
290
241
291
effects : {
242
- trackPointerMove ( { scope, send, event : evt } ) {
292
+ trackPointerMove ( { scope, send, event : evt , prop } ) {
243
293
const doc = scope . getDoc ( )
294
+ const boundaryEl = prop ( "getBoundaryEl" ) ?.( )
295
+ const boundaryRect = dom . getBoundaryRect ( scope , boundaryEl , false )
244
296
return trackPointerMove ( doc , {
245
297
onPointerMove ( { point, event } ) {
246
298
const { altKey, shiftKey } = event
247
- send ( { type : "DRAG" , position : point , axis : evt . axis , altKey, shiftKey } )
299
+ let x = clampValue ( point . x , boundaryRect . x , boundaryRect . x + boundaryRect . width )
300
+ let y = clampValue ( point . y , boundaryRect . y , boundaryRect . y + boundaryRect . height )
301
+ send ( { type : "DRAG" , position : { x, y } , axis : evt . axis , altKey, shiftKey } )
248
302
} ,
249
303
onPointerUp ( ) {
250
304
send ( { type : "DRAG_END" } )
0 commit comments