@blokkli/editor 2.0.0-alpha.21 → 2.0.0-alpha.23
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/dist/module.json +1 -1
- package/dist/module.mjs +97 -169
- package/dist/runtime/blokkliPlugins/MenuButton/index.vue +3 -1
- package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +20 -14
- package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue.d.ts +8 -4
- package/dist/runtime/blokkliPlugins/Sidebar/index.vue +55 -25
- package/dist/runtime/blokkliPlugins/Sidebar/index.vue.d.ts +4 -3
- package/dist/runtime/blokkliPlugins/ToolbarButton/index.vue +4 -1
- package/dist/runtime/blokkliPlugins/ViewOption/index.vue +3 -1
- package/dist/runtime/blokkliPlugins/index.d.ts +1 -3
- package/dist/runtime/blokkliPlugins/index.js +0 -4
- package/dist/runtime/components/Blocks/FromLibrary/index.vue +0 -5
- package/dist/runtime/components/BlokkliEditable.vue +6 -1
- package/dist/runtime/components/BlokkliField.vue +1 -1
- package/dist/runtime/components/BlokkliProvider.vue +4 -4
- package/dist/runtime/components/Edit/Actions/ItemDropdown.vue +66 -0
- package/dist/runtime/components/Edit/Actions/ItemDropdown.vue.d.ts +6 -0
- package/dist/runtime/components/Edit/Actions/index.vue +7 -49
- package/dist/runtime/components/Edit/AnimationCanvas/index.vue +23 -68
- package/dist/runtime/components/Edit/BlockProxy/index.vue +2 -8
- package/dist/runtime/components/Edit/BlokkliErrorBoundary.vue +33 -49
- package/dist/runtime/components/Edit/BlokkliErrorBoundary.vue.d.ts +14 -1
- package/dist/runtime/components/Edit/BlokkliRootErrorBoundary.vue +93 -0
- package/dist/runtime/components/Edit/BlokkliRootErrorBoundary.vue.d.ts +12 -0
- package/dist/runtime/components/Edit/DraggableList.vue +5 -25
- package/dist/runtime/components/Edit/EditProvider.vue +24 -11
- package/dist/runtime/components/Edit/Features/{BlockAddList → AddList/Blocks}/index.vue +26 -62
- package/dist/runtime/components/Edit/Features/{Hover/Overlay → AddList/Blocks}/index.vue.d.ts +2 -2
- package/dist/runtime/components/Edit/Features/AddList/index.vue +29 -8
- package/dist/runtime/components/Edit/Features/Analyze/{Renderer.vue → Main.vue} +4 -8
- package/dist/runtime/components/Edit/Features/Analyze/{Overlay → Renderer}/fragment.glsl +10 -6
- package/dist/runtime/components/Edit/Features/Analyze/{Overlay → Renderer}/index.vue +43 -15
- package/dist/runtime/components/Edit/Features/Analyze/{Overlay → Renderer}/index.vue.d.ts +0 -2
- package/dist/runtime/components/Edit/Features/Analyze/{Overlay → Renderer}/vertex.glsl +11 -9
- package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue +15 -3
- package/dist/runtime/components/Edit/Features/Analyze/analyzers/helpers/collectTextElements.js +3 -0
- package/dist/runtime/components/Edit/Features/Analyze/index.vue +7 -3
- package/dist/runtime/components/Edit/Features/Anchors/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/Clipboard/List/index.vue +21 -10
- package/dist/runtime/components/Edit/Features/Clipboard/index.vue +18 -11
- package/dist/runtime/components/Edit/Features/Conversions/index.vue +16 -9
- package/dist/runtime/components/Edit/Features/Debug/DebugSection.vue +24 -0
- package/dist/runtime/components/Edit/Features/Debug/DebugSection.vue.d.ts +16 -0
- package/dist/runtime/components/Edit/Features/Debug/Main.vue +80 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Features.vue +34 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Icons.vue +15 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Icons.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Keyboard.vue +17 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Keyboard.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Logging.vue +66 -0
- package/dist/runtime/components/Edit/Features/{Selection/OverlayFallback/index.vue.d.ts → Debug/Section/Logging.vue.d.ts} +2 -1
- package/dist/runtime/components/Edit/Features/Debug/Section/Rendering.vue +96 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Rendering.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Selection.vue +25 -0
- package/dist/runtime/components/Edit/Features/Debug/Section/Selection.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Debug/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +20 -27
- package/dist/runtime/components/Edit/Features/DraggingOverlay/Renderer/fragment.glsl +80 -0
- package/dist/runtime/components/Edit/Features/DraggingOverlay/{DropTargets → Renderer}/index.vue +100 -87
- package/dist/runtime/components/Edit/Features/DraggingOverlay/{DropTargets → Renderer}/vertex.glsl +51 -8
- package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +3 -3
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +0 -6
- package/dist/runtime/components/Edit/Features/EditableField/index.vue +6 -2
- package/dist/runtime/components/Edit/Features/Fragments/Dialog/Item/index.vue +1 -5
- package/dist/runtime/components/Edit/Features/Hover/Renderer/fragment.glsl +141 -0
- package/dist/runtime/components/Edit/Features/Hover/{Overlay → Renderer}/index.vue +225 -38
- package/dist/runtime/components/Edit/Features/Hover/Renderer/index.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Hover/{Overlay → Renderer}/vertex.glsl +49 -11
- package/dist/runtime/components/Edit/Features/Hover/index.vue +9 -6
- package/dist/runtime/components/Edit/Features/Library/LibraryDialog/Item/index.vue +1 -5
- package/dist/runtime/components/Edit/Features/Library/index.vue +24 -12
- package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue +1 -1
- package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +26 -13
- package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue.d.ts +0 -1
- package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue +3 -47
- package/dist/runtime/components/Edit/Features/MultiSelect/{Overlay → Renderer}/fragment.glsl +13 -26
- package/dist/runtime/components/Edit/Features/MultiSelect/{Overlay → Renderer}/index.vue +130 -72
- package/dist/runtime/components/Edit/Features/MultiSelect/{Overlay → Renderer}/index.vue.d.ts +0 -1
- package/dist/runtime/components/Edit/Features/MultiSelect/{Overlay → Renderer}/vertex.glsl +27 -2
- package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +25 -12
- package/dist/runtime/components/Edit/Features/Ownership/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Content/index.vue +23 -6
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +2 -2
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/fragment.glsl +19 -17
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +242 -131
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/vertex.glsl +29 -12
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +12 -4
- package/dist/runtime/components/Edit/Features/Selection/{Overlay → Renderer}/fragment.glsl +23 -14
- package/dist/runtime/components/Edit/Features/Selection/{Overlay → Renderer}/index.vue +121 -28
- package/dist/runtime/components/Edit/Features/Selection/{Overlay → Renderer}/index.vue.d.ts +0 -2
- package/dist/runtime/components/Edit/Features/Selection/{Overlay → Renderer}/vertex.glsl +23 -14
- package/dist/runtime/components/Edit/Features/Selection/index.vue +46 -59
- package/dist/runtime/components/Edit/Features/Transform/Dialog/index.vue +5 -5
- package/dist/runtime/components/Edit/Features/Transform/index.vue +29 -22
- package/dist/runtime/components/Edit/Form/Checkboxes/index.vue +43 -0
- package/dist/runtime/components/Edit/Form/Checkboxes/index.vue.d.ts +20 -0
- package/dist/runtime/components/Edit/Messages/Item/index.vue.d.ts +1 -1
- package/dist/runtime/components/Edit/PreviewProvider.vue +1 -1
- package/dist/runtime/components/Edit/Sortli/index.vue +5 -8
- package/dist/runtime/components/Edit/Sortli/index.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Toolbar/index.vue +1 -4
- package/dist/runtime/components/Edit/ViewportBlockingRect/index.vue +9 -2
- package/dist/runtime/components/Edit/ViewportBlockingRect/index.vue.d.ts +4 -1
- package/dist/runtime/components/Edit/index.d.ts +6 -4
- package/dist/runtime/components/Edit/index.js +11 -7
- package/dist/runtime/css/output.css +1 -1
- package/dist/runtime/helpers/animationProvider.d.ts +58 -9
- package/dist/runtime/helpers/animationProvider.js +318 -75
- package/dist/runtime/helpers/composables/defineItemDropdownAction.d.ts +2 -0
- package/dist/runtime/helpers/composables/defineItemDropdownAction.js +10 -0
- package/dist/runtime/helpers/composables/defineRenderer.d.ts +5 -2
- package/dist/runtime/helpers/composables/defineRenderer.js +3 -2
- package/dist/runtime/helpers/composables/useGlobalBlokkliObject.d.ts +16 -0
- package/dist/runtime/helpers/composables/useGlobalBlokkliObject.js +36 -0
- package/dist/runtime/helpers/debugProvider.d.ts +13 -3
- package/dist/runtime/helpers/debugProvider.js +80 -12
- package/dist/runtime/helpers/domProvider.js +46 -32
- package/dist/runtime/helpers/dropTargets/index.js +1 -1
- package/dist/runtime/helpers/eventBus.d.ts +1 -1
- package/dist/runtime/helpers/index.d.ts +1 -6
- package/dist/runtime/helpers/index.js +0 -81
- package/dist/runtime/helpers/pluginProvider.d.ts +16 -0
- package/dist/runtime/helpers/pluginProvider.js +30 -1
- package/dist/runtime/helpers/providers/directive.d.ts +4 -1
- package/dist/runtime/helpers/providers/directive.js +9 -2
- package/dist/runtime/helpers/stateProvider.js +1 -0
- package/dist/runtime/helpers/uiProvider.d.ts +5 -1
- package/dist/runtime/helpers/uiProvider.js +41 -7
- package/dist/runtime/helpers/webgl/index.d.ts +2 -3
- package/dist/runtime/helpers/webgl/index.js +9 -14
- package/dist/runtime/icons/dock-left.svg +1 -0
- package/dist/runtime/icons/dock-right.svg +1 -0
- package/dist/runtime/icons/dock-window.svg +1 -0
- package/dist/runtime/plugins/blokkliDirectives.js +1 -1
- package/dist/runtime/types/index.d.ts +4 -21
- package/package.json +1 -1
- package/dist/runtime/blokkliPlugins/DroppableEdit/index.vue +0 -56
- package/dist/runtime/blokkliPlugins/DroppableEdit/index.vue.d.ts +0 -24
- package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue +0 -76
- package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue.d.ts +0 -31
- package/dist/runtime/components/Edit/Features/BlockAddList/docs.md +0 -15
- package/dist/runtime/components/Edit/Features/Debug/Renderer.vue +0 -240
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +0 -96
- package/dist/runtime/components/Edit/Features/Hover/Overlay/fragment.glsl +0 -139
- package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue +0 -42
- /package/dist/runtime/components/Edit/Features/Analyze/{Renderer.vue.d.ts → Main.vue.d.ts} +0 -0
- /package/dist/runtime/components/Edit/Features/Anchors/{Renderer.vue → Overlay/index.vue} +0 -0
- /package/dist/runtime/components/Edit/Features/{BlockAddList → Anchors/Overlay}/index.vue.d.ts +0 -0
- /package/dist/runtime/components/Edit/Features/Debug/{Renderer.vue.d.ts → Main.vue.d.ts} +0 -0
- /package/dist/runtime/components/Edit/Features/{Anchors/Renderer.vue.d.ts → Debug/Section/Features.vue.d.ts} +0 -0
- /package/dist/runtime/components/Edit/Features/DraggingOverlay/{DropTargets → Renderer}/index.vue.d.ts +0 -0
- /package/dist/runtime/components/Edit/Features/Ownership/{Renderer.vue → Banner/index.vue} +0 -0
- /package/dist/runtime/components/Edit/Features/Ownership/{Renderer.vue.d.ts → Banner/index.vue.d.ts} +0 -0
|
@@ -5,11 +5,13 @@ import type { StorageProvider } from './storageProvider.js';
|
|
|
5
5
|
import type { CursorKeyword } from './dom/index.js';
|
|
6
6
|
import type { CanvasDrawEvent, Coord } from '#blokkli/types';
|
|
7
7
|
import type { SelectionProvider } from './selectionProvider.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { RectangleBufferCollector } from './webgl/index.js';
|
|
9
|
+
import type { DebugProvider } from './debugProvider.js';
|
|
9
10
|
export type RenderContext = CanvasDrawEvent & {
|
|
10
|
-
|
|
11
|
+
changeOptionsTransition: number;
|
|
11
12
|
};
|
|
12
|
-
|
|
13
|
+
type PreferredRenderingMode = 'auto' | 'webgl' | '2d';
|
|
14
|
+
export type Renderer<T = RectangleBufferCollector<any>> = {
|
|
13
15
|
id: string;
|
|
14
16
|
zIndex: number;
|
|
15
17
|
enabled?: () => boolean;
|
|
@@ -19,29 +21,72 @@ export type Renderer = {
|
|
|
19
21
|
mouse: Coord;
|
|
20
22
|
mouseArtboard: Coord;
|
|
21
23
|
}) => boolean | undefined;
|
|
22
|
-
|
|
24
|
+
collector: () => T;
|
|
25
|
+
program?: () => {
|
|
26
|
+
shaders: [string, string];
|
|
27
|
+
};
|
|
28
|
+
render: (ctx: RenderContext, gl: WebGLRenderingContext, program: ProgramInfo) => void;
|
|
29
|
+
renderFallback?: (ctx: RenderContext, ctx2d: CanvasRenderingContext2D) => void;
|
|
23
30
|
};
|
|
24
31
|
export type AnimationProvider = {
|
|
25
32
|
/**
|
|
26
33
|
* Request an animation loop. Should be called when UI state changes.
|
|
27
34
|
*/
|
|
28
35
|
requestDraw: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Reset the animation state and force a remount of all renderer components.
|
|
38
|
+
*/
|
|
39
|
+
reset: () => void;
|
|
29
40
|
/**
|
|
30
41
|
* Get the WebGL rendering context.
|
|
42
|
+
* Returns undefined if context is lost or not available.
|
|
31
43
|
*/
|
|
32
44
|
gl: () => WebGLRenderingContext | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get the raw WebGL context even if it's lost.
|
|
47
|
+
* For debugging purposes only (e.g., context loss testing).
|
|
48
|
+
*/
|
|
49
|
+
getRawGL: () => WebGLRenderingContext | null;
|
|
33
50
|
setSharedUniforms: (gl: WebGLRenderingContext, programInfo: ProgramInfo) => void;
|
|
34
51
|
dpi: ComputedRef<number>;
|
|
35
52
|
webglSupported: ComputedRef<boolean | null>;
|
|
36
53
|
webglEnabled: WritableComputedRef<boolean>;
|
|
37
|
-
|
|
54
|
+
preferredRenderingMode: WritableComputedRef<PreferredRenderingMode>;
|
|
55
|
+
/**
|
|
56
|
+
* Reactive property that indicates if we're currently rendering with WebGL.
|
|
57
|
+
* True when WebGL context exists and is not lost.
|
|
58
|
+
*/
|
|
59
|
+
isRenderingWebGL: ComputedRef<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Reactive property that indicates if we have a WebGL context.
|
|
62
|
+
* True even if the context is lost (for debugging purposes).
|
|
63
|
+
*/
|
|
64
|
+
hasWebGLContext: ComputedRef<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Reactive key that increments when WebGL context is restored.
|
|
67
|
+
* Use this as a component key to force remounting renderer components on context loss/restore.
|
|
68
|
+
*/
|
|
69
|
+
renderKey: ComputedRef<number>;
|
|
70
|
+
/**
|
|
71
|
+
* Reactive key that changes when switching between WebGL and 2D rendering modes.
|
|
72
|
+
* Use this as the canvas element key to force creating a new canvas with the appropriate context.
|
|
73
|
+
*/
|
|
74
|
+
canvasKey: ComputedRef<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Set the canvas element to use for rendering.
|
|
77
|
+
* This initializes the appropriate context based on webglEnabled.
|
|
78
|
+
*/
|
|
79
|
+
setCanvasElement: (canvas: HTMLCanvasElement) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Remove the canvas element and clean up contexts.
|
|
82
|
+
*/
|
|
83
|
+
removeCanvasElement: () => void;
|
|
38
84
|
/**
|
|
39
85
|
* Register a WebGL program.
|
|
40
86
|
*
|
|
41
87
|
* The programs are cached by the given ID.
|
|
42
88
|
*/
|
|
43
89
|
registerProgram: (id: string, gl: WebGLRenderingContext, shaders: string[]) => ProgramInfo;
|
|
44
|
-
setMouseCoords: (x: number, y: number) => void;
|
|
45
90
|
cursor: ComputedRef<CursorKeyword>;
|
|
46
91
|
/**
|
|
47
92
|
* Handle a click event by calling onClick handlers on renderers.
|
|
@@ -50,12 +95,16 @@ export type AnimationProvider = {
|
|
|
50
95
|
handleClick: (x: number, y: number) => boolean;
|
|
51
96
|
/**
|
|
52
97
|
* Register a WebGL renderer with a specific zIndex.
|
|
53
|
-
* Returns an unregister function.
|
|
98
|
+
* Returns an object with the collector instance and an unregister function.
|
|
54
99
|
*/
|
|
55
|
-
registerRenderer: (id: string, config: Omit<Renderer
|
|
100
|
+
registerRenderer: <T = RectangleBufferCollector<any>>(id: string, config: Omit<Renderer<T>, 'id'>) => {
|
|
101
|
+
collector: T;
|
|
102
|
+
unregister: () => void;
|
|
103
|
+
};
|
|
56
104
|
/**
|
|
57
105
|
* Unregister a WebGL renderer.
|
|
58
106
|
*/
|
|
59
107
|
unregisterRenderer: (id: string) => void;
|
|
60
108
|
};
|
|
61
|
-
export default function (ui: UiProvider, storage: StorageProvider, selection: SelectionProvider,
|
|
109
|
+
export default function (ui: UiProvider, storage: StorageProvider, selection: SelectionProvider, debug: DebugProvider): AnimationProvider;
|
|
110
|
+
export {};
|
|
@@ -3,22 +3,143 @@ import useAnimationFrame from "./composables/useAnimationFrame.js";
|
|
|
3
3
|
import {
|
|
4
4
|
ref,
|
|
5
5
|
computed,
|
|
6
|
+
watch,
|
|
6
7
|
onMounted,
|
|
7
8
|
onBeforeUnmount
|
|
8
9
|
} from "#imports";
|
|
9
10
|
import { eventBus } from "#blokkli/helpers/eventBus";
|
|
10
11
|
import { createProgramInfo } from "twgl.js";
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
import { useTransitionedValue } from "./useTransitionedValue.js";
|
|
13
|
+
function configureWebGLContext(gl) {
|
|
14
|
+
gl.enable(gl.BLEND);
|
|
15
|
+
gl.disable(gl.DEPTH_TEST);
|
|
16
|
+
gl.clearColor(0, 0, 0, 0);
|
|
17
|
+
gl.blendFunc(gl.SRC_ALPHA_SATURATE, gl.ONE);
|
|
18
|
+
gl.blendEquation(gl.FUNC_ADD);
|
|
19
|
+
}
|
|
20
|
+
export default function(ui, storage, selection, debug) {
|
|
21
|
+
const logger = debug.createLogger("Animation");
|
|
22
|
+
const preferredRenderingMode = storage.use(
|
|
23
|
+
"preferredRenderingMode",
|
|
24
|
+
"auto"
|
|
25
|
+
);
|
|
26
|
+
const webglSupported = ref(null);
|
|
27
|
+
const webglEnabled = computed({
|
|
28
|
+
get: () => {
|
|
29
|
+
if (preferredRenderingMode.value === "2d") {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (preferredRenderingMode.value === "webgl") {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return webglSupported.value !== false;
|
|
36
|
+
},
|
|
37
|
+
set: (value) => {
|
|
38
|
+
preferredRenderingMode.value = value ? "webgl" : "2d";
|
|
39
|
+
}
|
|
40
|
+
});
|
|
13
41
|
const currentCursor = ref("default");
|
|
14
42
|
const cursor = computed(() => currentCursor.value);
|
|
43
|
+
const renderKey = ref(0);
|
|
44
|
+
const canvasKey = computed(() => webglEnabled.value ? "webgl" : "2d");
|
|
45
|
+
const isRenderingWebGL = computed(
|
|
46
|
+
() => hasGLContext.value && !isContextLost.value
|
|
47
|
+
);
|
|
15
48
|
const renderers = /* @__PURE__ */ new Map();
|
|
49
|
+
const rendererPrograms = /* @__PURE__ */ new Map();
|
|
50
|
+
const rendererCollectors = /* @__PURE__ */ new Map();
|
|
51
|
+
const rendererFailures = /* @__PURE__ */ new Map();
|
|
52
|
+
const rendererCooldowns = /* @__PURE__ */ new Map();
|
|
53
|
+
const renderersPermanentlyDisabled = /* @__PURE__ */ new Set();
|
|
54
|
+
function shouldSkipRenderer(id) {
|
|
55
|
+
if (renderersPermanentlyDisabled.has(id)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
const cooldownEnd = rendererCooldowns.get(id);
|
|
59
|
+
if (cooldownEnd) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
if (now < cooldownEnd) {
|
|
62
|
+
return true;
|
|
63
|
+
} else {
|
|
64
|
+
rendererCooldowns.delete(id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
function handleRendererFailure(id) {
|
|
70
|
+
const failures = (rendererFailures.get(id) || 0) + 1;
|
|
71
|
+
rendererFailures.set(id, failures);
|
|
72
|
+
if (failures === 6) {
|
|
73
|
+
renderersPermanentlyDisabled.add(id);
|
|
74
|
+
rendererFailures.delete(id);
|
|
75
|
+
rendererCooldowns.delete(id);
|
|
76
|
+
logger.error(
|
|
77
|
+
`Renderer "${id}" has been permanently disabled due to repeated failures.`
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (failures === 5) {
|
|
82
|
+
const cooldownEnd = Date.now() + 5e3;
|
|
83
|
+
rendererCooldowns.set(id, cooldownEnd);
|
|
84
|
+
logger.error(
|
|
85
|
+
`Renderer "${id}" failed 5 times in a row. Skipping for 5 seconds.`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function handleRendererSuccess(id) {
|
|
90
|
+
rendererFailures.delete(id);
|
|
91
|
+
}
|
|
92
|
+
function executeRenderer(renderer, ctx, ctx2dContext2) {
|
|
93
|
+
if (!renderer.enabled || renderer.enabled()) {
|
|
94
|
+
const glContext2 = gl();
|
|
95
|
+
if (glContext2 && webglEnabled.value && !shouldSkipRenderer(renderer.id)) {
|
|
96
|
+
const program = rendererPrograms.get(renderer.id);
|
|
97
|
+
if (program) {
|
|
98
|
+
try {
|
|
99
|
+
renderer.render(ctx, glContext2, program);
|
|
100
|
+
handleRendererSuccess(renderer.id);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
handleRendererFailure(renderer.id);
|
|
103
|
+
logger.error(`Renderer "${renderer.id}" failed:`, error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else if (ctx2dContext2 && renderer.renderFallback) {
|
|
107
|
+
try {
|
|
108
|
+
renderer.renderFallback(ctx, ctx2dContext2);
|
|
109
|
+
handleRendererSuccess(renderer.id);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
handleRendererFailure(renderer.id);
|
|
112
|
+
logger.error(`Renderer "${renderer.id}" (2D fallback) failed:`, error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
16
117
|
function registerRenderer(id, config) {
|
|
17
|
-
|
|
18
|
-
|
|
118
|
+
logger.log("Registered Renderer: " + id);
|
|
119
|
+
const renderer = { id, ...config };
|
|
120
|
+
renderers.set(id, renderer);
|
|
121
|
+
const collector = config.collector();
|
|
122
|
+
rendererCollectors.set(id, collector);
|
|
123
|
+
if (renderer.program) {
|
|
124
|
+
const glContext2 = gl();
|
|
125
|
+
if (glContext2) {
|
|
126
|
+
const { shaders } = renderer.program();
|
|
127
|
+
const programInfo = registerProgram(id, glContext2, shaders);
|
|
128
|
+
rendererPrograms.set(id, programInfo);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
collector,
|
|
133
|
+
unregister: () => unregisterRenderer(id)
|
|
134
|
+
};
|
|
19
135
|
}
|
|
20
136
|
function unregisterRenderer(id) {
|
|
21
137
|
renderers.delete(id);
|
|
138
|
+
rendererPrograms.delete(id);
|
|
139
|
+
rendererCollectors.delete(id);
|
|
140
|
+
rendererFailures.delete(id);
|
|
141
|
+
rendererCooldowns.delete(id);
|
|
142
|
+
renderersPermanentlyDisabled.delete(id);
|
|
22
143
|
}
|
|
23
144
|
function handleClick(x, y) {
|
|
24
145
|
const sortedRenderers = Array.from(renderers.values()).filter((renderer) => !renderer.enabled || renderer.enabled()).sort((a, b) => b.zIndex - a.zIndex);
|
|
@@ -44,54 +165,170 @@ export default function(ui, storage, selection, element) {
|
|
|
44
165
|
let mouseX = 0;
|
|
45
166
|
let mouseY = 0;
|
|
46
167
|
let iterator = 120;
|
|
47
|
-
const webglSupported = ref(null);
|
|
48
168
|
const maxCanvasWidth = ref(16384);
|
|
49
169
|
const maxCanvasHeight = ref(16384);
|
|
50
170
|
let webglLimitsQueried = false;
|
|
51
171
|
let canvasElement = null;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
172
|
+
let glContext = null;
|
|
173
|
+
let ctx2dContext = null;
|
|
174
|
+
const isContextLost = ref(false);
|
|
175
|
+
const hasGLContext = ref(false);
|
|
176
|
+
let lastCanvasWidth = 0;
|
|
177
|
+
let lastCanvasHeight = 0;
|
|
178
|
+
function initializeContexts() {
|
|
179
|
+
if (!canvasElement) {
|
|
180
|
+
glContext = null;
|
|
181
|
+
ctx2dContext = null;
|
|
182
|
+
isContextLost.value = false;
|
|
183
|
+
hasGLContext.value = false;
|
|
184
|
+
return;
|
|
55
185
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
186
|
+
canvasElement.removeEventListener("webglcontextlost", handleContextLost);
|
|
187
|
+
canvasElement.removeEventListener(
|
|
188
|
+
"webglcontextrestored",
|
|
189
|
+
handleContextRestored
|
|
60
190
|
);
|
|
61
|
-
if (
|
|
62
|
-
|
|
191
|
+
if (webglEnabled.value && webglSupported.value !== false) {
|
|
192
|
+
const gl2 = canvasElement.getContext("webgl2", {
|
|
193
|
+
premultipliedAlpha: true
|
|
194
|
+
});
|
|
195
|
+
if (gl2) {
|
|
196
|
+
glContext = gl2;
|
|
197
|
+
ctx2dContext = null;
|
|
198
|
+
isContextLost.value = false;
|
|
199
|
+
hasGLContext.value = true;
|
|
200
|
+
webglSupported.value = true;
|
|
201
|
+
if (!webglLimitsQueried) {
|
|
202
|
+
const maxViewportDims = gl2.getParameter(
|
|
203
|
+
gl2.MAX_VIEWPORT_DIMS
|
|
204
|
+
);
|
|
205
|
+
maxCanvasWidth.value = maxViewportDims[0] || 16384;
|
|
206
|
+
maxCanvasHeight.value = maxViewportDims[1] || 16384;
|
|
207
|
+
webglLimitsQueried = true;
|
|
208
|
+
}
|
|
209
|
+
configureWebGLContext(gl2);
|
|
210
|
+
canvasElement.addEventListener(
|
|
211
|
+
"webglcontextlost",
|
|
212
|
+
handleContextLost,
|
|
213
|
+
false
|
|
214
|
+
);
|
|
215
|
+
canvasElement.addEventListener(
|
|
216
|
+
"webglcontextrestored",
|
|
217
|
+
handleContextRestored,
|
|
218
|
+
false
|
|
219
|
+
);
|
|
220
|
+
} else {
|
|
221
|
+
webglSupported.value = false;
|
|
222
|
+
glContext = null;
|
|
223
|
+
hasGLContext.value = false;
|
|
224
|
+
ctx2dContext = canvasElement.getContext("2d");
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
glContext = null;
|
|
228
|
+
hasGLContext.value = false;
|
|
229
|
+
ctx2dContext = canvasElement.getContext("2d");
|
|
63
230
|
}
|
|
64
|
-
canvasElement = el;
|
|
65
|
-
return el;
|
|
66
231
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
232
|
+
watch(webglEnabled, () => {
|
|
233
|
+
const programCount = registeredPrograms.size;
|
|
234
|
+
registeredPrograms.clear();
|
|
235
|
+
rendererPrograms.clear();
|
|
236
|
+
removeCanvasElement();
|
|
237
|
+
logger.log(
|
|
238
|
+
`Cleared ${programCount} WebGL programs and stopped rendering due to mode change to ${webglEnabled.value ? "WebGL" : "2D"}`
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
function handleContextLost(event) {
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
logger.error("WebGL context lost");
|
|
244
|
+
isContextLost.value = true;
|
|
245
|
+
const programCount = registeredPrograms.size;
|
|
246
|
+
registeredPrograms.clear();
|
|
247
|
+
rendererPrograms.clear();
|
|
248
|
+
logger.log(`Cleared ${programCount} invalidated WebGL programs`);
|
|
249
|
+
}
|
|
250
|
+
function handleContextRestored() {
|
|
251
|
+
logger.log("WebGL context restored");
|
|
252
|
+
isContextLost.value = false;
|
|
253
|
+
const restoredGL = glContext;
|
|
254
|
+
if (restoredGL) {
|
|
255
|
+
configureWebGLContext(restoredGL);
|
|
256
|
+
logger.log("Re-configured WebGL context settings");
|
|
70
257
|
}
|
|
71
|
-
|
|
72
|
-
|
|
258
|
+
renderKey.value++;
|
|
259
|
+
logger.log(
|
|
260
|
+
`Incremented renderKey to ${renderKey.value} to force renderer remount`
|
|
261
|
+
);
|
|
262
|
+
requestDraw();
|
|
263
|
+
}
|
|
264
|
+
function reset() {
|
|
265
|
+
isContextLost.value = true;
|
|
266
|
+
registeredPrograms.clear();
|
|
267
|
+
rendererPrograms.clear();
|
|
268
|
+
renderKey.value++;
|
|
269
|
+
isContextLost.value = false;
|
|
270
|
+
}
|
|
271
|
+
function setCanvasElement(canvas) {
|
|
272
|
+
canvasElement = canvas;
|
|
273
|
+
initializeContexts();
|
|
274
|
+
updateCanvasSize();
|
|
275
|
+
renderKey.value++;
|
|
276
|
+
logger.log(
|
|
277
|
+
`Canvas element set with ${webglEnabled.value ? "WebGL" : "2D"} context, renderKey = ${renderKey.value}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
function removeCanvasElement() {
|
|
281
|
+
if (canvasElement) {
|
|
282
|
+
canvasElement.removeEventListener("webglcontextlost", handleContextLost);
|
|
283
|
+
canvasElement.removeEventListener(
|
|
284
|
+
"webglcontextrestored",
|
|
285
|
+
handleContextRestored
|
|
286
|
+
);
|
|
73
287
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
288
|
+
canvasElement = null;
|
|
289
|
+
glContext = null;
|
|
290
|
+
ctx2dContext = null;
|
|
291
|
+
isContextLost.value = false;
|
|
292
|
+
hasGLContext.value = false;
|
|
293
|
+
lastCanvasWidth = 0;
|
|
294
|
+
lastCanvasHeight = 0;
|
|
295
|
+
}
|
|
296
|
+
function updateCanvasSize() {
|
|
297
|
+
if (!canvasElement) {
|
|
80
298
|
return;
|
|
81
299
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
300
|
+
const canvasWidth = ui.viewport.value.width * dpi.value;
|
|
301
|
+
const canvasHeight = ui.viewport.value.height * dpi.value;
|
|
302
|
+
if (canvasWidth !== lastCanvasWidth || canvasHeight !== lastCanvasHeight) {
|
|
303
|
+
canvasElement.width = canvasWidth;
|
|
304
|
+
canvasElement.height = canvasHeight;
|
|
305
|
+
if (glContext) {
|
|
306
|
+
glContext.viewport(0, 0, canvasWidth, canvasHeight);
|
|
307
|
+
}
|
|
308
|
+
lastCanvasWidth = canvasWidth;
|
|
309
|
+
lastCanvasHeight = canvasHeight;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function gl() {
|
|
313
|
+
if (isContextLost.value) {
|
|
314
|
+
return void 0;
|
|
90
315
|
}
|
|
316
|
+
return glContext || void 0;
|
|
317
|
+
}
|
|
318
|
+
function getRawGL() {
|
|
91
319
|
return glContext;
|
|
92
320
|
}
|
|
321
|
+
const getChangeOptionsTransition = useTransitionedValue(
|
|
322
|
+
() => {
|
|
323
|
+
return selection.isChangingOptions.value ? 0 : 1;
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
duration: 150
|
|
327
|
+
}
|
|
328
|
+
);
|
|
93
329
|
useAnimationFrame((time) => {
|
|
94
330
|
const selectedUuids = [...selection.uuids.value];
|
|
331
|
+
const changeOptionsTransition = getChangeOptionsTransition();
|
|
95
332
|
if (iterator < 1) {
|
|
96
333
|
return;
|
|
97
334
|
}
|
|
@@ -103,27 +340,22 @@ export default function(ui, storage, selection, element) {
|
|
|
103
340
|
fieldAreas: [],
|
|
104
341
|
time
|
|
105
342
|
});
|
|
106
|
-
|
|
343
|
+
updateCanvasSize();
|
|
344
|
+
if (!canvasElement) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
107
347
|
if (glContext) {
|
|
108
|
-
glContext.enable(glContext.BLEND);
|
|
109
|
-
glContext.blendFunc(glContext.SRC_ALPHA_SATURATE, glContext.ONE);
|
|
110
|
-
glContext.blendEquation(glContext.FUNC_ADD);
|
|
111
348
|
glContext.clearColor(0, 0, 0, 0);
|
|
112
349
|
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
350
|
+
} else if (ctx2dContext) {
|
|
351
|
+
ctx2dContext.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
|
113
352
|
}
|
|
114
|
-
const sortedRenderers = Array.from(renderers.values()).sort(
|
|
115
|
-
(
|
|
116
|
-
|
|
117
|
-
let onlyRenderer = null;
|
|
118
|
-
for (const renderer of sortedRenderers) {
|
|
119
|
-
if (!renderer.enabled || renderer.enabled()) {
|
|
120
|
-
const onlyValue = typeof renderer.only === "function" ? renderer.only() : renderer.only;
|
|
121
|
-
if (onlyValue) {
|
|
122
|
-
onlyRenderer = renderer;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
353
|
+
const sortedRenderers = Array.from(renderers.values()).sort((a, b) => {
|
|
354
|
+
if (glContext) {
|
|
355
|
+
return a.zIndex - b.zIndex;
|
|
125
356
|
}
|
|
126
|
-
|
|
357
|
+
return b.zIndex - a.zIndex;
|
|
358
|
+
});
|
|
127
359
|
const artboardOffset = ui.artboardOffset.value;
|
|
128
360
|
const artboardScale = ui.artboardScale.value;
|
|
129
361
|
const artboardSize = ui.artboardSize.value;
|
|
@@ -132,7 +364,6 @@ export default function(ui, storage, selection, element) {
|
|
|
132
364
|
y: (mouseY - artboardOffset.y) / artboardScale
|
|
133
365
|
};
|
|
134
366
|
const ctx = {
|
|
135
|
-
gl: glContext,
|
|
136
367
|
time,
|
|
137
368
|
mouseX,
|
|
138
369
|
mouseY,
|
|
@@ -140,22 +371,26 @@ export default function(ui, storage, selection, element) {
|
|
|
140
371
|
artboardOffset,
|
|
141
372
|
artboardScale,
|
|
142
373
|
artboardSize,
|
|
143
|
-
selectedUuids
|
|
374
|
+
selectedUuids,
|
|
375
|
+
dpi: dpi.value,
|
|
376
|
+
changeOptionsTransition
|
|
144
377
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (
|
|
148
|
-
|
|
378
|
+
let onlyRenderer = null;
|
|
379
|
+
for (const renderer of sortedRenderers) {
|
|
380
|
+
if (!renderer.enabled || renderer.enabled()) {
|
|
381
|
+
const onlyValue = typeof renderer.only === "function" ? renderer.only() : renderer.only;
|
|
382
|
+
if (onlyValue) {
|
|
383
|
+
onlyRenderer = renderer;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
149
386
|
}
|
|
387
|
+
}
|
|
388
|
+
if (onlyRenderer) {
|
|
389
|
+
executeRenderer(onlyRenderer, ctx, ctx2dContext);
|
|
150
390
|
} else {
|
|
151
391
|
for (let i = sortedRenderers.length - 1; i >= 0; i--) {
|
|
152
392
|
const renderer = sortedRenderers[i];
|
|
153
|
-
|
|
154
|
-
const glContext2 = gl();
|
|
155
|
-
if (glContext2) {
|
|
156
|
-
renderer.render(ctx);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
393
|
+
executeRenderer(renderer, ctx, ctx2dContext);
|
|
159
394
|
}
|
|
160
395
|
}
|
|
161
396
|
let newCursor = "default";
|
|
@@ -197,6 +432,12 @@ export default function(ui, storage, selection, element) {
|
|
|
197
432
|
const dpi = computed(() => {
|
|
198
433
|
const viewportWidth = ui.viewport.value.width;
|
|
199
434
|
const viewportHeight = ui.viewport.value.height;
|
|
435
|
+
if (!webglEnabled.value) {
|
|
436
|
+
const MAX_2D_CANVAS_SIZE = 4096;
|
|
437
|
+
const maxDpiByWidth2 = MAX_2D_CANVAS_SIZE / viewportWidth;
|
|
438
|
+
const maxDpiByHeight2 = MAX_2D_CANVAS_SIZE / viewportHeight;
|
|
439
|
+
return Math.min(maxDpiByWidth2, maxDpiByHeight2, 1);
|
|
440
|
+
}
|
|
200
441
|
const deviceRatio = window.devicePixelRatio;
|
|
201
442
|
const maxDpiByWidth = maxCanvasWidth.value / viewportWidth;
|
|
202
443
|
const maxDpiByHeight = maxCanvasHeight.value / viewportHeight;
|
|
@@ -234,31 +475,33 @@ export default function(ui, storage, selection, element) {
|
|
|
234
475
|
);
|
|
235
476
|
gl2.uniform1f(gl2.getUniformLocation(programInfo.program, "u_dpi"), dpi.value);
|
|
236
477
|
}
|
|
237
|
-
const registeredPrograms =
|
|
478
|
+
const registeredPrograms = /* @__PURE__ */ new Map();
|
|
238
479
|
function registerProgram(id, gl2, shaders) {
|
|
239
|
-
if (!registeredPrograms
|
|
240
|
-
registeredPrograms
|
|
480
|
+
if (!registeredPrograms.has(id)) {
|
|
481
|
+
registeredPrograms.set(id, createProgramInfo(gl2, shaders));
|
|
241
482
|
}
|
|
242
|
-
return registeredPrograms
|
|
243
|
-
}
|
|
244
|
-
function setMouseCoords(x, y) {
|
|
245
|
-
mouseX = x;
|
|
246
|
-
mouseY = y;
|
|
247
|
-
iterator = 120;
|
|
483
|
+
return registeredPrograms.get(id);
|
|
248
484
|
}
|
|
249
485
|
return {
|
|
250
486
|
requestDraw,
|
|
251
487
|
gl,
|
|
488
|
+
getRawGL,
|
|
252
489
|
setSharedUniforms,
|
|
253
490
|
dpi,
|
|
254
491
|
registerProgram,
|
|
255
|
-
setMouseCoords,
|
|
256
492
|
webglSupported: computed(() => webglSupported.value && webglEnabled.value),
|
|
257
493
|
webglEnabled,
|
|
258
|
-
|
|
494
|
+
preferredRenderingMode,
|
|
495
|
+
isRenderingWebGL,
|
|
496
|
+
hasWebGLContext: computed(() => hasGLContext.value),
|
|
497
|
+
renderKey: computed(() => renderKey.value),
|
|
498
|
+
canvasKey,
|
|
499
|
+
setCanvasElement,
|
|
500
|
+
removeCanvasElement,
|
|
259
501
|
cursor,
|
|
260
502
|
handleClick,
|
|
261
503
|
registerRenderer,
|
|
262
|
-
unregisterRenderer
|
|
504
|
+
unregisterRenderer,
|
|
505
|
+
reset
|
|
263
506
|
};
|
|
264
507
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, useBlokkli } from "#imports";
|
|
2
|
+
export default function(cb) {
|
|
3
|
+
const { plugins } = useBlokkli();
|
|
4
|
+
onMounted(() => {
|
|
5
|
+
plugins.addItemDropdownAction(cb);
|
|
6
|
+
});
|
|
7
|
+
onBeforeUnmount(() => {
|
|
8
|
+
plugins.removeItemDropdownAction(cb);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -3,6 +3,9 @@ import type { Renderer } from '../animationProvider.js';
|
|
|
3
3
|
* Register a WebGL renderer with automatic cleanup on unmount.
|
|
4
4
|
*
|
|
5
5
|
* @param id - Unique identifier for the renderer
|
|
6
|
-
* @param config - Renderer configuration (zIndex, enabled, render)
|
|
6
|
+
* @param config - Renderer configuration (zIndex, enabled, render, collector)
|
|
7
|
+
* @returns Object containing the collector instance with inferred type
|
|
7
8
|
*/
|
|
8
|
-
export default function defineRenderer(id: string, config: Omit<Renderer
|
|
9
|
+
export default function defineRenderer<T>(id: string, config: Omit<Renderer<T>, 'id'>): {
|
|
10
|
+
collector: T;
|
|
11
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { onBeforeUnmount, useBlokkli } from "#imports";
|
|
2
2
|
export default function defineRenderer(id, config) {
|
|
3
3
|
const { animation } = useBlokkli();
|
|
4
|
-
const
|
|
4
|
+
const { collector, unregister } = animation.registerRenderer(id, config);
|
|
5
5
|
onBeforeUnmount(() => {
|
|
6
|
-
|
|
6
|
+
unregister();
|
|
7
7
|
});
|
|
8
|
+
return { collector };
|
|
8
9
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LogMessage } from '../debugProvider.js';
|
|
2
|
+
type BlokkliGlobalWindowObject = {
|
|
3
|
+
messages: LogMessage[];
|
|
4
|
+
};
|
|
5
|
+
export declare function useGlobalBlokkliObject(): {
|
|
6
|
+
init: () => void;
|
|
7
|
+
pushMessage: (message: LogMessage) => void;
|
|
8
|
+
getMessages: () => LogMessage[];
|
|
9
|
+
cleanup: () => void;
|
|
10
|
+
};
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
__BLOKKLI__?: BlokkliGlobalWindowObject;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export {};
|