Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/hooks/useViewModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useState, useEffect, useRef } from 'react';
import { EventType, Rive, ViewModel } from '@rive-app/canvas';
import { UseViewModelParameters } from '../types';

const defaultParams: UseViewModelParameters = {
useDefault: false,
name: '',
};

const equal = (
params: UseViewModelParameters | null,
to: UseViewModelParameters | null
): boolean => {
if (!params || !to) {
return false;
}
if (params.useDefault !== to.useDefault || params.name !== to.name) {
return false;
}
return true;
};

/**
* Custom hook for fetching a view model.
*
* @param rive - Rive instance
* @param userParameters - Parameters to load view model
* @returns
*/
export default function useViewModel(
rive: Rive | null,
userParameters?: UseViewModelParameters
): ViewModel | null {
const [viewModel, setViewModel] = useState<ViewModel | null>(null);
const currentParams = useRef<UseViewModelParameters | null>(null);

useEffect(() => {
const parameters = {
...defaultParams,
...userParameters,
};

function getViewModel(): ViewModel | null {
if (rive) {
if (parameters?.useDefault) {
return rive!.defaultViewModel();
} else if (parameters?.name) {
return rive.viewModelByName(parameters?.name);
}
}
return null;
}
function setViewModelValue() {
if (!rive) {
setViewModel(null);
currentParams.current = null;
} else {
const viewModel = getViewModel();
setViewModel(viewModel);
currentParams.current = parameters;
}
}

if (!equal(parameters, currentParams.current)) {
rive?.on(EventType.Load, setViewModelValue);
setViewModelValue();
}
return () => {
rive?.off(EventType.Load, setViewModelValue);
};
}, [rive, userParameters]);

return viewModel;
}
91 changes: 91 additions & 0 deletions src/hooks/useViewModelInstance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useState, useEffect, useRef } from 'react';
import {
EventType,
Rive,
ViewModel,
ViewModelInstance,
} from '@rive-app/canvas';
import { UseViewModelInstanceParameters } from '../types';

const defaultParams: UseViewModelInstanceParameters = {
useDefault: false,
useNew: true,
name: '',
};

const equal = (
params: UseViewModelInstanceParameters | null,
to: UseViewModelInstanceParameters | null
): boolean => {
if (!params || !to) {
return false;
}
if (
params.useDefault !== to.useDefault ||
params.useNew !== to.useNew ||
params.name !== to.name
) {
return false;
}
return true;
};

/**
* Custom hook for fetching a view model instance.
*
* @param rive - Rive instance
* @param userParameters - Parameters to load view model instance
* @returns
*/
export default function useViewModel(
rive: Rive | null,
viewModel: ViewModel | null,
userParameters?: UseViewModelInstanceParameters
) : ViewModelInstance | null {
const [viewModelInstance, setViewModelInstance] =
useState<ViewModelInstance | null>(null);
const currentParams = useRef<UseViewModelInstanceParameters | null>(null);

useEffect(() => {
const parameters = {
...defaultParams,
...userParameters,
};

function setInstance(instance: ViewModelInstance | null) {
setViewModelInstance(instance);
rive!.bindViewModelInstance(instance);
currentParams.current = parameters;
}
function getViewModelInstance(): ViewModelInstance | null {
if (viewModel) {
if (parameters.useDefault) {
return viewModel?.defaultInstance();
} else if (parameters.name) {
return viewModel?.instanceByName(parameters.name);
} else if (parameters.useNew) {
return viewModel?.instance();
}
}
return null;
}
function setViewModelValue() {
if (!rive || !viewModel) {
setViewModelInstance(null);
} else {
const instance = getViewModelInstance();
setInstance(instance ?? null);
}
}

if (!equal(parameters, currentParams.current)) {
rive?.on(EventType.Load, setViewModelValue);
setViewModelValue();
}
return () => {
rive?.off(EventType.Load, setViewModelValue);
};
}, [rive, userParameters]);

return viewModelInstance;
}
99 changes: 99 additions & 0 deletions src/hooks/useViewModelInstanceProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState, useEffect, useRef } from 'react';
import {
EventType,
ViewModelInstance,
} from '@rive-app/canvas';
import { UseViewModelInstanceValueParameters } from '../types';

const defaultParams: UseViewModelInstanceValueParameters = {
viewModelInstance: null,
};

const equal = (
path: string[],
params: UseViewModelInstanceValueParameters | null,
to: HookArguments | null
): boolean => {
if (!params || !to) {
return false;
}
if (
params.rive !== to.parameters.rive ||
params.viewModelInstance !== to.parameters.viewModelInstance ||
path.join('') !== to.path.join('')
) {
return false;
}
return true;
};

type HookArguments = {
path: string[],
parameters: UseViewModelInstanceValueParameters,
}

/**
* Custom hook for fetching a view model instance value.
*
* @param name - name of the propery
* @param path - Path to reach the required property
* @param userParameters - Parameters to load view model instance number
* @returns
*/
export default function useViewModelInstanceProperty(
path: string[] = [],
userParameters?: UseViewModelInstanceValueParameters
): ViewModelInstance | null {
const [viewModelInstance, setViewModelValue] =
useState<ViewModelInstance | null>(null);
const currentArguments = useRef<HookArguments | null>(
null
);

useEffect(() => {
const parameters = {
...defaultParams,
...userParameters,
};

function getInstanceValue(): ViewModelInstance | null {
let viewModelInstance: ViewModelInstance | null = null;
if (userParameters?.viewModelInstance) {
viewModelInstance = userParameters?.viewModelInstance;
} else if (userParameters?.rive) {
viewModelInstance = userParameters?.rive?.viewModelInstance;
}
if (viewModelInstance) {
let index = 0;
while (index < path?.length) {
if(!viewModelInstance) {
return null;
}
viewModelInstance = viewModelInstance?.viewModel(path[index]);
index++;
}
return viewModelInstance;
}
return null;
}

function searchViewModelInstance() {
const instanceValue = getInstanceValue();
setViewModelValue(instanceValue);
currentArguments.current = {
parameters,
path,
};
}

if (!equal(path, parameters, currentArguments.current)) {
parameters.rive?.on(EventType.Load, searchViewModelInstance);
searchViewModelInstance();
}
return () => {
parameters.rive?.off(EventType.Load, searchViewModelInstance);
};
}, [path, userParameters]);

return viewModelInstance;
}
90 changes: 90 additions & 0 deletions src/hooks/useViewModelNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useState, useEffect, useRef } from 'react';
import {
EventType,
ViewModelInstance,
ViewModelInstanceNumber,
} from '@rive-app/canvas';
import { UseViewModelInstanceNumberParameters } from '../types';
import useViewModelInstanceProperty from './useViewModelInstanceProperty';

const defaultParams: UseViewModelInstanceNumberParameters = {
viewModelInstance: null,
initialValue: 0,
};

const equal = (
name: string,
params: UseViewModelInstanceNumberParameters | null,
viewModelInstance: ViewModelInstance | null,
to: HookArguments | null
): boolean => {
if (!params || !to) {
return false;
}
if (
params.initialValue !== to.parameters.initialValue ||
name !== to.name ||
viewModelInstance !== to.viewModelInstance
) {
return false;
}
return true;
};

type HookArguments = {
name: string,
parameters: UseViewModelInstanceNumberParameters,
viewModelInstance: ViewModelInstance | null,
}

/**
* Custom hook for fetching a view model instance value.
*
* @param name - name of the propery
* @param path - Path to reach the required property
* @param userParameters - Parameters to load view model instance number
* @returns
*/
export default function useViewModelNumber(
name: string,
path: string[] = [],
userParameters?: UseViewModelInstanceNumberParameters
): ViewModelInstanceNumber | null {
const [viewModel, setViewModelValue] =
useState<ViewModelInstanceNumber | null>(null);
const currentArguments = useRef<HookArguments | null>(
null
);

const viewModelInstance = useViewModelInstanceProperty(path, userParameters);

useEffect(() => {
const parameters = {
...defaultParams,
...userParameters,
};

function searchViewModelValue() {
const instanceValue = viewModelInstance?.number(name) || null;
if(instanceValue !== null && parameters.initialValue !== undefined) {
instanceValue.value = parameters.initialValue;
}
setViewModelValue(instanceValue);
currentArguments.current = {
parameters,
name,
viewModelInstance,
};
}

if (!equal(name, parameters, viewModelInstance, currentArguments.current)) {
parameters.rive?.on(EventType.Load, searchViewModelValue);
searchViewModelValue();
}
return () => {
parameters.rive?.off(EventType.Load, searchViewModelValue);
};
}, [name, userParameters, viewModelInstance]);

return viewModel;
}
Loading
Loading