mirror of
https://github.com/rive-app/rive-react.git
synced 2026-03-13 08:22:30 +08:00
223 lines
7.2 KiB
Plaintext
223 lines
7.2 KiB
Plaintext
<!-- RiveTestHook.stories.mdx -->
|
|
|
|
import { useState, useEffect } from 'react';
|
|
|
|
import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
|
|
|
|
import RiveComponent, {
|
|
EventType,
|
|
useRive,
|
|
useStateMachineInput,
|
|
} from '../../src';
|
|
import { Button } from './components/Button';
|
|
import './rive-overview.css';
|
|
|
|
<Meta title="React Runtime/State Machines" />
|
|
|
|
# State Machine Usage
|
|
|
|
Not familiar with Rive State Machines? Check out our [help docs](https://rive.app/community/doc/state-machine/docwH5zPdh93) on what these are first!
|
|
|
|
The `useStateMachineInput` hook is a helper that makes grabbing references to state machine inputs easier to setup. This hook should be used along with the `useRive` hook, as you need to pass in the `rive` instance returned from `useRive`. See each of the examples below to see usage of the hook creating instance of three types of inputs:
|
|
|
|
- Booleans
|
|
- Numbers
|
|
- Triggers
|
|
|
|
## Boolean inputs
|
|
|
|
Once you grab a reference to the state machine input, you can get/set the value of the input via the `.value` property.
|
|
|
|
**Note:** The input instance value itself is not a stateful React variable, therefore, any logic in the component dependent on an input value changing will not trigger a re-render like a React stateful variable change would. You can achieve this effect by keeping reference to the state machine input value inside a React state variable. See the example below for this pattern.
|
|
|
|
<Canvas withSource="open">
|
|
<Story name="Boolean input">
|
|
{() => {
|
|
const STATE_MACHINE_NAME = 'State Machine 1';
|
|
const ON_HOVER_INPUT_NAME = 'Hover';
|
|
const ON_PRESSED_INPUT_NAME = 'Pressed';
|
|
const { rive, RiveComponent: RiveComponentTouch } = useRive({
|
|
src: 'like.riv',
|
|
stateMachines: STATE_MACHINE_NAME,
|
|
artboard: 'New Artboard',
|
|
autoplay: true,
|
|
});
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
// Both onHoverInput and onPressedInput are boolean inputs. To transition
|
|
// states we need to set the value property to true or false.
|
|
const onPressedInput = useStateMachineInput(
|
|
rive,
|
|
STATE_MACHINE_NAME,
|
|
ON_PRESSED_INPUT_NAME
|
|
);
|
|
const onHoverInput = useStateMachineInput(
|
|
rive,
|
|
STATE_MACHINE_NAME,
|
|
ON_HOVER_INPUT_NAME
|
|
);
|
|
function onMouseDown() {
|
|
onPressedInput.value = true;
|
|
}
|
|
function onMouseUp() {
|
|
onPressedInput.value = false;
|
|
}
|
|
function onMouseEnter() {
|
|
onHoverInput.value = true;
|
|
setIsHovered(true);
|
|
}
|
|
function onMouseLeave() {
|
|
onHoverInput.value = false;
|
|
setIsHovered(false);
|
|
}
|
|
return (
|
|
<>
|
|
<div className="center">
|
|
<RiveComponentTouch
|
|
className="base-canvas-size"
|
|
onMouseEnter={onMouseEnter}
|
|
onMouseLeave={onMouseLeave}
|
|
onMouseDown={onMouseDown}
|
|
onMouseUp={onMouseUp}
|
|
/>
|
|
<p>Hover and click on the canvas</p>
|
|
<p>Is cursor hovering? {isHovered ? 'Yes' : 'No'}</p>
|
|
</div>
|
|
</>
|
|
);
|
|
}}
|
|
</Story>
|
|
</Canvas>
|
|
|
|
## Number inputs
|
|
|
|
Once you grab a reference to the state machine input, you can get/set the value of the input via the `.value` property.
|
|
|
|
<Canvas withSource="open">
|
|
<Story name="Number input">
|
|
{() => {
|
|
const STATE_MACHINE_NAME = 'skill-controller';
|
|
const INPUT_NAME = 'level';
|
|
const { rive, RiveComponent: RiveComponentTouch } = useRive({
|
|
src: 'skills.riv',
|
|
stateMachines: STATE_MACHINE_NAME,
|
|
artboard: 'New Artboard',
|
|
autoplay: true,
|
|
});
|
|
// levelInput is a number state machine input. To transition the state machine,
|
|
// we need to set the value to a number. For this state machine input, we need
|
|
// to set to 0, 1 or 2 for a state transition to occur.
|
|
const levelInput = useStateMachineInput(
|
|
rive,
|
|
STATE_MACHINE_NAME,
|
|
INPUT_NAME
|
|
);
|
|
return (
|
|
// The animation will fit to the parent element, so we set a large height
|
|
// and width for this example.
|
|
<div className="center">
|
|
<RiveComponentTouch className="large-canvas-size" />
|
|
<div className="btn-group">
|
|
Choose a level:
|
|
<Button onClick={() => (levelInput.value = 0)}>0</Button>
|
|
<Button onClick={() => (levelInput.value = 1)}>1</Button>
|
|
<Button onClick={() => (levelInput.value = 2)}>2</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}}
|
|
</Story>
|
|
</Canvas>
|
|
|
|
## Trigger inputs
|
|
|
|
Unlike the boolean and number inputs, you invoke the `.fire()` method on a trigger input.
|
|
|
|
<Canvas withSource="open">
|
|
<Story name="Trigger input">
|
|
{() => {
|
|
const STATE_MACHINE_NAME = 'State Machine 1';
|
|
const INPUT_NAME = 'Pressed';
|
|
const { rive, RiveComponent: RiveComponentTouch } = useRive({
|
|
src: 'piggy-bank.riv',
|
|
stateMachines: STATE_MACHINE_NAME,
|
|
artboard: 'New Artboard',
|
|
autoplay: true,
|
|
});
|
|
// pressedInput in a trigger state machine input. To transition the state
|
|
// we need to call the `fire()` method on the input.
|
|
const pressedInput = useStateMachineInput(
|
|
rive,
|
|
STATE_MACHINE_NAME,
|
|
INPUT_NAME
|
|
);
|
|
// The animation will fit to the parent element, so we set a large height
|
|
// and width for this example.
|
|
return (
|
|
<div className="center">
|
|
<RiveComponentTouch
|
|
className="base-canvas-size"
|
|
onClick={() => pressedInput.fire()}
|
|
/>
|
|
<p>Click on the canvas</p>
|
|
</div>
|
|
);
|
|
}}
|
|
</Story>
|
|
</Canvas>
|
|
|
|
## Rive Text
|
|
|
|
A simple example showing Rive Text rendering. Note that if you are using the `@rive-app/react-canvas-lite` package,
|
|
the Rive Text bit will not render on the graphic, however, the rest of the Rive content should without issue.
|
|
|
|
<Canvas withSource="open">
|
|
<Story name="Rive Text">
|
|
{() => {
|
|
const STATE_MACHINE_NAME = 'State Machine 1';
|
|
const { rive, RiveComponent } = useRive({
|
|
src: 'text_test.riv',
|
|
stateMachines: STATE_MACHINE_NAME,
|
|
autoplay: true,
|
|
automaticallyHandleEvents: true,
|
|
});
|
|
return (
|
|
<div className="center">
|
|
<RiveComponent className="base-canvas-size" />
|
|
</div>
|
|
);
|
|
}}
|
|
</Story>
|
|
</Canvas>
|
|
|
|
## Rive Events
|
|
|
|
To listen for Rive Events reported during state machine play, use the `on` API to add an event listener.
|
|
|
|
<Canvas withSource="open">
|
|
<Story name="Rive Events">
|
|
{() => {
|
|
const STATE_MACHINE_NAME = 'State Machine 1';
|
|
const { rive, RiveComponent } = useRive({
|
|
src: 'rating_animation.riv',
|
|
stateMachines: STATE_MACHINE_NAME,
|
|
autoplay: true,
|
|
automaticallyHandleEvents: true,
|
|
});
|
|
useEffect(() => {
|
|
if (rive) {
|
|
rive.on(EventType.RiveEvent, onRiveEventReceived);
|
|
}
|
|
}, [rive]);
|
|
const onRiveEventReceived = (riveEvent) => {
|
|
console.log('Rive Event Fired', riveEvent);
|
|
};
|
|
return (
|
|
<div className="center">
|
|
<RiveComponent className="base-canvas-size" />
|
|
<p>Click on the 5 star!</p>
|
|
</div>
|
|
);
|
|
}}
|
|
</Story>
|
|
</Canvas>
|