@opentiny/tiny-engine-canvas 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.
Files changed (52) hide show
  1. package/.eslintrc.js +42 -0
  2. package/README.md +7 -0
  3. package/canvas.html +212 -0
  4. package/dist/index.js +48919 -0
  5. package/index.html +13 -0
  6. package/package.json +30 -0
  7. package/public/favicon.ico +0 -0
  8. package/src/Design.vue +53 -0
  9. package/src/assets/logo.png +0 -0
  10. package/src/canvas.js +34 -0
  11. package/src/components/builtin/CanvasBox.vue +22 -0
  12. package/src/components/builtin/CanvasCol.vue +89 -0
  13. package/src/components/builtin/CanvasCollection.js +278 -0
  14. package/src/components/builtin/CanvasCollection.vue +106 -0
  15. package/src/components/builtin/CanvasIcon.vue +30 -0
  16. package/src/components/builtin/CanvasImg.vue +18 -0
  17. package/src/components/builtin/CanvasPlaceholder.vue +26 -0
  18. package/src/components/builtin/CanvasRow.vue +67 -0
  19. package/src/components/builtin/CanvasRowColContainer.vue +42 -0
  20. package/src/components/builtin/CanvasSlot.vue +22 -0
  21. package/src/components/builtin/CanvasText.vue +18 -0
  22. package/src/components/builtin/builtin.json +955 -0
  23. package/src/components/builtin/helper.js +46 -0
  24. package/src/components/builtin/index.js +33 -0
  25. package/src/components/common/index.js +158 -0
  26. package/src/components/container/CanvasAction.vue +554 -0
  27. package/src/components/container/CanvasContainer.vue +244 -0
  28. package/src/components/container/CanvasDivider.vue +246 -0
  29. package/src/components/container/CanvasDragItem.vue +38 -0
  30. package/src/components/container/CanvasFooter.vue +86 -0
  31. package/src/components/container/CanvasMenu.vue +214 -0
  32. package/src/components/container/CanvasResize.vue +195 -0
  33. package/src/components/container/CanvasResizeBorder.vue +219 -0
  34. package/src/components/container/container.js +791 -0
  35. package/src/components/container/keyboard.js +147 -0
  36. package/src/components/container/shortCutPopover.vue +181 -0
  37. package/src/components/render/CanvasEmpty.vue +14 -0
  38. package/src/components/render/RenderMain.js +408 -0
  39. package/src/components/render/context.js +53 -0
  40. package/src/components/render/render.js +689 -0
  41. package/src/components/render/runner.js +140 -0
  42. package/src/i18n/en.json +5 -0
  43. package/src/i18n/zh.json +5 -0
  44. package/src/i18n.js +21 -0
  45. package/src/index.js +96 -0
  46. package/src/locale.js +19 -0
  47. package/src/lowcode.js +104 -0
  48. package/src/main.js +17 -0
  49. package/test/form.json +690 -0
  50. package/test/group.json +99 -0
  51. package/test/jsslot.json +427 -0
  52. package/vite.config.js +73 -0
@@ -0,0 +1,791 @@
1
+ /**
2
+ * Copyright (c) 2023 - present TinyEngine Authors.
3
+ * Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license.
6
+ *
7
+ * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8
+ * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9
+ * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10
+ *
11
+ */
12
+
13
+ import { reactive, toRaw, nextTick, shallowReactive } from 'vue'
14
+ import {
15
+ addScript as appendScript,
16
+ addStyle as appendStyle,
17
+ copyObject,
18
+ NODE_UID,
19
+ NODE_TAG,
20
+ NODE_LOOP
21
+ } from '../common'
22
+ import { useCanvas, useLayout, useResource, useTranslate } from '@opentiny/tiny-engine-controller'
23
+ export const POSITION = Object.freeze({
24
+ TOP: 'top',
25
+ BOTTOM: 'bottom',
26
+ LEFT: 'left',
27
+ RIGHT: 'right',
28
+ IN: 'in',
29
+ FORBID: 'forbid'
30
+ })
31
+ import { isVsCodeEnv } from '@opentiny/tiny-engine-common/js/environments'
32
+
33
+ const initialDragState = {
34
+ keydown: false,
35
+ draging: false,
36
+ data: null,
37
+ position: null, // ghost位置
38
+ mouse: null, // iframe里鼠标位置
39
+ element: null,
40
+ offset: {}
41
+ }
42
+
43
+ export const canvasState = shallowReactive({
44
+ type: 'normal',
45
+ schema: null,
46
+ renderer: null, // 存放画布内的api
47
+ iframe: null,
48
+ loading: true,
49
+ current: null,
50
+ parent: null,
51
+ loopId: null
52
+ })
53
+
54
+ export const getContext = () => {
55
+ return getRenderer().getContext()
56
+ }
57
+
58
+ // 记录拖拽状态
59
+ export const dragState = reactive({
60
+ ...initialDragState
61
+ })
62
+
63
+ export const initialRectState = {
64
+ top: 0,
65
+ height: 0,
66
+ width: 0,
67
+ left: 0,
68
+ schema: null,
69
+ configure: null,
70
+ componentName: ''
71
+ }
72
+
73
+ const initialLineState = {
74
+ top: 0,
75
+ height: 0,
76
+ width: 0,
77
+ left: 0,
78
+ position: '',
79
+ id: '',
80
+ config: null
81
+ }
82
+
83
+ // 选中画布中元素时的状态
84
+ export const selectState = reactive({
85
+ ...initialRectState
86
+ })
87
+
88
+ // 鼠标移入画布中元素时的状态
89
+ export const hoverState = reactive({
90
+ ...initialRectState
91
+ })
92
+
93
+ // 拖拽时的位置状态
94
+ export const lineState = reactive({
95
+ ...initialLineState
96
+ })
97
+
98
+ export const dragStart = (
99
+ data,
100
+ element,
101
+ { offsetX = 0, offsetY = 0, horizontal, vertical, width, height, x, y } = {}
102
+ ) => {
103
+ // 表示鼠标按下开始拖拽
104
+ dragState.keydown = true
105
+ dragState.data = data || {}
106
+
107
+ // 记录上次一开始拖拽的时间
108
+ dragState.timer = Date.now()
109
+
110
+ // 如果element存在表示在iframe内部拖拽
111
+ dragState.element = element
112
+ dragState.offset = { offsetX, offsetY, horizontal, vertical, width, height, x, y }
113
+ clearHover()
114
+ }
115
+
116
+ export const clearLineState = () => {
117
+ Object.assign(lineState, initialLineState)
118
+ }
119
+
120
+ export const dragEnd = () => {
121
+ const { element, data } = dragState
122
+
123
+ if (element && canvasState.type === 'absolute') {
124
+ data.props = data.props || {}
125
+ data.props.style = element.style.cssText
126
+ }
127
+
128
+ // 重置拖拽状态
129
+ Object.assign(dragState, initialDragState)
130
+
131
+ // 重置拖拽插入位置状态
132
+ clearLineState()
133
+ smoothScroll.stop()
134
+ }
135
+
136
+ export const getOffset = (element) => {
137
+ if (element.ownerDocument === document) {
138
+ return { x: 0, y: 0 }
139
+ }
140
+ const { x, y, bottom, top } = canvasState.iframe.getBoundingClientRect()
141
+ return { x, y, bottom, top }
142
+ }
143
+
144
+ export const getElement = (element) => {
145
+ // 如果当前元素是body
146
+ if (element === element.ownerDocument.body) {
147
+ return element
148
+ }
149
+ if (!element || element.nodeType !== 1) {
150
+ return undefined
151
+ }
152
+
153
+ if (element.getAttribute(NODE_UID)) {
154
+ return element
155
+ } else if (element.parentElement) {
156
+ return getElement(element.parentElement)
157
+ }
158
+
159
+ return undefined
160
+ }
161
+
162
+ const inserAfter = ({ parent, node, data }) => {
163
+ const parentChildren = parent.children
164
+ const index = parentChildren.indexOf(node)
165
+ parent.children.splice(index + 1, 0, data)
166
+ }
167
+
168
+ const insertBefore = ({ parent, node, data }) => {
169
+ const parentChildren = parent.children
170
+ const index = parentChildren.indexOf(node)
171
+ parent.children.splice(index, 0, data)
172
+ }
173
+
174
+ const insertInner = ({ node, data }, position) => {
175
+ node.children = node.children || []
176
+
177
+ if (position === POSITION.TOP || position === POSITION.LEFT) {
178
+ node.children.unshift(data)
179
+ } else {
180
+ node.children.push(data)
181
+ }
182
+ }
183
+
184
+ export const removeNode = ({ parent, node }) => {
185
+ const parentChildren = parent.children || parent.value
186
+ const index = parentChildren.indexOf(node)
187
+
188
+ if (index > -1) {
189
+ parentChildren.splice(index, 1)
190
+ } else {
191
+ const templates = parentChildren.filter(({ componentName }) => componentName === 'Template')
192
+
193
+ templates.forEach((template) => {
194
+ const { children } = template
195
+
196
+ if (children.length) {
197
+ children.splice(children.indexOf(node), 1)
198
+ }
199
+
200
+ if (!children.length) {
201
+ parentChildren.splice(parentChildren.indexOf(template), 1)
202
+ }
203
+ })
204
+ }
205
+ }
206
+
207
+ export const removeNodeById = (id) => {
208
+ removeNode(getNode(id, true))
209
+ clearSelect()
210
+ getController().addHistory()
211
+ canvasState.emit('remove')
212
+ }
213
+
214
+ export const insertNode = (node, position = POSITION.IN, select = true) => {
215
+ if (!node.parent) {
216
+ insertInner({ node: canvasState.schema, data: node.data }, position)
217
+ } else {
218
+ switch (position) {
219
+ case POSITION.TOP:
220
+ case POSITION.LEFT:
221
+ insertBefore(node)
222
+ break
223
+ case POSITION.BOTTOM:
224
+ case POSITION.RIGHT:
225
+ inserAfter(node)
226
+ break
227
+ case POSITION.IN:
228
+ insertInner(node)
229
+ break
230
+ default:
231
+ insertInner(node)
232
+ break
233
+ }
234
+ }
235
+
236
+ select && setTimeout(() => selectNode(node.data.id))
237
+
238
+ getController().addHistory()
239
+ }
240
+
241
+ export const addComponent = (data, position) => {
242
+ const { schema, parent } = getCurrent()
243
+
244
+ insertNode({ node: schema, parent, data }, position)
245
+ }
246
+
247
+ export const copyNode = (id) => {
248
+ const { node, parent } = getNode(id, true)
249
+
250
+ inserAfter({ parent, node, data: copyObject(node) })
251
+ getController().addHistory()
252
+ }
253
+
254
+ export const onMouseUp = ({ target }) => {
255
+ const { draging, data } = dragState
256
+ const { position } = lineState
257
+ const absolute = canvasState.type === 'absolute'
258
+ const sourceId = data?.id
259
+ const lineId = lineState.id
260
+ const allowInsert = position !== POSITION.FORBID
261
+
262
+ if (draging && allowInsert) {
263
+ const { parent, node } = getNode(lineId, true) || {} // target
264
+ const targetNode = { parent, node, data: toRaw(data) }
265
+
266
+ if (sourceId) {
267
+ // 内部拖拽
268
+ if (sourceId !== lineId && !absolute) {
269
+ removeNode(getNode(sourceId, true))
270
+ insertNode(targetNode, position)
271
+ }
272
+ } else {
273
+ // 从外部拖拽进来的无ID,insert
274
+ if (absolute) {
275
+ targetNode.node = getSchema()
276
+ data.props = data.props || {}
277
+ data.props.style = {
278
+ position: 'absolute',
279
+ top: dragState.mouse.y + 'px',
280
+ left: dragState.mouse.x + 'px'
281
+ }
282
+ }
283
+
284
+ insertNode(targetNode, position)
285
+ }
286
+ }
287
+
288
+ // 重置拖拽状态
289
+ dragEnd()
290
+ }
291
+
292
+ const smoothScroll = {
293
+ timmer: null,
294
+ /**
295
+ *
296
+ * @param {*} up 方向
297
+ * @param {*} step 每次滚动距离
298
+ * @param {*} time 滚动延时(不得大于系统滚动时长,否则可能出现卡顿效果)
299
+ */
300
+ start(up, step = 40, time = 100) {
301
+ const dom = getDocument().documentElement
302
+ const fn = () => {
303
+ const top = up ? dom.scrollTop + step : dom.scrollTop - step
304
+
305
+ dom.scrollTo({ top, behavior: 'smooth' })
306
+ this.timmer = setTimeout(fn, time)
307
+ }
308
+
309
+ this.timmer || fn()
310
+ },
311
+ stop() {
312
+ clearTimeout(this.timmer)
313
+ this.timmer = null
314
+ }
315
+ }
316
+
317
+ // 绝对布局
318
+ const absoluteMove = (event, element) => {
319
+ const { clientX, clientY } = event
320
+ const { offsetX, offsetY, horizontal, vertical, height, width, x, y } = dragState.offset
321
+
322
+ element.style.position = 'absolute'
323
+
324
+ if (!horizontal) {
325
+ // 未传方向信息时判断为移动元素位置
326
+ element.style.top = `${clientY - offsetY}px`
327
+ element.style.left = `${clientX - offsetX}px`
328
+ } else {
329
+ // 调整元素大小
330
+ if (horizontal === 'start') {
331
+ element.style.left = `${clientX}px`
332
+ element.style.width = `${width + (x - clientX)}px`
333
+ }
334
+
335
+ if (horizontal === 'end') {
336
+ element.style.width = `${clientX - x}px`
337
+ }
338
+
339
+ if (vertical === 'start') {
340
+ element.style.top = `${clientY}px`
341
+ element.style.height = `${height + (y - clientY)}px`
342
+ }
343
+
344
+ if (vertical === 'end') {
345
+ element.style.height = `${clientY - y}px`
346
+ }
347
+ }
348
+ updateRect()
349
+ }
350
+
351
+ const setDragPosition = ({ clientX, x, clientY, y, offsetBottom, offsetTop }) => {
352
+ const left = clientX + x
353
+ const top = clientY + y
354
+ if (clientY < 20) {
355
+ smoothScroll.start(false)
356
+ } else if (offsetBottom - clientY - offsetTop < 20) {
357
+ smoothScroll.start(true)
358
+ } else {
359
+ smoothScroll.stop()
360
+ }
361
+
362
+ dragState.position = { left, top }
363
+ }
364
+
365
+ export const dragMove = (event, isHover) => {
366
+ if (!dragState.draging && dragState.keydown && new Date().getTime() - dragState.timer < 200) {
367
+ return
368
+ }
369
+
370
+ const { x, y, bottom: offsetBottom, top: offsetTop } = getOffset(event.target)
371
+ const { clientX, clientY } = event
372
+ const { element } = dragState
373
+ const absolute = canvasState.type === 'absolute'
374
+
375
+ dragState.draging = dragState.keydown
376
+
377
+ dragState.mouse = { x: clientX, y: clientY }
378
+
379
+ // 如果仅仅是mouseover事件直接return,并重置拖拽位置状态,优化性能
380
+ if (isHover) {
381
+ lineState.position = ''
382
+ setHoverRect(getElement(event.target), null)
383
+
384
+ return
385
+ }
386
+
387
+ setHoverRect(getElement(event.target), dragState.data)
388
+
389
+ if (dragState.draging) {
390
+ // 绝对布局时走的逻辑
391
+ if (element && absolute) {
392
+ absoluteMove(event, element)
393
+ }
394
+ setDragPosition({ clientX, x, clientY, y, offsetBottom, offsetTop })
395
+ }
396
+ }
397
+
398
+ export const clearHover = () => {
399
+ Object.assign(hoverState, initialRectState, { slot: null })
400
+ }
401
+
402
+ export const clearSelect = () => {
403
+ canvasState.current = null
404
+ canvasState.parent = null
405
+ Object.assign(selectState, initialRectState)
406
+ }
407
+
408
+ export const querySelectById = (id, type = '') => {
409
+ let selector = `[${NODE_UID}="${id}"]`
410
+ const doc = canvasState.iframe.contentDocument
411
+ let element = doc.querySelector(selector)
412
+ const loopId = element?.getAttribute('loop-id')
413
+ if (element && loopId) {
414
+ const currentLoopId = getCurrent().loopId
415
+ selector = `[${NODE_UID}="${id}"][${NODE_LOOP}="${currentLoopId}"]`
416
+ element = doc.querySelector(selector)
417
+ }
418
+ return element
419
+ }
420
+
421
+ export const getCurrentElement = () => querySelectById(getCurrent().schema?.id)
422
+
423
+ export const updateRect = (id) => {
424
+ id = (typeof id === 'string' && id) || getCurrent().schema?.id
425
+ clearHover()
426
+
427
+ if (id) {
428
+ setTimeout(() => setSelectRect(querySelectById(id)))
429
+ } else {
430
+ clearSelect()
431
+ }
432
+ }
433
+ // type == clickTree, 为点击大纲; type == loop-id=xxx ,为点击循环数据
434
+ export const selectNode = async (id, type) => {
435
+ if (type && type.indexOf('loop-id') > -1) {
436
+ const loopId = type.split('=')[1]
437
+ canvasState.loopId = loopId
438
+ }
439
+ const { node, parent } = getNode(id, true) || {}
440
+ let element = querySelectById(id, type)
441
+
442
+ if (element) {
443
+ const { rootSelector } = getConfigure(node.componentName)
444
+ element = rootSelector ? element.querySelector(rootSelector) : element
445
+ }
446
+
447
+ canvasState.current = node
448
+ canvasState.parent = parent
449
+
450
+ await scrollToNode(element)
451
+ setSelectRect(element)
452
+ canvasState.emit('selected', node, parent, type)
453
+
454
+ return node
455
+ }
456
+
457
+ export const hoverNode = (id, data) => {
458
+ const element = querySelectById(id)
459
+ element && setHoverRect(element, data)
460
+ }
461
+
462
+ export const scrollToNode = (element) => {
463
+ if (element) {
464
+ const container = getDocument().documentElement
465
+ const h = container?.clientHeight
466
+ const { y, height } = element.getBoundingClientRect()
467
+
468
+ if (y < 0) {
469
+ container.scrollTo({ top: container.scrollTop + y - 15 })
470
+ } else if (y > h) {
471
+ container.scrollTo({ top: y + height - h + 15 })
472
+ }
473
+ }
474
+
475
+ return nextTick()
476
+ }
477
+ const setSelectRect = (element) => {
478
+ element = element || getDocument().body
479
+
480
+ const { left, height, top, width } = element.getBoundingClientRect()
481
+ const { x, y } = getOffset(element)
482
+ const componentName = getCurrent().schema?.componentName || ''
483
+ const scale = useLayout().getScale()
484
+ clearHover()
485
+ Object.assign(selectState, {
486
+ width: width * scale,
487
+ height: height * scale,
488
+ top: top * scale + y,
489
+ left: left * scale + x,
490
+ componentName
491
+ })
492
+ }
493
+
494
+ const isBodyEl = (element) => element.nodeName === 'BODY'
495
+
496
+ const setHoverRect = (element, data) => {
497
+ if (!element) {
498
+ return clearHover()
499
+ }
500
+ const componentName = element.getAttribute(NODE_TAG)
501
+ const id = element.getAttribute(NODE_UID)
502
+ const configure = getConfigure(componentName)
503
+ const rect = element.getBoundingClientRect()
504
+ const { left, height, top, width } = rect
505
+ const { x, y } = getOffset(element)
506
+ const scale = useLayout().getScale()
507
+
508
+ hoverState.configure = configure
509
+
510
+ if (data) {
511
+ let childEle = null
512
+ lineState.id = id
513
+ lineState.configure = configure
514
+ const rectType = isBodyEl(element) ? POSITION.IN : getPosLine(rect, configure).type
515
+
516
+ // 如果拖拽经过的元素是body或者是带有容器属性的盒子,并且在元素内部插入,则需要特殊处理
517
+ if ((isBodyEl(element) || configure?.isContainer) && rectType === POSITION.IN) {
518
+ const { node } = isBodyEl(element) ? { node: getSchema() } : getNode(id, true) || {}
519
+ const children = node?.children || []
520
+ if (children.length > 0) {
521
+ // 如果容器盒子有子节点,则以最后一个子节点为拖拽参照物
522
+ const lastNode = children[children.length - 1]
523
+ childEle = querySelectById(lastNode.id)
524
+ const childComponentName = element.getAttribute(childEle)
525
+ const Childconfigure = getConfigure(childComponentName)
526
+ lineState.id = lastNode.id
527
+ lineState.configure = Childconfigure
528
+ }
529
+ }
530
+
531
+ // 如果容器盒子有子元素
532
+ if (childEle) {
533
+ const childRect = childEle.getBoundingClientRect()
534
+ const { left, height, top, width } = childRect
535
+ const { x, y } = getOffset(childEle)
536
+ Object.assign(lineState, {
537
+ width: width * scale,
538
+ height: height * scale,
539
+ top: top * scale + y,
540
+ left: left * scale + x,
541
+ position: canvasState.type === 'absolute' || getPosLine(childRect, lineState.configure).type
542
+ })
543
+ } else {
544
+ Object.assign(lineState, {
545
+ width: width * scale,
546
+ height: height * scale,
547
+ top: top * scale + y,
548
+ left: left * scale + x,
549
+ position: canvasState.type === 'absolute' || getPosLine(rect, configure).type
550
+ })
551
+ }
552
+
553
+ useLayout().closePlugin()
554
+ }
555
+
556
+ // 设置元素hover状态
557
+ Object.assign(hoverState, {
558
+ width: width * scale,
559
+ height: height * scale,
560
+ top: top * scale + y,
561
+ left: left * scale + x,
562
+ componentName
563
+ })
564
+ return undefined
565
+ }
566
+
567
+ /**
568
+ * 是否允许插入
569
+ * @param {*} configure 当前放置目标的 configure,比如getConfigure(componentName)
570
+ * @param {*} data 当前插入目标的schame数据
571
+ * @returns
572
+ */
573
+ export const allowInsert = (configure = hoverState.configure || {}, data = dragState.data || {}) => {
574
+ const { nestingRule = {} } = configure
575
+ const { childWhitelist = [], descendantBlacklist = [] } = nestingRule
576
+
577
+ // 要插入的父节点必须是容器
578
+ if (!configure.isContainer) {
579
+ return false
580
+ }
581
+
582
+ let flag = true
583
+ // 白名单
584
+ flag = childWhitelist.length ? childWhitelist.includes(data?.componentName) : true
585
+
586
+ // 黑名单
587
+ if (descendantBlacklist.length) {
588
+ flag = !descendantBlacklist.includes(data?.componentName)
589
+ }
590
+
591
+ return flag
592
+ }
593
+
594
+ export const getConfigure = (targetName) => {
595
+ const material = getController().getMaterial(targetName)
596
+
597
+ // 这里如果是区块插槽,则返回标识为容器的对象
598
+ if (targetName === 'Template') {
599
+ return {
600
+ isContainer: true
601
+ }
602
+ }
603
+
604
+ return material?.content?.configure || material.configure || {}
605
+ }
606
+
607
+ // 获取位置信息,返回状态
608
+ const lineAbs = 20
609
+ const getPosLine = (rect, configure) => {
610
+ const mousePos = dragState.mouse
611
+ const yAbs = Math.min(lineAbs, rect.height / 3)
612
+ const xAbs = Math.min(lineAbs, rect.width / 3)
613
+ let type
614
+
615
+ if (mousePos.y < rect.top + yAbs) {
616
+ type = POSITION.TOP
617
+ } else if (mousePos.y > rect.bottom - yAbs) {
618
+ type = POSITION.BOTTOM
619
+ } else if (mousePos.x < rect.left + xAbs) {
620
+ type = POSITION.LEFT
621
+ } else if (mousePos.x > rect.right - xAbs) {
622
+ type = POSITION.RIGHT
623
+ } else if (configure.isContainer) {
624
+ type = allowInsert() ? POSITION.IN : POSITION.FORBID
625
+ } else {
626
+ type = POSITION.BOTTOM
627
+ }
628
+
629
+ return { type }
630
+ }
631
+
632
+ export const setPageCss = (css = '') => {
633
+ const id = 'page-css'
634
+ const document = getDocument()
635
+ let element = document.getElementById(id)
636
+ const head = document.querySelector('head')
637
+
638
+ document.body.setAttribute('style', '')
639
+
640
+ if (!element) {
641
+ element = document.createElement('style')
642
+ element.setAttribute('type', 'text/css')
643
+ element.setAttribute('id', id)
644
+
645
+ element.innerHTML = css
646
+ head.appendChild(element)
647
+ } else {
648
+ element.innerHTML = css
649
+ }
650
+ }
651
+
652
+ export const addStyle = (href) => appendStyle(href, getDocument())
653
+
654
+ export const addScript = (src) => appendScript(src, getDocument())
655
+
656
+ /**
657
+ *
658
+ * @param {*} messages
659
+ * @param {*} merge 是否合并,默认是重置所有数据
660
+ */
661
+ export const setLocales = (messages, merge) => {
662
+ const i18n = getRenderer().getI18n()
663
+
664
+ Object.keys(messages).forEach((lang) => {
665
+ const fn = merge ? 'mergeLocaleMessage' : 'setLocaleMessage'
666
+ i18n.global[fn](lang, messages[lang])
667
+ })
668
+ }
669
+
670
+ export const setState = (state) => {
671
+ getRenderer().setState(state)
672
+ }
673
+
674
+ export const setUtils = (utils) => {
675
+ getRenderer().setUtils(utils)
676
+ }
677
+
678
+ export const deleteState = (variable) => {
679
+ getRenderer().deleteState(variable)
680
+ }
681
+
682
+ export const setGlobalState = (state) => {
683
+ useResource().resState.globalState = state
684
+ getRenderer().setGlobalState(state)
685
+ }
686
+
687
+ export const getGlobalState = () => getRenderer().getGlobalState()
688
+
689
+ export const getRenderer = () => canvasState.renderer
690
+
691
+ export const getController = () => canvasState.controller
692
+
693
+ export const getNode = (id, parent) => getRenderer()?.getNode(id, parent)
694
+
695
+ export const getDocument = () => canvasState.iframe.contentDocument
696
+
697
+ export const getWindow = () => canvasState.iframe.contentWindow
698
+
699
+ export const getCurrent = () => {
700
+ return {
701
+ schema: canvasState.current,
702
+ parent: canvasState.parent,
703
+ loopId: canvasState.loopId
704
+ }
705
+ }
706
+
707
+ export const getNodePath = (id, nodes = []) => {
708
+ const { parent, node } = getNode(id, true) || {}
709
+
710
+ node && nodes.unshift({ name: node.componentName, node: id })
711
+
712
+ if (parent) {
713
+ parent && getNodePath(parent.id, nodes)
714
+ } else {
715
+ nodes.unshift({ name: 'BODY', node: id })
716
+ }
717
+
718
+ return nodes
719
+ }
720
+
721
+ export const setSchema = async (schema) => {
722
+ clearHover()
723
+ clearSelect()
724
+ canvasState.schema = await getRenderer()?.setSchema(schema)
725
+
726
+ return canvasState.schema
727
+ }
728
+
729
+ export const getSchema = () => getRenderer()?.getSchema()
730
+
731
+ export const setConfigure = (configure) => {
732
+ getRenderer().setConfigure(configure)
733
+ }
734
+
735
+ export const setProps = (data) => getRenderer()?.setProps(data)
736
+
737
+ export const setI18n = (data) => {
738
+ const messages = data || useTranslate().getData()
739
+ const i18n = getRenderer().getI18n()
740
+ Object.keys(messages).forEach((lang) => {
741
+ i18n.global.mergeLocaleMessage(lang, messages[lang])
742
+ })
743
+ }
744
+
745
+ export const setCanvasType = (type) => {
746
+ canvasState.type = type || 'normal'
747
+ getDocument().body.className = type === 'absolute' ? 'canvas-grid-bg' : ''
748
+ }
749
+
750
+ export const getCanvasType = () => canvasState.type
751
+
752
+ /**
753
+ * 画布派发事件
754
+ * @param {string} name 事件名称
755
+ * @param {any} data 派发的数据
756
+ */
757
+ export const canvasDispatch = (name, data, doc = getDocument()) => {
758
+ if (!doc) return
759
+
760
+ doc.dispatchEvent(new CustomEvent(name, data))
761
+ }
762
+
763
+ export const initCanvas = ({ renderer, iframe, emit, controller }) => {
764
+ const currentSchema = getSchema()
765
+
766
+ // 在点击刷新按钮的情况下继续保留最新的schema.json
767
+ const schema = currentSchema ? currentSchema : useCanvas().getPageSchema()
768
+
769
+ canvasState.iframe = iframe
770
+ canvasState.emit = emit
771
+ // 存放画布外层传进来的插件api
772
+ canvasState.controller = controller
773
+ canvasState.renderer = renderer
774
+ renderer.setController(controller)
775
+ setLocales(useTranslate().getData(), true)
776
+ if (isVsCodeEnv) {
777
+ const parent = window.parent
778
+ const senterMessage = parent.postMessage
779
+ // 发消息给webview
780
+ senterMessage({ type: 'i18nReady', value: true }, '*')
781
+ }
782
+
783
+ setGlobalState(useResource().resState.globalState)
784
+ renderer.setDataSourceMap(useResource().resState.dataSource)
785
+ // 设置画布全局的utils工具类上下文环境
786
+ setUtils(useResource().resState.utils)
787
+ setSchema(schema)
788
+ setConfigure(useResource().getConfigureMap())
789
+ canvasDispatch('updateDependencies', { detail: useResource().resState.thirdPartyDeps })
790
+ canvasState.loading = false
791
+ }