Mod Creation/Reusable Components with PetiteVue: Difference between revisions

Use SyntaxHighlight
(User:Coolrox95 Add mod guide navigation)
(Use SyntaxHighlight)
Line 21: Line 21:
'''Example'''
'''Example'''


  <nowiki><!-- templates.html -->
  <syntaxhighlight lang="html" line><!-- templates.html -->
<template id="counter-component">
<template id="counter-component">
   <span class="text-light">{{ count }}</span>
   <span class="text-light">{{ count }}</span>
   <button class="btn btn-secondary" @click="inc">+</button>
   <button class="btn btn-secondary" @click="inc">+</button>
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>// manifest.json
  <syntaxhighlight lang="js" line>// manifest.json
{
{
   "load": ["templates.html"]
   "load": ["templates.html"]
}</nowiki>
}</syntaxhighlight>


  <nowiki>// setup.mjs
  <syntaxhighlight lang="js" line>// setup.mjs
function Counter(props) {
function Counter(props) {
   return {
   return {
Line 48: Line 48:
     ui.create(Counter({ count: 0 }), document.getElementById('woodcutting-container'));
     ui.create(Counter({ count: 0 }), document.getElementById('woodcutting-container'));
   });
   });
}</nowiki>
}</syntaxhighlight>


=== ui.createStore(props: Record<string, unknown>): ComponentStore ===
=== ui.createStore(props: Record<string, unknown>): ComponentStore ===
Line 66: Line 66:
In the above example for <code>ui.create</code>, if you created a second <code>Counter</code> component, it would contain its own state and clicking the incrementing button on one would have no effect on the other. By using a store, you can share state in the following way:
In the above example for <code>ui.create</code>, if you created a second <code>Counter</code> component, it would contain its own state and clicking the incrementing button on one would have no effect on the other. By using a store, you can share state in the following way:


  <nowiki><!-- templates.html -->
  <syntaxhighlight lang="html" line><!-- templates.html -->
<template id="counter-component-using-store">
<template id="counter-component-using-store">
   <span class="text-light">{{ store.count }}</span>
   <span class="text-light">{{ store.count }}</span>
   <button class="btn btn-secondary" @click="store.inc">+</button>
   <button class="btn btn-secondary" @click="store.inc">+</button>
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>// manifest.json
  <syntaxhighlight lang="js" line>// manifest.json
{
{
   "load": ["templates.html"]
   "load": ["templates.html"]
}</nowiki>
}</syntaxhighlight>


  <nowiki>// setup.mjs
  <syntaxhighlight lang="js" line>// setup.mjs
function CounterUsingStore({ store }) {
function CounterUsingStore({ store }) {
   return {
   return {
Line 99: Line 99:
     ui.create(CounterUsingStore({ store }), document.getElementById('firemaking-container'));
     ui.create(CounterUsingStore({ store }), document.getElementById('firemaking-container'));
   });
   });
}</nowiki>
}</syntaxhighlight>


Now in this example, both the counter on the Woodcutting page and the Firemaking page should stay in sync with the current count.
Now in this example, both the counter on the Woodcutting page and the Firemaking page should stay in sync with the current count.
Line 109: Line 109:
'''Parameters'''
'''Parameters'''


<code>template: string</code> The selector string for the template you want to clone. For example, to target <code><template id="static-component"><!-- --></template></code>, you would use <code>'#static-component'</code>.
<code>template: string</code> The selector string for the template you want to clone. For example, to target <syntaxhighlight lang="html" inline><template id="static-component"><!-- --></template></syntaxhighlight>, you would use <syntaxhighlight lang="html" inline>'#static-component'</syntaxhighlight>.


<code>host: HTMLElement</code> The element that the component should be appended to.
<code>host: HTMLElement</code> The element that the component should be appended to.
Line 119: Line 119:
'''Example'''
'''Example'''


  <nowiki><!-- static-templates.html -->
  <syntaxhighlight lang="html" line><!-- static-templates.html -->
<template id="my-static-component">
<template id="my-static-component">
   <h3>Hello, this is static HTML</h3>
   <h3>Hello, this is static HTML</h3>
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>// manifest.json
  <syntaxhighlight lang="js" line>// manifest.json
{
{
   "load": ["static-templates.html"]
   "load": ["static-templates.html"]
}</nowiki>
}</syntaxhighlight>


  <nowiki>// setup.mjs
  <syntaxhighlight lang="js" line>// setup.mjs
export function setup({ onInterfaceReady }) {
export function setup({ onInterfaceReady }) {
   onInterfaceReady(() => {
   onInterfaceReady(() => {
Line 135: Line 135:
     ui.createStatic('#my-static-component', document.getElementById('woodcutting-container'));
     ui.createStatic('#my-static-component', document.getElementById('woodcutting-container'));
   });
   });
}</nowiki>
}</syntaxhighlight>


==== Nesting Static Components ====
==== Nesting Static Components ====
Line 143: Line 143:
For example, given the following templates:
For example, given the following templates:


  <nowiki><!-- static-templates.html -->
  <syntaxhighlight lang="html" line><!-- static-templates.html -->
<template id="static-parent">
<template id="static-parent">
   <h3>Hello, this is static HTML from the parent</h3>
   <h3>Hello, this is static HTML from the parent</h3>
Line 151: Line 151:
<template id="static-child">
<template id="static-child">
   <p>And this HTML is from a static child.</p>
   <p>And this HTML is from a static child.</p>
</template></nowiki>
</template></syntaxhighlight>


You could create the parent component using the following:
You could create the parent component using the following:


  <nowiki>// setup.mjs
  <syntaxhighlight lang="js" line>// setup.mjs
export function setup({ onInterfaceReady }) {
export function setup({ onInterfaceReady }) {
   onInterfaceReady(() => {
   onInterfaceReady(() => {
     ui.createStatic('#static-parent', document.getElementById('woodcutting-container'));
     ui.createStatic('#static-parent', document.getElementById('woodcutting-container'));
   });
   });
}</nowiki>
}</syntaxhighlight>


Which results in the following HTML being appended to the bottom of the Woodcutting page:
Which results in the following HTML being appended to the bottom of the Woodcutting page:


  <nowiki><h3>Hello, this is static HTML from the parent</h3>
  <syntaxhighlight lang="html" line><h3>Hello, this is static HTML from the parent</h3>
<div>
<div>
   <p>And this HTML is from a static child.</p>
   <p>And this HTML is from a static child.</p>
</div></nowiki>
</div></syntaxhighlight>


== Useful Patterns ==
== Useful Patterns ==
Line 177: Line 177:
Consider the following templates:
Consider the following templates:


  <nowiki><!-- templates.html -->
  <syntaxhighlight lang="html" line><!-- templates.html -->
<template id="block-component">
<template id="block-component">
   <div class="block">
   <div class="block">
Line 191: Line 191:
<template id="block-content">
<template id="block-content">
   <p v-for="line in lines">{{ line }}</p>
   <p v-for="line in lines">{{ line }}</p>
</template></nowiki>
</template></syntaxhighlight>


And defined components:
And defined components:


  <nowiki>
  <syntaxhighlight lang="js" line>
function Block(props) {
function Block(props) {
   return {
   return {
Line 218: Line 218:
     lines: props.lines
     lines: props.lines
   };
   };
}</nowiki>
}</syntaxhighlight>


A complete block component can be created with the following:
A complete block component can be created with the following:


  <nowiki>ui.create(Block({
  <syntaxhighlight lang="js" line>ui.create(Block({
   header: { title: 'My Block Component' },
   header: { title: 'My Block Component' },
   content: { lines: ['My first paragraph.', 'My second paragraph.'] }
   content: { lines: ['My first paragraph.', 'My second paragraph.'] }
}), document.getElementById('woodcutting-container'));</nowiki>
}), document.getElementById('woodcutting-container'));</syntaxhighlight>


=== Programmatically Manipulating Components ===
=== Programmatically Manipulating Components ===
Line 233: Line 233:
For example, using our <code>Counter</code> from above:
For example, using our <code>Counter</code> from above:


  <nowiki><!-- templates.html -->
  <syntaxhighlight lang="html" line><!-- templates.html -->
<template id="counter-component">
<template id="counter-component">
   <span class="text-light">{{ count }}</span>
   <span class="text-light">{{ count }}</span>
   <button class="btn btn-secondary" @click="inc">+</button>
   <button class="btn btn-secondary" @click="inc">+</button>
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>// setup.mjs
  <syntaxhighlight lang="js" line>// setup.mjs
function Counter(props) {
function Counter(props) {
   return {
   return {
Line 261: Line 261:
     counter.inc();
     counter.inc();
   });
   });
}</nowiki>
}</syntaxhighlight>


== PetiteVue Quick Reference ==
== PetiteVue Quick Reference ==
Line 273: Line 273:
'''Example'''
'''Example'''


  <nowiki><template id="binding-example"><h1>{{ text }}</h1></template></nowiki>
  <syntaxhighlight lang="html" line><template id="binding-example"><h1>{{ text }}</h1></template></syntaxhighlight>


  <nowiki>function BindingExample(props) {
  <syntaxhighlight lang="js" line>function BindingExample(props) {
   return {
   return {
     $template: '#binding-example',
     $template: '#binding-example',
     text: props.text
     text: props.text
   };
   };
}</nowiki>
}</syntaxhighlight>


  <nowiki>ui.create(BindingExample({ text: 'Hello, Melvor!' }), host);
  <syntaxhighlight lang="js" line>ui.create(BindingExample({ text: 'Hello, Melvor!' }), host);
// -> <h1>Hello, Melvor!</h1></nowiki>
// -> <h1>Hello, Melvor!</h1></syntaxhighlight>


=== Attribute Binding ===
=== Attribute Binding ===
Line 291: Line 291:
'''Example'''
'''Example'''


  <nowiki><template id="attr-binding-example">
  <syntaxhighlight lang="html" line><template id="attr-binding-example">
   <span v-bind:class="`text-${(warning ? 'warning' : 'info')}`">
   <span v-bind:class="`text-${(warning ? 'warning' : 'info')}`">
     This message could be a warning or informational.
     This message could be a warning or informational.
   </span>
   </span>
</template></nowiki>
</template></syntaxhighlight>


This notation accomplishes the same:
This notation accomplishes the same:


  <nowiki><template id="attr-binding-example">
  <syntaxhighlight lang="html" line><template id="attr-binding-example">
   <span :class="`text-${(warning ? 'warning' : 'info')}`">
   <span :class="`text-${(warning ? 'warning' : 'info')}`">
     This message could be a warning or informational.
     This message could be a warning or informational.
   </span>
   </span>
</template></nowiki>
</template></syntaxhighlight>


=== Event Binding/Handling ===
=== Event Binding/Handling ===
Line 311: Line 311:
'''Example'''
'''Example'''


  <nowiki><template id="event-binding-example">
  <syntaxhighlight lang="html" line><template id="event-binding-example">
   <button v-on:click="onClick">Click Me!</button>
   <button v-on:click="onClick">Click Me!</button>
</template></nowiki>
</template></syntaxhighlight>


This notation accomplishes the same:
This notation accomplishes the same:


  <nowiki><template id="event-binding-example">
  <syntaxhighlight lang="html" line><template id="event-binding-example">
   <button @click="onClick">Click Me!</button>
   <button @click="onClick">Click Me!</button>
</template></nowiki>
</template></syntaxhighlight>


And would be used in the component like:
And would be used in the component like:


  <nowiki>function EventBindingExample() {
  <syntaxhighlight lang="js" line>function EventBindingExample() {
   return {
   return {
     $template: '#event-binding-template',
     $template: '#event-binding-template',
Line 330: Line 330:
     }
     }
   };
   };
}</nowiki>
}</syntaxhighlight>


=== Input Value Binding ===
=== Input Value Binding ===
Line 338: Line 338:
'''Example'''
'''Example'''


  <nowiki><template id="input-binding-example">
  <syntaxhighlight lang="html" line><template id="input-binding-example">
   <input v-model="value" />
   <input v-model="value" />
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>function InputBindingExample(props) {
  <syntaxhighlight lang="js" line>function InputBindingExample(props) {
   return {
   return {
     value: props.initialValue,
     value: props.initialValue,
Line 358: Line 358:


// Assume the player changes the input in the UI to "new value"
// Assume the player changes the input in the UI to "new value"
console.log(input.value); // -> "new value"</nowiki>
console.log(input.value); // -> "new value"</syntaxhighlight>


=== Conditional Rendering ===
=== Conditional Rendering ===
Line 366: Line 366:
'''Example'''
'''Example'''


  <nowiki><template id="conditional-example">
  <syntaxhighlight lang="html" line><template id="conditional-example">
   <span v-if="value % 15 === 0">FizzBuzz</span>
   <span v-if="value % 15 === 0">FizzBuzz</span>
   <span v-else-if="value % 3 === 0">Fizz</span>
   <span v-else-if="value % 3 === 0">Fizz</span>
   <span v-else-if="value % 5 === 0">Buzz</span>
   <span v-else-if="value % 5 === 0">Buzz</span>
   <span v-else>{{ value }}</span>
   <span v-else>{{ value }}</span>
</template></nowiki>
</template></syntaxhighlight>


  <nowiki>function ConditionalExample(props) {
  <syntaxhighlight lang="js" line>function ConditionalExample(props) {
   return {
   return {
     $template: 'conditional-example',
     $template: 'conditional-example',
Line 381: Line 381:


ui.create(ConditionalExample({ value: 6 }), host);
ui.create(ConditionalExample({ value: 6 }), host);
// -> <span>Fizz</span></nowiki>
// -> <span>Fizz</span></syntaxhighlight>
{{ModGuideNav}}
{{ModGuideNav}}
{{Menu}}