-
Notifications
You must be signed in to change notification settings - Fork 0
Consumables
Consumables
are custom objects that hold a value, can be listened for changes, and can dispatch new values. They are used across Cardboard for different things. The State is just a Consumable
, for example. They can also be used to reactively manipulate tags, ie. updating text, setting styles, hiding elements. They can be "intersected", which means creating a new Consumable
that updates its value based on another Consumable
.
A Consumable
is a versatile object that holds a value and allows you to change the value and listen to value changes. This section will guide you on creating Consumables
and using them effectively.
To create a Consumable
, you can use the createConsumable
function:
import { createConsumable } from 'cardboard-js/dist/cardboard.js';
// Create a Consumable with an initial value (e.g., 42).
const count = createConsumable(42);
Or you can instantiate the class directly:
import { Consumable } from 'cardboard-js/dist/cardboard.js';
// Create a Consumable with an initial value (e.g., 42).
const count = new Consumable(42);
Or using the state
function for a shorter alternative:
import { state } from 'cardboard-js/dist/cardboard.js';
// Create a Consumable with an initial value (e.g., 42).
const count = state(42);
You can access the current value of a Consumable
using the value
property. This will give you the real value for any cases where you might need it:
const currentValue = count.value; // Gets the current value (42 in this case).
You can update the value of a Consumable
using the value
property. This will automatically trigger any registered listeners:
count.value = 55; // Sets the value to 55 and notifies listeners.
Or you can call the dispatch method:
count.dispatch(55); // Sets the value to 55 and notifies listeners.
Both approaches do the same thing.
You can add listeners to a Consumable
to perform actions when its value changes. Use the changed(callback)
method:
count.changed((newValue) => {
console.log(`Value changed to: ${newValue}`);
});
// Creating a Consumable
const temperature = createConsumable(25);
// Adding a listener to react to changes
temperature.changed((newTemperature) => {
if (newTemperature > 30) {
console.log("It's getting hot!");
} else {
console.log("The temperature is comfortable.");
}
});
// Changing the value
temperature.value = 35; // Triggers the listener, and "It's getting hot!" will be printed.
You can create a new Consumable
that depends on the value of another Consumable
using the intersect
method. The new Consumable
will automatically update when the original value changes:
import { intersect, createConsumable } from 'cardboard-js/dist/cardboard.js';
// Create a Consumable
const weight = createConsumable(70);
// Create an intersected Consumable based on 'weight'
const isOverweight = intersect(weight, (value) => value > 90);
// intersect the consumable directly
const isOverweight = weight.intersect((value) => value > 90);
// Adding a listener
isOverweight.changed((overweight) => {
if (overweight) {
console.log("You're overweight!");
} else {
console.log("You're in a healthy weight range.");
}
});
// Changing the original value
weight.value = 95; // Triggers the listener, and "You're overweight!" will be printed.
That's cool and all, you can create and use Consumables
for whatever you want.
But the main reason for having them is to be used for building apps with cardboard. For making apps reactive to be precise.
As you might or might not already now you can manipulate tags, manually and conditionally/reactively. It's in the conditionally and reactively part where Consumables
come into play.
Let me explain with a simple example:
const isDisabled = createConsumable(false);
input()
.disableIf(isDisabled)
.classIf(isDisabled, ['box-disabled']);
// In another part of the code:
isDisabled.value = true;
Whenever the isDisabled
consumable changes, the input element will react to that change, then disable or enable based on the new value of the consumable. The same goes for setting or removing classes.
Take a look at Conditionally Manipulating Tags for a more in-depth explanation.
Cardboard offers a set of functions provided to create new Consumables
that represent common conditions or comparisons. These functions are readily available for common use cases. Here are the intersectors we have for now:
Most built-in interceptors allow you to pass in a value or a Consumable.
const temperature = createConsumable(32);
const isTooHot = greaterThan(temperature, 30);
// Or
const hotTemp = createConsumable(30);
const isTooHot = greaterThan(temperature, hotTemp);
The greaterThan
function allows you to create a Consumable
that checks if the value is greater than a specified threshold. This is useful for scenarios like tracking temperature exceeding a certain limit:
const temperature = createConsumable(32);
const isTooHot = greaterThan(temperature, 30);
isTooHot.changed((hot) => {
if (hot) {
console.log("It's too hot outside!");
} else {
console.log("The weather is pleasant.");
}
});
The greaterThanOr
function creates a Consumable
that checks if the value is greater than or equal to a specified threshold. It's helpful for scenarios like determining if a score meets or exceeds a passing grade:
const examScore = createConsumable(78);
const isPassing = greaterThanOr(examScore, 70);
isPassing.changed((pass) => {
if (pass) {
console.log("Congratulations! You passed the exam.");
} else {
console.log("You need a higher score to pass.");
}
});
The lessThan
function creates a Consumable
that checks if the value is less than a specified threshold. It's handy for scenarios like age verification for age-restricted content:
const userAge = createConsumable(16);
const isAdult = lessThan(userAge, 18);
isAdult.changed((adult) => {
if (adult) {
console.log("You are an adult and can access this content.");
} else {
console.log("Sorry, this content is for adults only.");
}
});
The lessThanOr
function creates a Consumable
that checks if the value is less than or equal to a specified threshold. It's useful for scenarios like checking if a price falls within a budget:
const productPrice = createConsumable(25);
const isAffordable = lessThanOr(productPrice, 30);
isAffordable.changed((affordable) => {
if (affordable) {
console.log("This product fits within your budget.");
} else {
console.log("You might want to consider a more affordable option.");
}
});
The equalTo
function creates a Consumable
that checks if the value is equal to a specified value. It's beneficial for scenarios like verifying if an input matches a predefined value:
const userStatus = createConsumable("Active");
const isActive = equalTo(userStatus, "Active");
isActive.changed((active) => {
if (active) {
console.log("Your account is active.");
} else {
console.log("Your account is not active.");
}
});
The notEqualTo
function creates a Consumable
that checks if the value is not equal to a specified value. It's useful for scenarios like checking if a selected option is not the default one:
const selectedOption = createConsumable("Select an option");
const isCustomChoice = notEqualTo(selectedOption, "Select an option");
isCustomChoice.changed((custom) => {
if (custom) {
console.log("You've made a custom selection.");
} else {
console.log("You haven't selected a custom option yet.");
}
});
By using these built-in intersectors, you can easily create Consumables
that represent common conditions and comparisons in real-world scenarios, making it simple to react to changes in values and provide feedback or perform actions accordingly.
This Wiki is a work in progress, it's just me doing everything around here :P
If you read this and have some free time, and want to spend it helping me with the wiki or anything else, you're more than welcome!