Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[馃悶] Getting props/restProps inside component$() and turning them into signal doesn't seem to work like expected. #6113

Open
akashlama1998-icloud opened this issue Apr 11, 2024 · 1 comment
Labels
STATUS-1: needs triage New issue which needs to be triaged TYPE: bug Something isn't working

Comments

@akashlama1998-icloud
Copy link

Which component is affected?

Qwik Optimizer (rust)

Describe the bug

Describe

Below is the code snippet I wrote for changing aria-busy on an interval and inside the <Button></Button> reading that aria-busy turning it to a Signal to add transitions using useTransition hook.

import { component$, useSignal, useVisibleTask$, Slot, type PropsOf, type Signal } from '@builder.io/qwik';

export default component$(() => {
  const ariaBusy = useSignal<boolean>();

  useVisibleTask$(({ cleanup, track }) => {
    track(() => ariaBusy.value);

    const interval = setInterval(() => {
      ariaBusy.value = ariaBusy.value === undefined ? true : undefined;
    }, 3000);

    cleanup(() => clearInterval(interval));
  });

  return (
    <Button aria-busy={ariaBusy.value} disabled={ariaBusy.value}>
      Test
    </Button>
  );
});

export const Button = component$(({ class: className, ...restProps }: PropsOf<"button">) => {
  const ariaBusy = useSignal(!!restProps["aria-busy"]);
  const { stage, shouldMount } = useTransition(ariaBusy, { duration: 5 });

  useVisibleTask$(({ track }) => {
    track(() => restProps["aria-busy"]);

    ariaBusy.value = !!restProps["aria-busy"];
  });

  return (
    <button class={className} {...restProps}>
      {shouldMount.value ? (
        <i class={`${stage}`}>Spinner</i>
      ) : (
        <span class={`${stage}`}>
          <Slot />
        </span>
      )}
    </button>
  );
});

type Canceller = {
	id?: number;
};

type Stage = "enterFrom" | "enterTo" | "leaveFrom" | "leaveTo" | "idle";

export function useTransition(
	signal: Signal<boolean>,
	config: {
		appear?: boolean;
		duration: number;
	} = {
		appear: false,
		duration: 0.3,
	}
): { stage: Signal<Stage>; shouldMount: Signal<boolean> } {
	const stage = useSignal<Stage>(config.appear ? "enterFrom" : "idle");
	const timer = useSignal<Canceller>({});
	const shouldMount = useSignal(signal.value);

	useVisibleTask$(({ cleanup, track }) => {
		track(() => signal.value);
		clearAnimationFrameDuration(timer.value);

		if (signal.value) {
			if (config.appear) stage.value = "enterFrom";
			shouldMount.value = true;
			timer.value = setAnimationFrameDuration(() => (stage.value = "enterTo"));
		} else if (shouldMount.value) {
			stage.value = "leaveFrom";
			setAnimationFrameDuration(() => (stage.value = "leaveTo"));
			timer.value = setAnimationFrameDuration(() => (shouldMount.value = false), config.duration);
		}

		cleanup(() => clearAnimationFrameDuration(timer.value));
	});

	return { stage, shouldMount };
}

function setAnimationFrameDuration(callback: () => void, duration: number = 0) {
	const startTime = performance.now();
	const canceller: Canceller = {};

	function call() {
		canceller.id = requestAnimationFrame((now) => {
			if (now - startTime > duration * 1000) {
				callback();
			} else {
				call();
			}
		});
	}

	call();
	return canceller;
}

function clearAnimationFrameDuration(canceller: Canceller) {
	if (canceller.id) cancelAnimationFrame(canceller.id);
}

Expected

Expected turning aria-busy to a Signal and passing it to useTransition hook would just work.

What I got

Turns out making aria-busy into a Signal inside the component doesn't work due it being a Lexical Scoping I think and that's why the value isn't reactive. If that's the case then please teach me what should I do. If that's not the case then why is it not working as expected and how can I make it to work?

Reproduction

https://stackblitz.com/edit/vitejs-vite-khc7uk?file=src%2Fmain.tsx

Steps to reproduce

No response

System Info

System:
  OS: Linux 5.0 undefined
  CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Memory: 0 Bytes / 0 Bytes
  Shell: 1.0 - /bin/jsh
Binaries:
  Node: 18.18.0 - /usr/local/bin/node
  Yarn: 1.22.19 - /usr/local/bin/yarn
  npm: 10.2.3 - /usr/local/bin/npm
  pnpm: 8.15.3 - /usr/local/bin/pnpm
npmPackages:
  @builder.io/qwik: ^1.5.1 => 1.5.2 
  vite: ^5.2.8 => 5.2.8

Additional Information

No response

@akashlama1998-icloud akashlama1998-icloud added STATUS-1: needs triage New issue which needs to be triaged TYPE: bug Something isn't working labels Apr 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
STATUS-1: needs triage New issue which needs to be triaged TYPE: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants