Liquido
Liquido
SSolidJS
Created by Liquido on 7/6/2024 in #support
How to store JSX element in a signal and render it from other elements
I have created a dialog system using context where the dialog that I want to render is stored via a function provided by context and the provider is the one that renders the dialog:
import { render, Portal } from "solid-js/web";
import { createContext, useContext, createSignal, type JSX, type Accessor } from "solid-js";

export type DialogContextValue = {
openDialog(element: JSX.Element): void;

closeDialog(): void;
};

export const DialogContext = createContext<DialogContextValue>({
openDialog() {},
closeDialog() {},
});

type DialogProviderProps = {
children: JSX.Element
}

export function DialogProvider(props: DialogProviderProps) {
const [activeDialog, setActiveDialog] = createSignal<JSX.Element | undefined>(undefined)

const openDialog = (element: JSX.Element) => {
setActiveDialog(element)
}

const closeDialog = () => {
setActiveDialog(undefined);
}

return (
<DialogContext.Provider value={{ openDialog, closeDialog }}>
{props.children}
{activeDialog && <Portal>{activeDialog()}</Portal>}
</DialogContext.Provider>
);
}

function useDialog() { return useContext(DialogContext); }

function App() {
const dialog = useDialog();
return <button onClick={() => {
dialog.openDialog(<button onClick={dialog.closeDialog}>Dialog open. Click to close</button>);
}}>Open dialog</button>
}
import { render, Portal } from "solid-js/web";
import { createContext, useContext, createSignal, type JSX, type Accessor } from "solid-js";

export type DialogContextValue = {
openDialog(element: JSX.Element): void;

closeDialog(): void;
};

export const DialogContext = createContext<DialogContextValue>({
openDialog() {},
closeDialog() {},
});

type DialogProviderProps = {
children: JSX.Element
}

export function DialogProvider(props: DialogProviderProps) {
const [activeDialog, setActiveDialog] = createSignal<JSX.Element | undefined>(undefined)

const openDialog = (element: JSX.Element) => {
setActiveDialog(element)
}

const closeDialog = () => {
setActiveDialog(undefined);
}

return (
<DialogContext.Provider value={{ openDialog, closeDialog }}>
{props.children}
{activeDialog && <Portal>{activeDialog()}</Portal>}
</DialogContext.Provider>
);
}

function useDialog() { return useContext(DialogContext); }

function App() {
const dialog = useDialog();
return <button onClick={() => {
dialog.openDialog(<button onClick={dialog.closeDialog}>Dialog open. Click to close</button>);
}}>Open dialog</button>
}
Playground Link: https://playground.solidjs.com/anonymous/5d842f3f-3a3c-49b8-8287-9d46e0d29ca1 This works well but I have two problems. Firstly, I get a warning in the console when I trigger the modal:
dev.js:836 computations created outside a createRoot or render will never be disposed
And secondly, some components are not rendered when I open the modal. For example, I installed solid-icons package to render an icon. The icon is not rendered on first open but when I modify the code to trigger hot reload, the icon component is rendered inside it. The icons are rendered fine everywhere else.
6 replies
SSolidJS
Created by Liquido on 7/5/2024 in #support
How to make range input element reactive
const [step, setStep] = createSignal(0.01);

<div>
<label for="step">Step</label>
<input
id="step"
type="range"
min={0.01}
max={1.0}
value={step()}
onInput={(e) => {
console.log(e.currentTarget.value);
setStep(parseFloat(e.currentTarget.value));
}}
/>
{step()}
</div>
const [step, setStep] = createSignal(0.01);

<div>
<label for="step">Step</label>
<input
id="step"
type="range"
min={0.01}
max={1.0}
value={step()}
onInput={(e) => {
console.log(e.currentTarget.value);
setStep(parseFloat(e.currentTarget.value));
}}
/>
{step()}
</div>
How do I make this work?
3 replies
SSolidJS
Created by Liquido on 7/4/2024 in #support
How to pass props to context reactively?
I have a context that accepts props and then provides the prop values to its consumer components:
type FormGroupProps = { hasError?: boolean, name: string, children: JSXElement };

type FormGroupContextValue = { hasError: boolean, name: string };
const FormGroupContext = createContext<FormGroupContextValue>({
hasError: false, name: ''
});

export function FormGroup(props: FormGroupProps) {
return (
<FormGroupContext.Provider
value={{ hasError: Boolean(props.hasError), name: props.name }}
>
{props.children}
</FormGroupContext.Provider>
);
}

export function useFormGroup() {
return useContext(FormGroupContext);
}

export function TestComponent() {
const group = useFormGroup();
return (
<pre>
Has error: {group.hasError}
Name: {group.name}
</pre>
)
}

// Usage
const [errorA, setErrorA] = createSignal(false);

return <>
<FormGroup name="a" hasError={errorA()}>
<TestComponent />
</FormGroup>
<button onClick={() => setErrorA(err => !err)}>Toggle error</button>
</>
type FormGroupProps = { hasError?: boolean, name: string, children: JSXElement };

type FormGroupContextValue = { hasError: boolean, name: string };
const FormGroupContext = createContext<FormGroupContextValue>({
hasError: false, name: ''
});

export function FormGroup(props: FormGroupProps) {
return (
<FormGroupContext.Provider
value={{ hasError: Boolean(props.hasError), name: props.name }}
>
{props.children}
</FormGroupContext.Provider>
);
}

export function useFormGroup() {
return useContext(FormGroupContext);
}

export function TestComponent() {
const group = useFormGroup();
return (
<pre>
Has error: {group.hasError}
Name: {group.name}
</pre>
)
}

// Usage
const [errorA, setErrorA] = createSignal(false);

return <>
<FormGroup name="a" hasError={errorA()}>
<TestComponent />
</FormGroup>
<button onClick={() => setErrorA(err => !err)}>Toggle error</button>
</>
Playground link: https://playground.solidjs.com/anonymous/d7a38bbe-fa34-49c9-9d8f-7211839257ad How do I make the props passing to the context value reactive?
10 replies
SSolidJS
Created by Liquido on 6/27/2024 in #support
How to use useSubmission with server action passed to form?
I have a server action that returns data:
const createItemAction = action(async function (formData) {
"use server";
try {
validateInput(formData)
return { status: 'ok' };
} catch {
return { status: 'error' }
}
});

function CreateItem() {
const status = useSubmission(createItemAction);

console.log('status', status.result, status.pending, status.error);
return (
<form method="post" action={createItemAction}>
<input type="text" name="name" />
<button type="submit">Create</button>
</form>
)
}
const createItemAction = action(async function (formData) {
"use server";
try {
validateInput(formData)
return { status: 'ok' };
} catch {
return { status: 'error' }
}
});

function CreateItem() {
const status = useSubmission(createItemAction);

console.log('status', status.result, status.pending, status.error);
return (
<form method="post" action={createItemAction}>
<input type="text" name="name" />
<button type="submit">Create</button>
</form>
)
}
When I submit the form, I get no status data back. How am I supposed to use the useSubmission hook with server action and Form?
3 replies
SSolidJS
Created by Liquido on 6/22/2024 in #support
With Solid Auth template, I get "UnknownAction: cannot parse action at /api/auth/session"
I am using the Solid Start with Auth template and created a server action form form submission
import { getSession } from "@solid-mediakit/auth";
import { action } from "@solidjs/router";
import { getRequestEvent } from "solid-js/web";

const submitCreateAction = action(async function createAction(
formData: FormData
) {
"use server";

const event = getRequestEvent();
if (!event) throw new Error("No request event");

const session = await getSession(event.request, authOptions); // <-- This line causes the error
if (!session?.user?.id) throw new Error("Not logged in");

const userId = session.user.id;
const name = formData.get("name");

if (!name) throw new Error("Input is empty");

console.log("Name", name);
console.log("User ID", userId);
});


function CreatePage() {
return (
<form method="post" action={submitCreateAction}>
<label for="name">Name</label>
<input
type="text"
name="name"
id="name"
placeholder="Enter name"
/>
<button type="submit">Create</button>
</form>
);
}

export default requireAuth(CreatePage);
import { getSession } from "@solid-mediakit/auth";
import { action } from "@solidjs/router";
import { getRequestEvent } from "solid-js/web";

const submitCreateAction = action(async function createAction(
formData: FormData
) {
"use server";

const event = getRequestEvent();
if (!event) throw new Error("No request event");

const session = await getSession(event.request, authOptions); // <-- This line causes the error
if (!session?.user?.id) throw new Error("Not logged in");

const userId = session.user.id;
const name = formData.get("name");

if (!name) throw new Error("Input is empty");

console.log("Name", name);
console.log("User ID", userId);
});


function CreatePage() {
return (
<form method="post" action={submitCreateAction}>
<label for="name">Name</label>
<input
type="text"
name="name"
id="name"
placeholder="Enter name"
/>
<button type="submit">Create</button>
</form>
);
}

export default requireAuth(CreatePage);
This is the error keep getting on the server side:
[auth][error] UnknownAction: Cannot parse action at /api/auth/session. Read more at https://errors.authjs.dev#unknownaction
My goal is to get the userId from the session object. What am I doing wrong here?
10 replies
SSolidJS
Created by Liquido on 12/11/2023 in #support
How can I set a style based on reactive state with fallback to props?
I want to change color of a button when active and return back to default value when not active:
const Internal = (props) => {
const [clicked, setClicked] = createSignal(false);

const style = mergeProps(props.style, { color: clicked() ? 'orange' : 'red' });

return <button onClick={() => setClicked(c => !c)} style={style}>
{props.children}
</button>
}

function Counter() {
return (
<Internal style={{ color: 'blue', fontWeight: 'bold' }}>Click me</Internal>
);
}
const Internal = (props) => {
const [clicked, setClicked] = createSignal(false);

const style = mergeProps(props.style, { color: clicked() ? 'orange' : 'red' });

return <button onClick={() => setClicked(c => !c)} style={style}>
{props.children}
</button>
}

function Counter() {
return (
<Internal style={{ color: 'blue', fontWeight: 'bold' }}>Click me</Internal>
);
}
https://playground.solidjs.com/anonymous/c98af79a-5755-4edd-a7a4-f91d60c3ae02 How can I make the style value inside the Internal component reactive?
6 replies
SSolidJS
Created by Liquido on 12/1/2023 in #support
How to make SolidJS tags not return HTML elements for a custom renderer?
No description
12 replies
SSolidJS
Created by Liquido on 11/25/2023 in #support
How can I use SolidJS ref with typescript?
I want to create a ref to a canvas element:
export const Canvas = () => {
let ref: HTMLCanvasElement;

return <canvas ref={ref} width={500} height={500}></canvas>;
};
export const Canvas = () => {
let ref: HTMLCanvasElement;

return <canvas ref={ref} width={500} height={500}></canvas>;
};
But I keep getting TS error that "Variable ref is being used without being assigned." What's the correct way to use refs with Typescript?
2 replies