Skip to content

Reusable Components

Manolo Edge edited this page Oct 28, 2023 · 3 revisions

It's very easy to create reusable components in Cardboard. They're plain functions, that return a Tag. We capitalize them to keep with common practices in other frameworks.

Counter component

const Counter = () => {
  let count = state(0);

  return button(
    text(`Clicked $count times`, { count })
  ).clicked((_) => count.value++);
};

They can be used as any other tag:

div(Counter());

Todo component

export default function TodoItem(
  content: IConsumable<TodoItem>,
  remove: (self: CTag, content: IConsumable<TodoItem>) => void
) {
  const isComplete = grab(content, 'complete', false);
  const todoItem = grab(content, 'item', 'Empty TODO');

  return div(
    input()
      .setAttrs({ type: 'checkbox' })
      .on('change', (self, evt) => {
        content.value.complete = self.checked;
      }),
    h4(todoItem)
      .stylesIf(isComplete, { textDecoration: 'line-through' }),
    button('-')
      .clicked((self) => {
        if (remove) remove(self, content);
      }), // self.parent will be div
  );
}

Lifecycle events

In some cases, you might want to do stuff when the element is added to the page, or when it's removed. For that, Cardboard offers the function `withLifecycle(tag, { start, removed, beforeRemove }).

const Clock = () => {
  const seconds = state('00');
  const minutes = state('00');
  const hours = state('00');

  const setTime = () => {
    const date = new Date();
    seconds.value = date.getSeconds();
    minutes.value = date.getMinutes();
    hours.value = date.getHours();
  };

  let interval: any;

  return withLifecycle(
    div(hours, ':', minutes, ':', seconds),
    {
      start() {
        // Add the interval when the element is added
        setTime();
        clearInterval(interval);
        interval = setInterval(setTime, 500);
      },
      beforeRemove() {
        // You can return a Promise<boolean>, that if false, it will cancel the remove operation
        // Or if it's true or not return anything, the element will be removed
      },
      removed() {
        // Clear the interval when the element is removed
        clear interval(interval);
      },
    },
  );
};

It's handy to have this control, as you don't want the interval to keep going if the element is not on the page.

start

It fires whenever the element is added to the page. This can be handy when you want to make an action when the element is added to the page. For example, running an animation, Tween, etc...

beforeRemove

It fires before the element is removed from the page. If you return a promise that's false, the element will not be removed. If the promise returns true, or you don't return anything, the element will be removed as normal.

This can be very useful when you want to perform an action before the element is removed. For example, if you want to animate an element being removed from the page. You can return a promise that resolves when the animation or Tween ends. This way, the animation ends and then the element is removed.

removed

It fires whenever the element is removed from the page. A good place to remove side effects that might stay running even if the element is removed. Like in the example above, where we need to stop the interval when the element is removed. Otherwise, it stays running infinitely.

Request/recommend more events

If you miss any event, please let me know by dropping an issue here with your suggestion.