{"record":{"id":"9f154a05da8efa82","repo":"HelloZeroNet/ZeroNet","slug":"provide-a-transitions-object-to-the-projectionopti","errorCode":null,"errorMessage":"Provide a transitions object to the projectionOptions to do animations","messagePattern":"Provide a transitions object to the projectionOptions to do animations","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/UiConfig/media/js/all.js","lineNumber":263,"sourceCode":"    };\n    var appendChildren = function (parentSelector, insertions, main) {\n        for (var i = 0; i < insertions.length; i++) {\n            var item = insertions[i];\n            if (Array.isArray(item)) {\n                appendChildren(parentSelector, item, main);\n            } else {\n                if (item !== null && item !== undefined) {\n                    if (!item.hasOwnProperty('vnodeSelector')) {\n                        item = toTextVNode(item);\n                    }\n                    main.push(item);\n                }\n            }\n        }\n    };\n    // Render helper functions\n    var missingTransition = function () {\n        throw new Error('Provide a transitions object to the projectionOptions to do animations');\n    };\n    var DEFAULT_PROJECTION_OPTIONS = {\n        namespace: undefined,\n        eventHandlerInterceptor: undefined,\n        styleApplyer: function (domNode, styleName, value) {\n            // Provides a hook to add vendor prefixes for browsers that still need it.\n            domNode.style[styleName] = value;\n        },\n        transitions: {\n            enter: missingTransition,\n            exit: missingTransition\n        }\n    };\n    var applyDefaultProjectionOptions = function (projectorOptions) {\n        return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions);\n    };\n    var checkStyleValue = function (styleValue) {\n        if (typeof styleValue !== 'string') {","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/HelloZeroNet/ZeroNet/blob/454c0b2e7e000fda7000cba49027541fbf327b96/plugins/UiConfig/media/js/all.js#L245-L281","documentation":"missingTransition is used as a placeholder for transition-related projectionOptions (transitions.enterAnimation, exitAnimation, etc.). When a render/update triggers an animation (entering or exiting DOM nodes) and no transitions object was supplied via projectionOptions, maquette calls this stub which throws. Animations in maquette are opt-in and require an explicit transitions strategy.","triggerScenarios":"Calling dom.append/dom.merge/dom.createDom (or projector.append) with vnodes that have enterAnimation/exitAnimation properties set, while the projectionOptions object has no `transitions` key, so the default missingTransition stub is invoked during DOM creation or removal.","commonSituations":"Developers copy vnodes using CSS-transition helper properties (enterAnimation/exitAnimation) from examples but forget to pass `transitions: createCSSTransitionsAnimationHelper()` (or any object) into projectionOptions; also happens when bundling only part of maquette (e.g. the all.js bundle) where the transitions helper was tree-shaken or the projector was created without projection options.","solutions":["Pass a transitions object: projectionOptions = { transitions: maquette.createCSSTransitionsAnimationHelper() } when calling dom.append/merge/createDom or projector.append.","If you don't need animations, remove the enterAnimation/exitAnimation properties from your vnodes so missingTransition is never invoked.","Use the same projectionOptions object everywhere in a projector so the transitions object is consistently applied.","If a projector was already created, you can modify DEFAULT_PROJECTION_OPTIONS.transions via maquette.setProjectionOptions (or extendProjectionOptions) before first render."],"exampleFix":"// before\nvar projection = dom.append(container, h('div', { enterAnimation: 'fadeIn' }, ['hi']));\n// after\nvar projectionOptions = { transitions: maquette.createCSSTransitionsAnimationHelper() };\nvar projection = dom.append(container, h('div', { enterAnimation: 'fadeIn' }, ['hi']), projectionOptions);","handlingStrategy":"validation","validationCode":"function assertTransitions(projectionOptions) {\n  if (projectionOptions && !projectionOptions.transitions) {\n    throw new Error('projectionOptions.transitions is required when using enter/exit animations');\n  }\n}\n// call before dom.append/merge/createDom","typeGuard":"function hasTransitions(opts) {\n  return typeof opts === 'object' && opts !== null && typeof opts.transitions === 'object' && opts.transitions !== null;\n}","tryCatchPattern":"try {\n  projection = dom.append(container, vnode, projectionOptions);\n} catch (e) {\n  if (e.message.indexOf('transitions object') !== -1) {\n    projection = dom.append(container, vnode, Object.assign({ transitions: createCSSTransitionsAnimationHelper() }, projectionOptions));\n  } else { throw e; }\n}","preventionTips":["Define one shared projectionOptions object with a transitions object and reuse it for every append/merge/createDom call.","Only add enterAnimation/exitAnimation properties to vnodes when transitions are configured.","Set global defaults early with maquette.setProjectionOptions({ transitions: ... }) during app bootstrap.","Lint or code-review any vnode containing animation properties to confirm the call site passes projectionOptions."],"tags":["maquette","animation","configuration","virtual-dom"],"backgroundTag":"missing-transition-options","analyzedSha":"454c0b2e7e000fda7000cba49027541fbf327b96","analyzedAt":"2026-09-02T19:46:57.278Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}