npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

r3f-form

v4.0.0

Published

An *accessible* webGL form component library for use with React Three Fiber

Downloads

45

Readme

r3f-form

View examples

WARNING: UNDER HEAVY DEVELOPMENT

Each release will aim to be a fully functional and usable release, but breaking API changes WILL be likely for the forseeable future.

A webGL form component for use with React Three Fiber

image

This package aims to create a fully-functional and accessible <Form /> components that can be used within the @react-three/fiber ecosystem. Ultimately, the goal is to have fully functioning HTML <form>s -- with all viable input types -- rendered in webGL.

Current implementation binds webGL elements to the existing state and event systems of respective hidden HTML DOM elements. There is a heavy reliance on troika-three-text for text-rendering and selection/caret logic.

Note that r3f-form will only work within a React-Three-Fiber Canvas element. You must be using

as dependencies in your project to use r3f-form.

Install

npm install r3f-form
# or
yarn add r3f-form
# or
pnpm install r3f-form

How to use

Forms

In order to create a form, just wrap any relevant elements in a <Form>:

import { Form, Input, Label, Submit } from "r3f-form";

export function MyForm() {
  return (
    <Form>
      <Label text="username" />
      <Input name="username" />

      <Label text="password" />
      <Input name="password" type="password" />

      <Submit value="Login" />
    </Form>
  );
}

Note that each element in the form will require a name prop in order to be picked up in submission, just like in a normal DOM form element

The relevant inputs will be bound to respective DOM elements under the hood, and be rendered into the 3D scene like so:

image

You can define submission behavior just like with any old HTML <form>:

// redirect to a login script
<Form action="/login.php"></Form>;

// or handle it with a callback
const handleSubmit = (e: FormEvent) => {
  e.preventDefault();

  const data = new FormData(e.target);

  for (let [name, value] of data.entries()) {
    console.log(`${name}: ${value}`);
  }
};

<Form onSubmit={handleSubmit}></Form>;

Inputs

An editable text-box bound to an DOM <input> and represented in the webGL canvas.

type Props = {
  type?: "text" | "password";

  /** width of the container */
  width?: number;
  backgroundColor?: Color;
  selectionColor?: Color;
  backgroundOpacity?: number;

  /** [left/right , top/bottom] in THREE units, respectively
   *
   * note that height is implicitly defined by the capHeight of the rendered
   * text. The cap height is dependant on both the `textProps.font` being used and the
   * `textProps.fontSize` value
   */
  padding?: Vector2;
  cursorWidth?: number;

  /** 3D transformations */
  position: Vector3;
  rotation: Euler;
  scale: Vector3;

  // And ALL props available to DOM <input>s
};

Create a basic input field like so:

import { Input, Label } from "r3f-form";

export function MyInput() {
  return (
    <>
      <Label text="label" />
      <Input />
    </>
  );
}

image

You can access the value of the input via the onChange callback prop:

The callback is passed the ChangeEvent object from the underlying HTML <input>s change event on every change.

Read more about this event here

import { Input, Label } from "r3f-form";

export function MyInput() {
  const [username, setUsername] = React.useState("");
  // username will always contain the current value

  function handleChange(e) {
    setUsername(ev.target.value);
  }

  return (
    <>
      <Label text="Test Input" />
      <Input onChange={handleChange} />
    </>
  );
}

You can also create password inputs:

import { Input, Label } from "r3f-form";

export function MyPassword() {
  return (
    <>
      <Label text="Password" />
      <Input type="password" />
    </>
  );
}

image

Add custom padding to the text container:

import { Input, Label } from "r3f-form";

/*
 * padding: [horizontal padding, vertical padding] in THREE units
 */

export function MyInput() {
  return (
    <>
      <Label text="Label" />
      <Input padding={[0.05, 0.5]} />
    </>
  );
}

image


Textarea

type Props = {
  /** width of the container */
  width?: number;

  backgroundColor?: Color;
  backgroundOpacity?: number;
  selectionColor?: Color;

  /** [left/right , top/bottom] in THREE units, respectively
   *
   * note that height is implicitly defined by the capHeight of the rendered
   * text. The cap height is dependant on both the `textProps.font` being used
   * and the `textProps.fontSize` value
   */
  padding?: Vector2;
  cursorWidth?: number;

  /** 3D transformations */
  position: Vector3;
  rotation: Euler;
  scale: Vector3;

  // And ALL props available to DOM <textarea>s
};

Similar to the <Input /> component, you can also create a <Textarea /> like so:

import { Textarea, Label } from "r3f-form";

export function App() {
  return (
    <>
      <Label text="Default Textarea:" />
      <Textarea />
    </>
  );
}

image


Text

In order to configure the underlying troika-three-text instance that is responsible for rendering the actual text, you can use the <Text /> component.

There is a respective <InputText /> or <TextareaText /> component for both <Input />s and <Textarea />s.

For all configuration options, check out the troika docs.

Note that not all of troika's props are exposed on these <Text /> components

Change color and background opacity:

import { Input, Label, InputText } from "r3f-form";

export function App() {
  return (
    <>
      <Label text="Test Color/Opacity" />
      <Input backgroundOpacity={0.6} backgroundColor="black">
        <InputText color="red" />
      </Input>
    </>
  );
}

image

import { Input, Textarea, Label, InputText, TextareaText } from "r3f-form";

export function App() {
  return (
    <>
      <Label text="Test Color/Opacity" />
      <Input>
        <InputText color="#red" />
      </Input>

      <Label text="Test Textarea" />
      <Textarea>
        <TextareaText color="red" />
      </Textarea>
    </>
  );
}

Submit

Equivalent to a DOM <input type="submit" />, exposed as an independent component. By default it renders a button using the following props:

type Props = {
  value?: string;
  fontSize?: number;
  width?: number;
  height?: number;
  color?: Color;
  backgroundColor?: Color;

  /** 3D transformations */
  position: Vector3;
  rotation: Euler;
  scale: Vector3;

  // And ALL props available to DOM <input>s
};

Add a simple submit button to your forms like so:

<Form>
  <Label text="Username" />
  <Input name="username" />

  <Label text="Password" />
  <Input name="password" type="password" />

  <Submit value="Login" />
</Form>

image

While this provides a somewhat-customizable default button, the main purpose of this component is to provide a simple interface to use 3D elements to submit your forms. Any children passed in will submit the form on click. For example:

<Form>
  . . .
  <Submit value="submit">
    <MySubmitButton />
  </Submit>
</Form>

image

Clicking on the big red button would submit the <Form>