diff --git a/.prettierignore b/.prettierignore index 22fa1b9..944dc8d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -38,4 +38,6 @@ releases/ .output/ .next/ -.nuxt/ \ No newline at end of file +.nuxt/ + +apps/node/ \ No newline at end of file diff --git a/apps/node/script.mjs b/apps/node/script.mjs index b0124ee..b757b3d 100644 --- a/apps/node/script.mjs +++ b/apps/node/script.mjs @@ -6,6 +6,196 @@ import fs from 'fs'; import { DotLottie } from '@dotlottie/dotlottie-js/node'; +async function createDotLottieForTests() { + const dotLottie = new DotLottie(); + + await dotLottie + .setAuthor('Joe') + .setVersion('1.0') + .addAnimation({ + id: 'pigeon', + url: 'https://lottie.host/071a2de9-52ca-4ce4-ba2f-a5befd220bdd/ECzVp4eaMa.json', + }) + .addStateMachine({ + descriptor: { + id: 'exploding_pigeon', + initial: 0, + }, + states: [ + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + loop: false, + marker: "bird" + }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'explosion', + }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'feathers', + } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 1, + to_state: 2, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 2, + to_state: 0, + on_complete_event: {}, + }, + ], + context_variables: [], + listeners: [] + }) + .addStateMachine({ + descriptor: { + id: 'pigeon_without_explosion', + initial: 0, + }, + states: [ + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + loop: false, + marker: "bird" + }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'feathers', + } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 1, + to_state: 0, + on_complete_event: {}, + }, + ], + context_variables: [], + listeners: [] + }) + .build() + .then((value) => { + return value.toArrayBuffer(); + }) + .then((value) => { + fs.writeFileSync('exploding-pigeons-test-file.lottie', Buffer.from(value)); + }); +} + +async function createExplodingPigeon() { + const dotLottie = new DotLottie(); + + await dotLottie + .setAuthor('Joe') + .setVersion('1.0') + .addAnimation({ + id: 'pigeon', + url: 'https://lottie.host/071a2de9-52ca-4ce4-ba2f-a5befd220bdd/ECzVp4eaMa.json', + }) + .addStateMachine({ + descriptor: { + id: 'exploding_pigeon', + initial: 0, + }, + states: [ + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + loop: false, + marker: "bird" + }, + + { + animation_d: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'explosion', + }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'feathers', + } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 1, + to_state: 2, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 2, + to_state: 0, + on_complete_event: {}, + }, + ], + listeners: [], + context_variables: [ + { + type: "Numeric", + key: "counter_6", + value: 6 + } + ] + }) + .build() + .then((value) => { + return value.toArrayBuffer(); + }) + .then((value) => { + fs.writeFileSync('exploding_pigeon.zip', Buffer.from(value)); + }); +} + async function createDotLottie() { const dotLottie = new DotLottie(); @@ -21,7 +211,7 @@ async function createDotLottie() { url: 'https://lottie.host/cf7b43d1-3d6b-407a-970b-6305b18bebfa/uB1Jboo1o1.json', autoplay: true, }) - .addState({ + .addStateMachine({ id: 'state_1', state: { descriptor: { @@ -52,4 +242,6 @@ async function createDotLottie() { }); } -createDotLottie(); +// createDotLottie(); +// createExplodingPigeon(); +createDotLottieForTests(); diff --git a/packages/dotlottie-js/src/common/dotlottie-common.ts b/packages/dotlottie-js/src/common/dotlottie-common.ts index 608e63f..8358fb0 100644 --- a/packages/dotlottie-js/src/common/dotlottie-common.ts +++ b/packages/dotlottie-js/src/common/dotlottie-common.ts @@ -2,6 +2,8 @@ * Copyright 2023 Design Barn Inc. */ +/* eslint-disable @typescript-eslint/naming-convention */ + import type { Animation as AnimationType } from '@lottiefiles/lottie-types'; import type { ZipOptions } from 'fflate'; @@ -611,6 +613,9 @@ export class DotLottieCommon { const stateOption = { states: stateMachine.states, descriptor: { id: stateMachine.id, initial: stateMachine.initial }, + transitions: stateMachine.transitions, + listeners: stateMachine.listeners, + context_variables: stateMachine.contextVariables, zipOptions: stateMachine.zipOptions, }; diff --git a/packages/dotlottie-js/src/common/dotlottie-state-machine-common.ts b/packages/dotlottie-js/src/common/dotlottie-state-machine-common.ts index 2dc21cd..e2548be 100644 --- a/packages/dotlottie-js/src/common/dotlottie-state-machine-common.ts +++ b/packages/dotlottie-js/src/common/dotlottie-state-machine-common.ts @@ -2,31 +2,55 @@ * Copyright 2023 Design Barn Inc. */ +/* eslint-disable @typescript-eslint/naming-convention */ + import type { ZipOptions } from 'fflate'; import { safeParse, flatten } from 'valibot'; +import type { + DotLottieContextVariables, + DotLottieDescriptor, + DotLottieListener, + DotLottieListeners, + DotLottieStates, + DotLottieTransition, + DotLottieTransitions, +} from './dotlottie-state'; import { - DotLottieStatesSchema, - type DotLottieStates, - type DotLottieStateMachineDescriptor, - DotLottieStateMachineDescriptorSchema, + ContextVariablesSchema, + DescriptorSchema, + ListenersSchemas, + StatesSchema, + TransitionsSchema, } from './dotlottie-state'; -import { DotLottieError, ErrorCodes, createError } from './utils'; +import { DotLottieError, ErrorCodes } from './utils'; export interface DotLottieStateMachineCommonOptions { - descriptor: DotLottieStateMachineDescriptor; + context_variables: DotLottieContextVariables; + descriptor: DotLottieDescriptor; + listeners: DotLottieListeners; states: DotLottieStates; + transitions: DotLottieTransitions; zipOptions?: ZipOptions; } export class DotLottieStateMachineCommon { - protected _descriptor: DotLottieStateMachineDescriptor; + protected _descriptor: DotLottieDescriptor; protected _zipOptions: ZipOptions; protected _states: DotLottieStates; + protected _transitions: DotLottieTransition[]; + + protected _listeners: DotLottieListener[]; + + protected _contextVariables: DotLottieContextVariables; + public constructor(options: DotLottieStateMachineCommonOptions) { + this._requireValidContextVariables(options.context_variables); + this._requireValidListeners(options.listeners); + this._requireValidTransitions(options.transitions); this._requireValidId(options.descriptor.id); this._requireValidStates(options.states); this._requireValidDescriptor(options.descriptor); @@ -36,6 +60,14 @@ export class DotLottieStateMachineCommon { this._zipOptions = options.zipOptions ?? {}; this._states = options.states; + + this._descriptor = options.descriptor; + + this._listeners = options.listeners; + + this._transitions = options.transitions; + + this._contextVariables = options.context_variables; } public get zipOptions(): ZipOptions { @@ -64,19 +96,43 @@ export class DotLottieStateMachineCommon { this._states = states; } - public get initial(): string { + public get transitions(): DotLottieTransition[] { + return this._transitions; + } + + public set transitions(transitions: DotLottieTransition[]) { + this._transitions = transitions; + } + + public get listeners(): DotLottieListener[] { + return this._listeners; + } + + public set listeners(listeners: DotLottieListener[]) { + this._listeners = listeners; + } + + public get contextVariables(): DotLottieContextVariables { + return this._contextVariables; + } + + public set contextVariables(contextVariables: DotLottieContextVariables) { + this._contextVariables = contextVariables; + } + + public get initial(): number { return this._descriptor.initial; } - public set initial(initial: string) { + public set initial(initial: number) { this._descriptor.initial = initial; } - public get descriptor(): DotLottieStateMachineDescriptor { + public get descriptor(): DotLottieDescriptor { return this._descriptor; } - public set descriptor(descriptor: DotLottieStateMachineDescriptor) { + public set descriptor(descriptor: DotLottieDescriptor) { this._descriptor = descriptor; } @@ -84,30 +140,63 @@ export class DotLottieStateMachineCommon { return JSON.stringify({ descriptor: this._descriptor, states: this._states, + transitions: this._transitions, + context_variables: this._contextVariables, + listeners: this._listeners, }); } protected _requireValidId(id: string | undefined): void { if (!id) { - throw createError('Invalid id.'); + throw new DotLottieError('Invalid id.'); } } - protected _requireValidDescriptor(descriptor: DotLottieStateMachineDescriptor): void { - const result = safeParse(DotLottieStateMachineDescriptorSchema, descriptor); + protected _requireValidDescriptor(descriptor: DotLottieDescriptor): void { + const result = safeParse(DescriptorSchema, descriptor); if (!result.success) { - const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.error).nested, null, 2)}`; + const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.issues).nested, null, 2)}`; throw new DotLottieError(`Invalid descriptor: ${error}`, ErrorCodes.INVALID_STATEMACHINE); } } protected _requireValidStates(states: DotLottieStates): void { - const result = safeParse(DotLottieStatesSchema, states); + const result = safeParse(StatesSchema, states); + + if (!result.success) { + const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.issues).nested, null, 2)}`; + + throw new DotLottieError(`Invalid states: ${error}`, ErrorCodes.INVALID_STATEMACHINE); + } + } + + protected _requireValidContextVariables(contextVariables: DotLottieContextVariables): void { + const result = safeParse(ContextVariablesSchema, contextVariables); + + if (!result.success) { + const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.issues).nested, null, 2)}`; + + throw new DotLottieError(`Invalid states: ${error}`, ErrorCodes.INVALID_STATEMACHINE); + } + } + + protected _requireValidListeners(listeners: DotLottieListeners): void { + const result = safeParse(ListenersSchemas, listeners); + + if (!result.success) { + const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.issues).nested, null, 2)}`; + + throw new DotLottieError(`Invalid states: ${error}`, ErrorCodes.INVALID_STATEMACHINE); + } + } + + protected _requireValidTransitions(transitions: DotLottieTransitions): void { + const result = safeParse(TransitionsSchema, transitions); if (!result.success) { - const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.error).nested, null, 2)}`; + const error = `Invalid state machine declaration, ${JSON.stringify(flatten(result.issues).nested, null, 2)}`; throw new DotLottieError(`Invalid states: ${error}`, ErrorCodes.INVALID_STATEMACHINE); } diff --git a/packages/dotlottie-js/src/common/dotlottie-state.ts b/packages/dotlottie-js/src/common/dotlottie-state.ts index 844020c..f739003 100644 --- a/packages/dotlottie-js/src/common/dotlottie-state.ts +++ b/packages/dotlottie-js/src/common/dotlottie-state.ts @@ -2,103 +2,149 @@ * Copyright 2023 Design Barn Inc. */ -import type { Output } from 'valibot'; -import { - merge, - number, - object, - optional, - string, - union, - omit, - record, - tuple, - maxValue, - minValue, - array, -} from 'valibot'; - -import { ManifestAnimationSchema } from './manifest'; - -export const PlaybackOptionsSchema = omit(ManifestAnimationSchema, ['id']); - -export type PlaybackOptions = Output; - -export const TransitionableSchema = object({ - state: string(), -}); -export type Transitionable = Output; +/* eslint-disable @typescript-eslint/naming-convention */ -export const StateTransitionOnClickSchema = TransitionableSchema; +import type { Output } from 'valibot'; +import { boolean, number, object, optional, string, array, union, tuple } from 'valibot'; -export type StateTransitionOnClick = Output; +const NumericStringBooleanType = union([string('Numeric'), string('String'), string('Boolean')]); -export const StateTransitionOnAfterSchema = merge([TransitionableSchema, object({ ms: number() })]); +// Guard Schema +export const GuardSchema = object({ + type: NumericStringBooleanType, + context_key: string(), + condition_type: string(), + compare_to: union([string(), number(), boolean()]), +}); -export type StateTransitionOnAfter = Output; +// Event Schemas +const NumericEventSchema = object({ value: number() }); +const BooleanEventSchema = object({ value: boolean() }); +const StringEventSchema = object({ value: string() }); +const PointerEventSchema = object({ target: optional(string()) }); + +// const TransitionType = union([string('Transition')]); +const TransitionType = string('Transition'); + +// Transition Schema +export const TransitionSchema = object({ + type: TransitionType, + from_state: number(), + to_state: number(), + guards: optional(array(GuardSchema)), + numeric_event: optional(NumericEventSchema), + boolean_event: optional(BooleanEventSchema), + string_event: optional(StringEventSchema), + on_complete_event: optional(object({})), + on_pointer_down_event: optional(PointerEventSchema), + on_pointer_up_event: optional(PointerEventSchema), + on_pointer_enter_event: optional(PointerEventSchema), + on_pointer_exit_event: optional(PointerEventSchema), + on_pointer_move_event: optional(PointerEventSchema), +}); -export const StateTransitionOnEnterSchema = merge([TransitionableSchema, object({ count: number() })]); +export const TransitionsSchema = array(TransitionSchema); + +// Entry/Exit Action Schema +const URLActionSchema = object({ type: string(), url: string(), target: string() }); +const ThemeActionSchema = object({ type: string(), themeId: string() }); +const SoundActionSchema = object({ type: string(), soundId: string() }); +const LogActionSchema = object({ type: string(), message: string() }); + +const ActionSchema = union([URLActionSchema, ThemeActionSchema, SoundActionSchema, LogActionSchema]); + +const Modes = union([string('Forward'), string('Reverse'), string('Bounce'), string('ReverseBounce')]); + +const StateType = union([string('PlaybackState'), string('FinalState'), string('SyncState'), string('GobalState')]); + +export const PlaybackStateSchema = object({ + type: StateType, + animation_id: optional(string()), + loop: optional(boolean()), + autoplay: optional(boolean()), + mode: optional(Modes), + speed: optional(number()), + marker: optional(string()), + segment: optional(optional(tuple([number(), number()]))), + use_frame_interpolation: optional(boolean()), + reset_context: optional(string()), + entry_actions: optional(array(ActionSchema)), + exit_actions: optional(array(ActionSchema)), +}); -export type StateTransitionOnEnter = Output; +export const SyncStateSchema = object({ + type: string(), + animation_id: optional(string()), + frame_context_key: string(), + reset_context: string(), + entry_actions: optional(array(ActionSchema)), + exit_actions: optional(array(ActionSchema)), +}); -export const StateTransitionOnMouseEnterSchema = TransitionableSchema; +export const FinalStateSchema = object({ + type: string(), + reset_context: string(), + entry_actions: optional(array(ActionSchema)), + exit_actions: optional(array(ActionSchema)), +}); -export type StateTransitionOnMouseEnter = Output; +export const GlobalStateSchema = object({ + type: string(), + reset_context: string(), + entry_actions: optional(array(ActionSchema)), + exit_actions: optional(array(ActionSchema)), +}); -export const StateTransitionOnMouseLeaveSchema = TransitionableSchema; +export const StateSchema = union([PlaybackStateSchema, SyncStateSchema, FinalStateSchema, GlobalStateSchema]); +export const StatesSchema = array(StateSchema); -export type StateTransitionOnMouseLeave = Output; +// Listener Schema +export const ListenerSchema = object({ + type: string(), + target: optional(string()), + action: string(), + value: union([string(), boolean(), number()]), + context_key: string(), +}); -export const StateTransitionOnCompleteSchema = TransitionableSchema; +export const ListenersSchemas = array(ListenerSchema); -export type StateTransitionOnComplete = Output; +// Context Variable Schema +export const ContextVariableSchema = object({ + type: NumericStringBooleanType, + key: string(), + value: union([number(), string(), boolean()]), +}); -export const StateTransitionOnShowSchema = merge([ - TransitionableSchema, - object({ threshold: optional(array(number([minValue(0), maxValue(1)]))) }), -]); -export type StateTransitionOnShow = Output; +export const ContextVariablesSchema = array(ContextVariableSchema); -export const DotLottieStateTransitionEventsSchema = object({ - onAfter: optional(StateTransitionOnAfterSchema), - onClick: optional(StateTransitionOnClickSchema), - onComplete: optional(StateTransitionOnCompleteSchema), - onEnter: optional(StateTransitionOnEnterSchema), - onMouseEnter: optional(StateTransitionOnMouseEnterSchema), - onMouseLeave: optional(StateTransitionOnMouseLeaveSchema), - onShow: optional(StateTransitionOnShowSchema), -}); -export type DotLottieStateTransitionEvents = Output; - -export const DotLottieStatePlaybackSettingsSchema = merge([ - PlaybackOptionsSchema, - object({ - playOnScroll: optional(tuple([number([minValue(0), maxValue(1)]), number([minValue(0), maxValue(1)])])), - segments: optional(union([tuple([number(), number()]), string()])), - }), -]); -export type DotLottieStatePlaybackSettings = Output; - -export const DotLottieStateSchema = merge([ - DotLottieStateTransitionEventsSchema, - object({ - animationId: optional(string()), - playbackSettings: DotLottieStatePlaybackSettingsSchema, - }), -]); -export type DotLottieState = Output; - -export const DotLottieStatesSchema = record(string(), DotLottieStateSchema); -export type DotLottieStates = Output; - -export const DotLottieStateMachineDescriptorSchema = object({ +// Descriptor Schema +export const DescriptorSchema = object({ id: string(), - initial: string(), + initial: number(), }); -export type DotLottieStateMachineDescriptor = Output; +export type DotLottieStates = Output; +export type DotLottieDescriptor = Output; +export type DotLottieState = Output; +export type DotLottieAction = Output; +export type DotLottieNumericEvent = Output; +export type DotLottieBooleanEvent = Output; +export type DotLottieStringEvent = Output; +export type DotLottiePointerEvent = Output; +export type DotLottieGuard = Output; +export type DotLottieContextVariables = Output; +export type DotLottieListener = Output; +export type DotLottieListeners = Output; +export type DotLottieTransition = Output; +export type DotLottieTransitions = Output; + +// DotLottieStateMachine Schema export const DotLottieStateMachineSchema = object({ - descriptor: DotLottieStateMachineDescriptorSchema, - states: DotLottieStatesSchema, + descriptor: DescriptorSchema, + states: StatesSchema, + transitions: TransitionsSchema, + listeners: ListenersSchemas, + context_variables: ContextVariablesSchema, }); export type DotLottieStateMachine = Output; diff --git a/packages/dotlottie-js/src/tests/__fixtures__/simple/exploding-pigeons-test-file.lottie b/packages/dotlottie-js/src/tests/__fixtures__/simple/exploding-pigeons-test-file.lottie new file mode 100644 index 0000000..9ac07d3 Binary files /dev/null and b/packages/dotlottie-js/src/tests/__fixtures__/simple/exploding-pigeons-test-file.lottie differ diff --git a/packages/dotlottie-js/src/tests/__fixtures__/simple/state/pigeon-state.ts b/packages/dotlottie-js/src/tests/__fixtures__/simple/state/pigeon-state.ts index dc1e2b0..d03823d 100644 --- a/packages/dotlottie-js/src/tests/__fixtures__/simple/state/pigeon-state.ts +++ b/packages/dotlottie-js/src/tests/__fixtures__/simple/state/pigeon-state.ts @@ -3,79 +3,89 @@ import { DotLottieStateMachine } from "../../../../common" export const PigeonState: DotLottieStateMachine = { descriptor: { id: 'exploding_pigeon', - initial: 'running', + initial: 0, }, - states: { - running: { - animationId:"pigeon", - playbackSettings: { - autoplay: true, - loop: true, - direction: 1 , - segments: 'bird', - }, - onClick: { - state: 'exploding', - }, + states: [ + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + loop: false, + marker: "bird" }, - exploding: { - animationId:"pigeon", - playbackSettings: { - autoplay: true, - loop: 3, - direction: 1 , - segments: 'explosion', - }, - onComplete: { - state: 'feathers', - }, + + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'explosion', }, - feathers: { - animationId:"pigeon", - playbackSettings: { - autoplay: true, - loop: false, - direction: 1 , - segments: 'feathers', - }, - onComplete: { - state: 'running', - }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'feathers', + } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + on_complete_event: {}, }, - }, + { + type: "Transition", + from_state: 1, + to_state: 2, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 2, + to_state: 0, + on_complete_event: {}, + }, + ], + context_variables: [], + listeners: [] } export const SmileyWifi: DotLottieStateMachine = { - descriptor: { - id: 'simple_click_to_next_prev', - initial: 'bounceState', + descriptor: { + id: 'simple_click_to_next_prev', + initial: 0, + }, + states: [ + { + type: "PlaybackState", + animation_id: 'smiley', + autoplay: true, + loop: true, + mode: "Reverse", + speed: 2, }, - states: { - smileyState: { - animationId: 'smiley', - playbackSettings: { - autoplay: true, - loop: true, - direction: -1 , - speed: 2, - defaultTheme: 'bounce-dark', - }, - onMouseEnter: { - state: 'wifiState', - }, - }, - wifiState: { - animationId: 'wifi', - playbackSettings: { - autoplay: true, - loop: true, - direction: 1 , - defaultTheme: 'wifi-dark', - }, - onMouseLeave: { - state: 'smileyState', - }, - }, + { + type: "PlaybackState", + animation_id: 'wifi', + autoplay: true, + loop: true, + mode: "Forward", }, - } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + string_event: { value: 'click' }, + } + ], + listeners: [], + context_variables: [] +}; diff --git a/packages/dotlottie-js/src/tests/__fixtures__/simple/state/segments-state.ts b/packages/dotlottie-js/src/tests/__fixtures__/simple/state/segments-state.ts index 09d9c54..31158d2 100644 --- a/packages/dotlottie-js/src/tests/__fixtures__/simple/state/segments-state.ts +++ b/packages/dotlottie-js/src/tests/__fixtures__/simple/state/segments-state.ts @@ -1,21 +1,42 @@ import { DotLottieStateMachine } from "../../../../common"; -export const SegmentsState: DotLottieStateMachine = { - descriptor: { - id: "state_segments", - initial: "loopState" - }, - states: { - loopState: { - animationId: "segments", - playbackSettings: { +export const PigeonWithoutExplosion: DotLottieStateMachine = + { + descriptor: { + id: 'pigeon_without_explosion', + initial: 0, + }, + states: [ + { + animation_id: "pigeon", + type: "PlaybackState", autoplay: true, - loop: true, - segments: [ - 70, - 500 - ] + loop: false, + marker: "bird" + }, + { + animation_id: "pigeon", + type: "PlaybackState", + autoplay: true, + speed: 0.8, + loop: false, + marker: 'feathers', } - } + ], + transitions: [ + { + type: "Transition", + from_state: 0, + to_state: 1, + on_complete_event: {}, + }, + { + type: "Transition", + from_state: 1, + to_state: 0, + on_complete_event: {}, + }, + ], + context_variables: [], + listeners: [] } -} diff --git a/packages/dotlottie-js/src/tests/__fixtures__/simple/states.lottie b/packages/dotlottie-js/src/tests/__fixtures__/simple/states.lottie deleted file mode 100644 index fb13362..0000000 Binary files a/packages/dotlottie-js/src/tests/__fixtures__/simple/states.lottie and /dev/null differ diff --git a/packages/dotlottie-js/src/tests/lottie-state-browser.spec.ts b/packages/dotlottie-js/src/tests/lottie-state-browser.spec.ts index 133d17a..26930db 100644 --- a/packages/dotlottie-js/src/tests/lottie-state-browser.spec.ts +++ b/packages/dotlottie-js/src/tests/lottie-state-browser.spec.ts @@ -3,6 +3,7 @@ */ /* eslint-disable no-new */ +/* eslint-disable @typescript-eslint/naming-convention */ import type { AnimationData } from '../common'; import { DotLottie } from '../dotlottie'; @@ -18,17 +19,23 @@ describe('LottieState', () => { expect(() => { // act new LottieStateMachine({ - descriptor: { id: '', initial: '' }, + descriptor: { id: '', initial: 0 }, states: PigeonState.states, + listeners: PigeonState.listeners, + transitions: PigeonState.transitions, + context_variables: PigeonState.context_variables, }); // assert - }).toThrowError('[dotlottie-js]: Invalid id.'); + }).toThrowError('Invalid id.'); }); it('gets and sets the zipOptions', () => { const theme = new LottieStateMachine({ - descriptor: { id: 'test', initial: '' }, + descriptor: { id: 'test', initial: 0 }, states: PigeonState.states, + listeners: PigeonState.listeners, + transitions: PigeonState.transitions, + context_variables: PigeonState.context_variables, zipOptions: { level: 9, mem: 1, @@ -52,15 +59,17 @@ describe('LottieState', () => { it('gets and sets the id', () => { // arrange const state = new LottieStateMachine({ - descriptor: { id: 'test', initial: '' }, - states: { - test: { - playbackSettings: { - direction: 1, - autoplay: true, - }, + descriptor: { id: 'test', initial: 0 }, + states: [ + { + type: 'PlaybackState', + mode: 'Forward', + autoplay: true, }, - }, + ], + listeners: [], + transitions: [], + context_variables: [], }); expect(state.id).toEqual('test'); diff --git a/packages/dotlottie-js/src/tests/lottie-state-node.spec.ts b/packages/dotlottie-js/src/tests/lottie-state-node.spec.ts index 7754429..ae3625e 100644 --- a/packages/dotlottie-js/src/tests/lottie-state-node.spec.ts +++ b/packages/dotlottie-js/src/tests/lottie-state-node.spec.ts @@ -3,6 +3,7 @@ */ /* eslint-disable no-new */ +/* eslint-disable @typescript-eslint/naming-convention */ import type { AnimationData } from '../common'; import { DotLottie } from '../dotlottie'; @@ -18,17 +19,23 @@ describe('LottieState', () => { expect(() => { // act new LottieStateMachine({ - descriptor: { id: '', initial: '' }, - states: {}, + descriptor: { id: '', initial: 0 }, + states: [], + transitions: [], + listeners: [], + context_variables: [], }); // assert - }).toThrowError('[dotlottie-js]: Invalid id.'); + }).toThrowError('Invalid id.'); }); it('gets and sets the zipOptions', () => { const theme = new LottieStateMachine({ - descriptor: { id: 'test', initial: '' }, - states: {}, + descriptor: { id: 'test', initial: 0 }, + states: [], + transitions: [], + listeners: [], + context_variables: [], zipOptions: { level: 9, mem: 1, @@ -52,8 +59,11 @@ describe('LottieState', () => { it('gets and sets the id', () => { // arrange const state = new LottieStateMachine({ - descriptor: { id: 'test', initial: '' }, - states: {}, + descriptor: { id: 'test', initial: 0 }, + states: [], + transitions: [], + listeners: [], + context_variables: [], }); expect(state.id).toEqual('test'); @@ -70,6 +80,9 @@ describe('LottieState', () => { const pigeonState = new LottieStateMachine({ descriptor: PigeonState.descriptor, states: PigeonState.states, + transitions: PigeonState.transitions, + listeners: PigeonState.listeners, + context_variables: PigeonState.context_variables, }); // assert diff --git a/packages/dotlottie-js/src/tests/utils-browser.spec.ts b/packages/dotlottie-js/src/tests/utils-browser.spec.ts index 9e0ebf4..3de453d 100644 --- a/packages/dotlottie-js/src/tests/utils-browser.spec.ts +++ b/packages/dotlottie-js/src/tests/utils-browser.spec.ts @@ -35,9 +35,9 @@ import dotLottieManifest from './__fixtures__/simple/animation/manifest.json'; import dotLottieTheme from './__fixtures__/simple/animation/themes/theme1.json'; import dotLottieAnimationWithImages from './__fixtures__/simple/big-merged-dotlottie.lottie'; import bullAnimation from './__fixtures__/simple/bull.lottie'; +import stateAnimation from './__fixtures__/simple/exploding-pigeons-test-file.lottie'; import { PigeonState } from './__fixtures__/simple/state/pigeon-state'; -import { SegmentsState } from './__fixtures__/simple/state/segments-state'; -import stateAnimation from './__fixtures__/simple/states.lottie'; +import { PigeonWithoutExplosion } from './__fixtures__/simple/state/segments-state'; describe('createError', () => { it('returns an instance of Error with the correct message', () => { @@ -252,9 +252,9 @@ describe('getStateMachine', () => { }); it('gets state machine by id', async () => { - const stateMachine = await getStateMachine(stateAnimation, 'state_segments'); + const stateMachine = await getStateMachine(stateAnimation, 'pigeon_without_explosion'); - expect(stateMachine?.states).toEqual(SegmentsState.states); + expect(stateMachine?.states).toEqual(PigeonWithoutExplosion.states); }); }); @@ -332,11 +332,7 @@ describe('getStateMachines', () => { it('returns a map of state machines', async () => { const stateMachines = await getStateMachines(stateAnimation); - // Not all states are being checked - // const stateSegments = `{"descriptor":{"id":"state_segments","initial":"loopState"},"states":{"loopState":{"animationId":"segments","statePlaybackSettings":{"autoplay":true,"loop":true,"segments":[70,500]}}}}`; - // const explodingPigeon = `{"descriptor":{"id":"exploding_pigeon","initial":"running"},"states":{"running":{"animationId":"pigeon","statePlaybackSettings":{"autoplay":true,"loop":true,"direction":1,"segments":"bird"},"onClick":{"state":"exploding"}},"exploding":{"animationId":"pigeon","statePlaybackSettings":{"autoplay":true,"loop":3,"direction":1,"segments":"explosion"},"onComplete":{"state":"feathers"}},"feathers":{"animationId":"pigeon","statePlaybackSettings":{"autoplay":true,"loop":false,"direction":1,"segments":"feathers"},"onComplete":{"state":"running"}}}}`; - - expect(stateMachines['state_segments']).toEqual(JSON.stringify(SegmentsState)); + expect(stateMachines['pigeon_without_explosion']).toEqual(JSON.stringify(PigeonWithoutExplosion)); expect(stateMachines['exploding_pigeon']).toEqual(JSON.stringify(PigeonState)); }); diff --git a/packages/dotlottie-js/src/tests/utils-node.spec.ts b/packages/dotlottie-js/src/tests/utils-node.spec.ts index ef8378a..5463c11 100644 --- a/packages/dotlottie-js/src/tests/utils-node.spec.ts +++ b/packages/dotlottie-js/src/tests/utils-node.spec.ts @@ -35,9 +35,9 @@ import dotLottieManifest from './__fixtures__/simple/animation/manifest.json'; import dotLottieTheme from './__fixtures__/simple/animation/themes/theme1.json'; import dotLottieAnimationWithImages from './__fixtures__/simple/big-merged-dotlottie.lottie'; import bullAnimation from './__fixtures__/simple/bull.lottie'; +import stateAnimation from './__fixtures__/simple/exploding-pigeons-test-file.lottie'; import { PigeonState } from './__fixtures__/simple/state/pigeon-state'; -import { SegmentsState } from './__fixtures__/simple/state/segments-state'; -import stateAnimation from './__fixtures__/simple/states.lottie'; +import { PigeonWithoutExplosion } from './__fixtures__/simple/state/segments-state'; describe('createError', () => { it('returns an instance of Error with the correct message', () => { @@ -260,9 +260,9 @@ describe('getStateMachine', () => { }); it('gets state machine by id', async () => { - const stateMachine = await getStateMachine(stateAnimation, 'state_segments'); + const stateMachine = await getStateMachine(stateAnimation, 'pigeon_without_explosion'); - expect(stateMachine?.states).toEqual(SegmentsState.states); + expect(stateMachine?.states).toEqual(PigeonWithoutExplosion.states); }); }); @@ -296,9 +296,7 @@ describe('getStateMachines', () => { it('returns a map of state machines', async () => { const stateMachines = await getStateMachines(stateAnimation); - // Not all states are being checked - - expect(stateMachines['state_segments']).toEqual(JSON.stringify(SegmentsState)); + expect(stateMachines['pigeon_without_explosion']).toEqual(JSON.stringify(PigeonWithoutExplosion)); expect(stateMachines['exploding_pigeon']).toEqual(JSON.stringify(PigeonState)); });