@@ -17,6 +17,7 @@ import {
17
17
$styles ,
18
18
$styleSourceSelections ,
19
19
$selectedBreakpoint ,
20
+ $selectedInstanceSelector ,
20
21
} from "~/shared/nano-states" ;
21
22
import {
22
23
$breakpointsMenuView ,
@@ -56,6 +57,10 @@ import { findAvailableVariables } from "~/shared/data-variables";
56
57
import { atom } from "nanostores" ;
57
58
import type { StyleValue } from "@webstudio-is/css-engine" ;
58
59
import { createBatchUpdate } from "../features/style-panel/shared/use-style-data" ;
60
+ import { applyOperations } from "../features/ai/apply-operations" ;
61
+ import { getInstanceStyleDecl } from "../features/style-panel/shared/model" ;
62
+ import { getElementByInstanceSelector } from "~/shared/dom-utils" ;
63
+ import type { operations } from "@webstudio-is/ai" ;
59
64
60
65
export const $styleSourceInputElement = atom < HTMLInputElement | undefined > ( ) ;
61
66
@@ -226,6 +231,103 @@ export const convertPositionToProperty = (
226
231
batch . publish ( ) ;
227
232
} ;
228
233
234
+ export const convertToAbsolutePosition = ( ) => {
235
+ const selectedInstance = $selectedInstance . get ( ) ;
236
+ const selectedInstanceSelector = $selectedInstanceSelector . get ( ) ;
237
+
238
+ if ( ! selectedInstance || ! selectedInstanceSelector ) {
239
+ return ;
240
+ }
241
+
242
+ const position = getInstanceStyleDecl ( "position" , selectedInstanceSelector ) ;
243
+ if (
244
+ position . usedValue . type === "keyword" &&
245
+ position . usedValue . value === "absolute"
246
+ ) {
247
+ return ;
248
+ }
249
+
250
+ // Ensure parent instance isn't using `position: static`
251
+ const selectedInstancePath = $selectedInstancePath . get ( ) ! ;
252
+ const parent = selectedInstancePath [ 1 ] ;
253
+
254
+ let parentRect : DOMRect | undefined ;
255
+ let isParentStatic = false ;
256
+
257
+ if ( parent ) {
258
+ const parentElement = getElementByInstanceSelector ( parent . instanceSelector ) ;
259
+ parentRect = parentElement ?. getBoundingClientRect ( ) ;
260
+
261
+ // Change parent position to relative if it's static
262
+ const parentPosition = getInstanceStyleDecl (
263
+ "position" ,
264
+ parent . instanceSelector
265
+ ) ;
266
+ isParentStatic =
267
+ parentPosition . usedValue . type === "keyword" &&
268
+ parentPosition . usedValue . value === "static" ;
269
+ }
270
+
271
+ const instanceElement = getElementByInstanceSelector (
272
+ selectedInstanceSelector
273
+ ) ;
274
+
275
+ if ( ! instanceElement ) {
276
+ return ;
277
+ }
278
+
279
+ const operations : operations . WsOperations = [ ] ;
280
+
281
+ if ( isParentStatic ) {
282
+ operations . push ( {
283
+ operation : "applyStyles" ,
284
+ instanceIds : [ parent . instance . id ] ,
285
+ styles : [
286
+ {
287
+ property : "position" ,
288
+ value : { type : "keyword" , value : "relative" } ,
289
+ } ,
290
+ ] ,
291
+ } ) ;
292
+ }
293
+
294
+ const rect = instanceElement . getBoundingClientRect ( ) ;
295
+
296
+ operations . push ( {
297
+ operation : "applyStyles" ,
298
+ instanceIds : [ selectedInstance . id ] ,
299
+ styles : [
300
+ {
301
+ property : "position" ,
302
+ value : { type : "keyword" , value : "absolute" } ,
303
+ } ,
304
+ {
305
+ property : "top" ,
306
+ value : {
307
+ type : "unit" ,
308
+ value : rect . top - ( parentRect ?. top ?? 0 ) ,
309
+ unit : "px" ,
310
+ } ,
311
+ } ,
312
+ {
313
+ property : "left" ,
314
+ value : {
315
+ type : "unit" ,
316
+ value : rect . left - ( parentRect ?. left ?? 0 ) ,
317
+ unit : "px" ,
318
+ } ,
319
+ } ,
320
+ // Unset margin properties.
321
+ { property : "marginTop" , value : null } ,
322
+ { property : "marginLeft" , value : null } ,
323
+ { property : "marginRight" , value : null } ,
324
+ { property : "marginBottom" , value : null } ,
325
+ ] ,
326
+ } ) ;
327
+
328
+ applyOperations ( operations ) ;
329
+ } ;
330
+
229
331
export const wrapIn = ( component : string ) => {
230
332
const instancePath = $selectedInstancePath . get ( ) ;
231
333
// global root or body are selected
@@ -564,6 +666,10 @@ export const { emitCommand, subscribeCommands } = createCommandsEmitter({
564
666
name : "convertPositionToMargin" ,
565
667
handler : ( ) => convertPositionToProperty ( "margin" ) ,
566
668
} ,
669
+ {
670
+ name : "convertToAbsolutePosition" ,
671
+ handler : convertToAbsolutePosition ,
672
+ } ,
567
673
568
674
{
569
675
name : "deleteInstanceBuilder" ,
0 commit comments