profectus-docs/assets/guide_advanced-concepts_mixins.md.DyEDOWRs.lean.js

12 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import{_ as s,c as e,a0 as a,o as t}from"./chunks/framework.P9qPzDnn.js";const D=JSON.parse('{"title":"Mixins and Wrappers","description":"","frontmatter":{},"headers":[],"relativePath":"guide/advanced-concepts/mixins.md","filePath":"guide/advanced-concepts/mixins.md","lastUpdated":1737056209000}'),n={name:"guide/advanced-concepts/mixins.md"};function l(r,i,h,p,k,o){return t(),e("div",null,i[0]||(i[0]=[a(`<h1 id="mixins-and-wrappers" tabindex="-1">Mixins and Wrappers <a class="header-anchor" href="#mixins-and-wrappers" aria-label="Permalink to &quot;Mixins and Wrappers&quot;"></a></h1><p>Mixins and wrappers are ways of adding functionality to your features in a modular way, allowing them to be shared with the community or reused between projects with ease. There&#39;s already a couple built into the engine, including one that every renderable feature uses, <code>vueFeatureMixin</code>.</p><h2 id="mixins" tabindex="-1">Mixins <a class="header-anchor" href="#mixins" aria-label="Permalink to &quot;Mixins&quot;"></a></h2><p>Mixins are for adding additional properties to the feature, and are used by the one writing the feature itself (rather than just instantiating it). For example, <code>vueFeatureMixin</code> takes a couple parameters - a string for identifying features, an options object that can contain settings like <code>visibility</code>, <code>style</code>, <code>classes</code>, etc. - and a render function - and adds various properties required for rendering the feature. The mixin gets implemented by having the feature&#39;s options object extending the mixin&#39;s options, the feature interface extending the mixin itself, and destructuring the mixin&#39;s return object in the constructor itself:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes material-theme-palenight material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#C792EA;--shiki-dark:#C792EA;">const</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> clickable </span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">=</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> {</span></span>
<span class="line"><span style="--shiki-light:#F07178;--shiki-dark:#F07178;"> type</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">:</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> ClickableType</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> ...</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">(props </span><span style="--shiki-light:#89DDFF;--shiki-light-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic;">as</span><span style="--shiki-light:#FFCB6B;--shiki-dark:#FFCB6B;"> Omit</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">&lt;typeof</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> props</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> keyof</span><span style="--shiki-light:#FFCB6B;--shiki-dark:#FFCB6B;"> VueFeature</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> |</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> keyof</span><span style="--shiki-light:#FFCB6B;--shiki-dark:#FFCB6B;"> ClickableOptions</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">&gt;</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">)</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> ...</span><span style="--shiki-light:#82AAFF;--shiki-dark:#82AAFF;">vueFeatureMixin</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">(</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">&quot;</span><span style="--shiki-light:#C3E88D;--shiki-dark:#C3E88D;">clickable</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">&quot;</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> options</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> ()</span><span style="--shiki-light:#C792EA;--shiki-dark:#C792EA;"> =&gt;</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> (</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> &lt;</span><span style="--shiki-light:#BABED8;--shiki-light-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic;">Clickable</span></span>
<span class="line"><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> canClick</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">={</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">clickable.canClick</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">}</span></span>
<span class="line"><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> onClick</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">={</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">clickable.onClick</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">}</span></span>
<span class="line"><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> display</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">={</span><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;">clickable.display</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">}</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> /&gt;</span></span>
<span class="line"><span style="--shiki-light:#BABED8;--shiki-dark:#BABED8;"> ))</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">,</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;"> ...</span></span>
<span class="line"><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">}</span><span style="--shiki-light:#89DDFF;--shiki-light-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic;"> satisfies</span><span style="--shiki-light:#FFCB6B;--shiki-dark:#FFCB6B;"> Clickable</span><span style="--shiki-light:#89DDFF;--shiki-dark:#89DDFF;">;</span></span></code></pre></div><p>You&#39;ll note the properties included by the mixin also get omitted from the props object, since they&#39;ll be overwritten. In the end, you&#39;ll know its setup correctly because the <code>satisfies</code> clause won&#39;t cause issues (assuming you&#39;ve correctly made <code>Clickable</code> extend <code>VueFeature</code> or whatever the name of the feature and mixin are).</p><p>Custom mixins should work similarly to the existing mixins and support everything mentioned above. The bonus amounts/completions mixins are good examples of what a simpler mixin would look like.</p><p>If there&#39;s a feature you&#39;d like to write that could work as either a mixin or wrapper, prefer mixins due to their better typing. If the person using the mixin or wrapper wasn&#39;t creating a new feature, they can easily extend the feature to use the mixin like I demonstrate <a href="https://forums.moddingtree.com/t/using-the-bonus-mixins-on-repeatables-and-challenges/1648" target="_blank" rel="noreferrer">here</a>.</p><h2 id="wrappers" tabindex="-1">Wrappers <a class="header-anchor" href="#wrappers" aria-label="Permalink to &quot;Wrappers&quot;"></a></h2><p>Wrappers have the advantage of not requiring extending the feature and being able to access pre-defined properties on the feature, but make types a bit more tricky to work with.</p><p>Wrappers take a constructed feature and modify or add properties on it. For example, <code>addTooltip</code> will take a vue feature and make it have a tooltip on hover. It and all wrappers should take the feature as the first param and the options func as the second.</p><p>Similar to a feature, the wrapper should make a lazy proxy with all its properties. But, you can&#39;t add this lazy object to the feature directly, because that would force its evaluation. Instead, you should use <a href="/api/util/proxies/functions/runAfterEvaluation">runAfterEvaluation</a> and inside its callback add the wrapper object to the feature and make sure the wrapper object gets evaluated by referencing a property within it. If it is a wrapper around a vue component, you can also add the wrapper element to the feature&#39;s <code>wrappers</code> array inside the callback.</p>`,12)]))}const F=s(n,[["render",l]]);export{D as __pageData,F as default};