More API docs
This commit is contained in:
parent
a86e220bdc
commit
7815fb2dc3
7 changed files with 442 additions and 96 deletions
|
@ -38,6 +38,15 @@ export interface IProject {
|
||||||
* The project's address
|
* The project's address
|
||||||
*/
|
*/
|
||||||
readonly address: ProjectAddress
|
readonly address: ProjectAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Sheet under the project
|
||||||
|
* @param sheetId Sheets are identified by their `sheetId`, which must be a string longer than 3 characters
|
||||||
|
* @param instanceId Optionally provide an `instanceId` if you want to create multiple instances of the same Sheet
|
||||||
|
* @returns The newly created Sheet
|
||||||
|
*
|
||||||
|
* **Docs: https://docs.theatrejs.com/in-depth/#sheets**
|
||||||
|
*/
|
||||||
sheet(sheetId: string, instanceId?: string): ISheet
|
sheet(sheetId: string, instanceId?: string): ISheet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
||||||
|
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
|
||||||
import type {
|
import type {
|
||||||
IShorthandCompoundProps,
|
IShorthandCompoundProps,
|
||||||
IValidCompoundProps,
|
IValidCompoundProps,
|
||||||
|
@ -7,48 +8,123 @@ import type {
|
||||||
import {sanitizeCompoundProps} from './internals'
|
import {sanitizeCompoundProps} from './internals'
|
||||||
import {propTypeSymbol} from './internals'
|
import {propTypeSymbol} from './internals'
|
||||||
|
|
||||||
|
const validateCommonOpts = (
|
||||||
|
fnCallSignature: string,
|
||||||
|
opts?: PropTypeConfigOpts,
|
||||||
|
) => {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
if (opts === undefined) return
|
||||||
|
if (typeof opts !== 'object' || opts === null) {
|
||||||
|
throw new Error(
|
||||||
|
`opts in ${fnCallSignature} must either be undefined or an object.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(opts, 'label')) {
|
||||||
|
const {label} = opts
|
||||||
|
if (typeof label !== 'string') {
|
||||||
|
throw new Error(
|
||||||
|
`opts.label in ${fnCallSignature} should be a string. ${userReadableTypeOfValue(
|
||||||
|
label,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (label.trim().length !== label.length) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.label in ${fnCallSignature} should not start/end with whitespace. "${label}" given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (label.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.label in ${fnCallSignature} should not be an empty string. If you wish to have no label, remove opts.label from opts.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a compound prop type (basically a JS object).
|
* A compound prop type (basically a JS object).
|
||||||
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* ```ts
|
* ```ts
|
||||||
* // the root prop type of an object is always a compound
|
* // shorthand
|
||||||
* const props = {
|
* const position = {
|
||||||
* // compounds can be nested
|
* x: 0,
|
||||||
* position: t.compound({
|
* y: 0
|
||||||
* x: t.number(0),
|
|
||||||
* y: t.number(0)
|
|
||||||
* })
|
|
||||||
* }
|
* }
|
||||||
|
* assert(sheet.object('some object', position).value.x === 0)
|
||||||
*
|
*
|
||||||
* const obj = sheet.obj('key', props)
|
* // nesting
|
||||||
* console.log(obj.value) // {position: {x: 10.3, y: -1}}
|
* const foo = {bar: {baz: {quo: 0}}}
|
||||||
|
* assert(sheet.object('some object', foo).bar.baz.quo === 0)
|
||||||
|
*
|
||||||
|
* // With additional options:
|
||||||
|
* const position = t.compound(
|
||||||
|
* {x: 0, y: 0},
|
||||||
|
* // a custom label for the prop:
|
||||||
|
* {label: "Position"}
|
||||||
|
* )
|
||||||
* ```
|
* ```
|
||||||
* @param props
|
* @param props
|
||||||
* @param extras
|
* @param opts
|
||||||
* @returns
|
* @returns
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const compound = <Props extends IShorthandCompoundProps>(
|
export const compound = <Props extends IShorthandCompoundProps>(
|
||||||
props: Props,
|
props: Props,
|
||||||
extras?: PropTypeConfigExtras,
|
opts?: PropTypeConfigOpts,
|
||||||
): PropTypeConfig_Compound<
|
): PropTypeConfig_Compound<
|
||||||
ShorthandCompoundPropsToLonghandCompoundProps<Props>
|
ShorthandCompoundPropsToLonghandCompoundProps<Props>
|
||||||
> => {
|
> => {
|
||||||
|
validateCommonOpts('t.compound(props, opts)', opts)
|
||||||
return {
|
return {
|
||||||
type: 'compound',
|
type: 'compound',
|
||||||
props: sanitizeCompoundProps(props),
|
props: sanitizeCompoundProps(props),
|
||||||
valueType: null as $IntentionalAny,
|
valueType: null as $IntentionalAny,
|
||||||
[propTypeSymbol]: 'TheatrePropType',
|
[propTypeSymbol]: 'TheatrePropType',
|
||||||
label: extras?.label,
|
label: opts?.label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A number prop type.
|
||||||
*
|
*
|
||||||
* @param defaultValue
|
* Usage
|
||||||
* @param opts
|
* ```ts
|
||||||
* @returns
|
* // shorthand:
|
||||||
|
* const obj = sheet.object('key', {x: 0})
|
||||||
*
|
*
|
||||||
|
* // With options (equal to above)
|
||||||
|
* const obj = sheet.object('key', {
|
||||||
|
* x: t.number(0)
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // With a range (note that opts.range is just a visual guide, not a validation rule)
|
||||||
|
* const x = t.number(0, {range: [0, 10]}) // limited to 0 and 10
|
||||||
|
*
|
||||||
|
* // With custom nudging
|
||||||
|
* const x = t.number(0, {nudgeMultiplier: 0.1}) // nudging will happen in 0.1 increments
|
||||||
|
*
|
||||||
|
* // With custom nudging function
|
||||||
|
* const x = t.number({
|
||||||
|
* nudgeFn: (
|
||||||
|
* // the mouse movement (in pixels)
|
||||||
|
* deltaX: number,
|
||||||
|
* // the movement as a fraction of the width of the number editor's input
|
||||||
|
* deltaFraction: number,
|
||||||
|
* // A multiplier that's usually 1, but might be another number if user wants to nudge slower/faster
|
||||||
|
* magnitude: number,
|
||||||
|
* // the configuration of the number
|
||||||
|
* config: {nudgeMultiplier?: number; range?: [number, number]},
|
||||||
|
* ): number => {
|
||||||
|
* return deltaX * magnitude
|
||||||
|
* },
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param defaultValue The default value (Must be a finite number)
|
||||||
|
* @param opts The options (See usage examples)
|
||||||
|
* @returns A number prop config
|
||||||
*/
|
*/
|
||||||
export const number = (
|
export const number = (
|
||||||
defaultValue: number,
|
defaultValue: number,
|
||||||
|
@ -56,8 +132,60 @@ export const number = (
|
||||||
nudgeFn?: PropTypeConfig_Number['nudgeFn']
|
nudgeFn?: PropTypeConfig_Number['nudgeFn']
|
||||||
range?: PropTypeConfig_Number['range']
|
range?: PropTypeConfig_Number['range']
|
||||||
nudgeMultiplier?: number
|
nudgeMultiplier?: number
|
||||||
} & PropTypeConfigExtras,
|
} & PropTypeConfigOpts,
|
||||||
): PropTypeConfig_Number => {
|
): PropTypeConfig_Number => {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
validateCommonOpts('t.number(defaultValue, opts)', opts)
|
||||||
|
if (typeof defaultValue !== 'number' || !isFinite(defaultValue)) {
|
||||||
|
throw new Error(
|
||||||
|
`Argument defaultValue in t.number(defaultValue) must be a number. ${userReadableTypeOfValue(
|
||||||
|
defaultValue,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (typeof opts === 'object' && opts) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(opts, 'range')) {
|
||||||
|
if (!Array.isArray(opts.range)) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.range in t.number(defaultValue, opts) must be a tuple of two numbers. ${userReadableTypeOfValue(
|
||||||
|
opts.range,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (opts.range.length !== 2) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.range in t.number(defaultValue, opts) must have two elements. ${opts.range.length} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!opts.range.every((n) => typeof n === 'number' && isFinite(n))) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.range in t.number(defaultValue, opts) must be a tuple of two finite numbers.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(opts, 'nudgeMultiplier')) {
|
||||||
|
if (
|
||||||
|
typeof opts!.nudgeMultiplier !== 'number' ||
|
||||||
|
!isFinite(opts!.nudgeMultiplier)
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`opts.nudgeMultiplier in t.number(defaultValue, opts) must be a finite number. ${userReadableTypeOfValue(
|
||||||
|
opts!.nudgeMultiplier,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(opts, 'nudgeFn')) {
|
||||||
|
if (typeof opts?.nudgeFn !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
`opts.nudgeFn in t.number(defaultValue, opts) must be a function. ${userReadableTypeOfValue(
|
||||||
|
opts!.nudgeFn,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
valueType: 0,
|
valueType: 0,
|
||||||
|
@ -72,57 +200,117 @@ export const number = (
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A boolean prop type
|
||||||
*
|
*
|
||||||
* @param defaultValue
|
* Usage:
|
||||||
* @param extras
|
* ```ts
|
||||||
* @returns
|
* // shorthand:
|
||||||
|
* const obj = sheet.object('key', {isOn: true})
|
||||||
*
|
*
|
||||||
|
* // with a label:
|
||||||
|
* const obj = sheet.object('key', {
|
||||||
|
* isOn: t.boolean(true, {
|
||||||
|
* label: 'Enabled'
|
||||||
|
* })
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param defaultValue The default value (must be a boolean)
|
||||||
|
* @param opts Options (See usage examples)
|
||||||
*/
|
*/
|
||||||
export const boolean = (
|
export const boolean = (
|
||||||
defaultValue: boolean,
|
defaultValue: boolean,
|
||||||
extras?: PropTypeConfigExtras,
|
opts?: PropTypeConfigOpts,
|
||||||
): PropTypeConfig_Boolean => {
|
): PropTypeConfig_Boolean => {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
validateCommonOpts('t.boolean(defaultValue, opts)', opts)
|
||||||
|
if (typeof defaultValue !== 'boolean') {
|
||||||
|
throw new Error(
|
||||||
|
`defaultValue in t.boolean(defaultValue) must be a boolean. ${userReadableTypeOfValue(
|
||||||
|
defaultValue,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: defaultValue,
|
default: defaultValue,
|
||||||
valueType: null as $IntentionalAny,
|
valueType: null as $IntentionalAny,
|
||||||
[propTypeSymbol]: 'TheatrePropType',
|
[propTypeSymbol]: 'TheatrePropType',
|
||||||
label: extras?.label,
|
label: opts?.label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A string prop type
|
||||||
*
|
*
|
||||||
* @param defaultValue
|
* Usage:
|
||||||
* @param extras
|
* ```ts
|
||||||
* @returns
|
* // shorthand:
|
||||||
|
* const obj = sheet.object('key', {message: "Animation loading"})
|
||||||
*
|
*
|
||||||
|
* // with a label:
|
||||||
|
* const obj = sheet.object('key', {
|
||||||
|
* message: t.string("Animation Loading", {
|
||||||
|
* label: 'The Message'
|
||||||
|
* })
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param defaultValue The default value (must be a string)
|
||||||
|
* @param opts The options (See usage examples)
|
||||||
|
* @returns A string prop type
|
||||||
*/
|
*/
|
||||||
export const string = (
|
export const string = (
|
||||||
defaultValue: string,
|
defaultValue: string,
|
||||||
extras?: PropTypeConfigExtras,
|
opts?: PropTypeConfigOpts,
|
||||||
): PropTypeConfig_String => {
|
): PropTypeConfig_String => {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
validateCommonOpts('t.string(defaultValue, opts)', opts)
|
||||||
|
if (typeof defaultValue !== 'string') {
|
||||||
|
throw new Error(
|
||||||
|
`defaultValue in t.string(defaultValue) must be a string. ${userReadableTypeOfValue(
|
||||||
|
defaultValue,
|
||||||
|
)} given.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: defaultValue,
|
default: defaultValue,
|
||||||
valueType: null as $IntentionalAny,
|
valueType: null as $IntentionalAny,
|
||||||
[propTypeSymbol]: 'TheatrePropType',
|
[propTypeSymbol]: 'TheatrePropType',
|
||||||
label: extras?.label,
|
label: opts?.label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A stringLiteral prop type, useful for building menus or radio buttons.
|
||||||
*
|
*
|
||||||
* @param defaultValue
|
* Usage:
|
||||||
* @param options
|
* ```ts
|
||||||
* @param extras
|
* // Basic usage
|
||||||
* @returns
|
* const obj = sheet.object('key', {
|
||||||
|
* light: t.stringLiteral("r", {r: "Red", "g": "Green"})
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // Shown as a radio switch with a custom label
|
||||||
|
* const obj = sheet.object('key', {
|
||||||
|
* light: t.stringLiteral("r", {r: "Red", "g": "Green"})
|
||||||
|
* }, {as: "switch", label: "Street Light"})
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param defaultValue A string
|
||||||
|
* @param options An object like `{[value]: Label}`. Example: {r: "Red", "g": "Green"}
|
||||||
|
* @param opts Extra opts
|
||||||
|
* @param opts.as Determines if editor is shown as a menu or a switch. Either 'menu' or 'switch'. Default: 'menu'
|
||||||
|
* @returns A stringLiteral prop type
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export function stringLiteral<Opts extends {[key in string]: string}>(
|
export function stringLiteral<Opts extends {[key in string]: string}>(
|
||||||
defaultValue: Extract<keyof Opts, string>,
|
defaultValue: Extract<keyof Opts, string>,
|
||||||
options: Opts,
|
options: Opts,
|
||||||
extras?: {as?: 'menu' | 'switch'} & PropTypeConfigExtras,
|
opts?: {as?: 'menu' | 'switch'} & PropTypeConfigOpts,
|
||||||
): PropTypeConfig_StringLiteral<Extract<keyof Opts, string>> {
|
): PropTypeConfig_StringLiteral<Extract<keyof Opts, string>> {
|
||||||
return {
|
return {
|
||||||
type: 'stringLiteral',
|
type: 'stringLiteral',
|
||||||
|
@ -130,24 +318,11 @@ export function stringLiteral<Opts extends {[key in string]: string}>(
|
||||||
options: {...options},
|
options: {...options},
|
||||||
[propTypeSymbol]: 'TheatrePropType',
|
[propTypeSymbol]: 'TheatrePropType',
|
||||||
valueType: null as $IntentionalAny,
|
valueType: null as $IntentionalAny,
|
||||||
as: extras?.as ?? 'menu',
|
as: opts?.as ?? 'menu',
|
||||||
label: extras?.label,
|
label: opts?.label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export const rgba = (
|
|
||||||
// defaultValue: {r: number; b: number; g: number; a: number},
|
|
||||||
// extras?: PropTypeConfigExtras,
|
|
||||||
// ): PropTypeConfig_CSSRGBA => {
|
|
||||||
// return {
|
|
||||||
// type: 'cssrgba',
|
|
||||||
// valueType: null as $IntentionalAny,
|
|
||||||
// [s]: 'TheatrePropType',
|
|
||||||
// label: extras?.label,
|
|
||||||
// default: defaultValue,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
interface IBasePropType<ValueType> {
|
interface IBasePropType<ValueType> {
|
||||||
valueType: ValueType
|
valueType: ValueType
|
||||||
[propTypeSymbol]: 'TheatrePropType'
|
[propTypeSymbol]: 'TheatrePropType'
|
||||||
|
@ -190,7 +365,7 @@ export interface PropTypeConfig_Boolean extends IBasePropType<boolean> {
|
||||||
default: boolean
|
default: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropTypeConfigExtras {
|
export interface PropTypeConfigOpts {
|
||||||
label?: string
|
label?: string
|
||||||
}
|
}
|
||||||
export interface PropTypeConfig_String extends IBasePropType<string> {
|
export interface PropTypeConfig_String extends IBasePropType<string> {
|
||||||
|
@ -206,12 +381,6 @@ export interface PropTypeConfig_StringLiteral<T extends string>
|
||||||
as: 'menu' | 'switch'
|
as: 'menu' | 'switch'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Determine if 'compound' is a clear term for what this is.
|
|
||||||
* I didn't want to use 'object' as it could get confused with
|
|
||||||
* SheetObject.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -221,12 +390,6 @@ export interface PropTypeConfig_Compound<Props extends IValidCompoundProps>
|
||||||
props: Record<string, PropTypeConfig>
|
props: Record<string, PropTypeConfig>
|
||||||
}
|
}
|
||||||
|
|
||||||
// export interface PropTypeConfig_CSSRGBA
|
|
||||||
// extends IBasePropType<{r: number; g: number; b: number; a: number}> {
|
|
||||||
// type: 'cssrgba'
|
|
||||||
// default: {r: number; g: number; b: number; a: number}
|
|
||||||
// }
|
|
||||||
|
|
||||||
export interface PropTypeConfig_Enum extends IBasePropType<{}> {
|
export interface PropTypeConfig_Enum extends IBasePropType<{}> {
|
||||||
type: 'enum'
|
type: 'enum'
|
||||||
cases: Record<string, PropTypeConfig>
|
cases: Record<string, PropTypeConfig>
|
||||||
|
@ -238,7 +401,6 @@ export type PropTypeConfig_AllPrimitives =
|
||||||
| PropTypeConfig_Boolean
|
| PropTypeConfig_Boolean
|
||||||
| PropTypeConfig_String
|
| PropTypeConfig_String
|
||||||
| PropTypeConfig_StringLiteral<$IntentionalAny>
|
| PropTypeConfig_StringLiteral<$IntentionalAny>
|
||||||
// | PropTypeConfig_CSSRGBA
|
|
||||||
|
|
||||||
export type PropTypeConfig =
|
export type PropTypeConfig =
|
||||||
| PropTypeConfig_AllPrimitives
|
| PropTypeConfig_AllPrimitives
|
||||||
|
|
|
@ -28,6 +28,32 @@ export interface ISequence {
|
||||||
* Starts playback of a sequence.
|
* Starts playback of a sequence.
|
||||||
* Returns a promise that either resolves to true when the playback completes,
|
* Returns a promise that either resolves to true when the playback completes,
|
||||||
* or resolves to false if playback gets interrupted (for example by calling sequence.pause())
|
* or resolves to false if playback gets interrupted (for example by calling sequence.pause())
|
||||||
|
*
|
||||||
|
* @returns A promise that resolves when the playback is finished, or rejects if interruped
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // plays the sequence from the current position to sequence.length
|
||||||
|
* sheet.sequence.play()
|
||||||
|
*
|
||||||
|
* // plays the sequence at 2.4x speed
|
||||||
|
* sheet.sequence.play({rate: 2.4})
|
||||||
|
*
|
||||||
|
* // plays the sequence from second 1 to 4
|
||||||
|
* sheet.sequence.play({range: [1, 4]})
|
||||||
|
*
|
||||||
|
* // plays the sequence 4 times
|
||||||
|
* sheet.sequence.play({iterationCount: 4})
|
||||||
|
*
|
||||||
|
* // plays the sequence in reverse
|
||||||
|
* sheet.sequence.play({direction: 'reverse'})
|
||||||
|
*
|
||||||
|
* // plays the sequence back and forth forever (until interrupted)
|
||||||
|
* sheet.sequence.play({iterationCount: Infinity, direction: 'alternateReverse})
|
||||||
|
*
|
||||||
|
* // plays the sequence and logs "done" once playback is finished
|
||||||
|
* sheet.sequence.play().then(() => console.log('done'))
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
play(conf?: {
|
play(conf?: {
|
||||||
/**
|
/**
|
||||||
|
@ -57,13 +83,29 @@ export interface ISequence {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current position of the playhead.
|
* The current position of the playhead.
|
||||||
* In a time-based sequence, this represents the current time.
|
* In a time-based sequence, this represents the current time in seconds.
|
||||||
*/
|
*/
|
||||||
position: number
|
position: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Attaches an audio source to the sequence. Playing the sequence automatically
|
||||||
|
* plays the audio source and their times are kept in sync.
|
||||||
*
|
*
|
||||||
* @param args
|
* @returns A promise that resolves once the audio source is loaded and decoded
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Loads and decodes audio from the URL and then attaches it to the sequence
|
||||||
|
* await sheet.sequence.attachAudio({source: "https://localhost/audio.ogg"})
|
||||||
|
* sheet.sequence.play()
|
||||||
|
*
|
||||||
|
* // Providing your own AudioAPI Context, destination, etc
|
||||||
|
* const audioContext: AudioContext = {...} // create an AudioContext using the Audio API
|
||||||
|
* const audioBuffer: AudioBuffer = {...} // create an AudioBuffer
|
||||||
|
* const destinationNode = audioContext.destination
|
||||||
|
*
|
||||||
|
* await sheet.sequence.attachAudio({source: audioBuffer, audioContext, destinationNode})
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
attachAudio(args: IAttachAudioArgs): Promise<void>
|
attachAudio(args: IAttachAudioArgs): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,20 +18,82 @@ import type {
|
||||||
} from '@theatre/core/propTypes/internals'
|
} from '@theatre/core/propTypes/internals'
|
||||||
|
|
||||||
export interface ISheetObject<Props extends IShorthandCompoundProps = {}> {
|
export interface ISheetObject<Props extends IShorthandCompoundProps = {}> {
|
||||||
|
/**
|
||||||
|
* All Objects will have `object.type === 'Theatre_SheetObject_PublicAPI'`
|
||||||
|
*/
|
||||||
readonly type: 'Theatre_SheetObject_PublicAPI'
|
readonly type: 'Theatre_SheetObject_PublicAPI'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The current values of the props.
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const obj = sheet.object("obj", {x: 0})
|
||||||
|
* console.log(obj.value.x) // prints 0 or the current numeric value
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
readonly value: ShorthandPropToLonghandProp<Props>['valueType']
|
readonly value: ShorthandPropToLonghandProp<Props>['valueType']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Pointer to the props of the object.
|
||||||
|
*
|
||||||
|
* More documentation soon.
|
||||||
|
*/
|
||||||
readonly props: Pointer<this['value']>
|
readonly props: Pointer<this['value']>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The instance of Sheet the Object belongs to
|
||||||
|
*/
|
||||||
readonly sheet: ISheet
|
readonly sheet: ISheet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Project the project belongs to
|
||||||
|
*/
|
||||||
readonly project: IProject
|
readonly project: IProject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object representing the address of the Object
|
||||||
|
*/
|
||||||
readonly address: SheetObjectAddress
|
readonly address: SheetObjectAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls `fn` every time the value of the props change.
|
||||||
|
*
|
||||||
|
* @returns an Unsubscribe function
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const obj = sheet.object("Box", {position: {x: 0, y: 0}})
|
||||||
|
* const div = document.getElementById("box")
|
||||||
|
*
|
||||||
|
* const unsubscribe = obj.onValuesChange((newValues) => {
|
||||||
|
* div.style.left = newValues.position.x + 'px'
|
||||||
|
* div.style.top = newValues.position.y + 'px'
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // you can call unsubscribe() to stop listening to changes
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
onValuesChange(fn: (values: this['value']) => void): VoidFn
|
onValuesChange(fn: (values: this['value']) => void): VoidFn
|
||||||
// prettier-ignore
|
|
||||||
|
/**
|
||||||
|
* Sets the initial value of the object. This value overrides the default
|
||||||
|
* values defined in the prop types, but would itself be overridden if the user
|
||||||
|
* overrides it in the UI with a static or animated value.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const obj = sheet.object("obj", {position: {x: 0, y: 0}})
|
||||||
|
*
|
||||||
|
* obj.value // {position: {x: 0, y: 0}}
|
||||||
|
*
|
||||||
|
* // here, we only override position.x
|
||||||
|
* obj.initialValue = {position: {x: 2}}
|
||||||
|
*
|
||||||
|
* obj.value // {position: {x: 2, y: 0}}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
set initialValue(value: DeepPartialOfSerializableValue<this['value']>)
|
set initialValue(value: DeepPartialOfSerializableValue<this['value']>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,55 @@ export type SheetObjectConfig<
|
||||||
> = Props
|
> = Props
|
||||||
|
|
||||||
export interface ISheet {
|
export interface ISheet {
|
||||||
|
/**
|
||||||
|
* All sheets have `sheet.type === 'Theatre_Sheet_PublicAPI'`
|
||||||
|
*/
|
||||||
readonly type: 'Theatre_Sheet_PublicAPI'
|
readonly type: 'Theatre_Sheet_PublicAPI'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Project this Sheet belongs to
|
||||||
|
*/
|
||||||
readonly project: IProject
|
readonly project: IProject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address of the Sheet
|
||||||
|
*/
|
||||||
readonly address: SheetAddress
|
readonly address: SheetAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a child object for the sheet
|
||||||
|
*
|
||||||
|
* **Docs: https://docs.theatrejs.com/in-depth/#objects**
|
||||||
|
*
|
||||||
|
* @param key Each object is identified by a key, which is a non-empty string
|
||||||
|
* @param props The props of the object. See examples
|
||||||
|
*
|
||||||
|
* @returns An Object
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Create an object named "a unique key" with no props
|
||||||
|
* const obj = sheet.object("a unique key", {})
|
||||||
|
* obj.address.objectKey // "a unique key"
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* // Create an object with {x: 0}
|
||||||
|
* const obj = sheet.object("obj", {x: 0})
|
||||||
|
* obj.value.x // returns 0 or the current number that the user has set
|
||||||
|
*
|
||||||
|
* // Create an object with nested props
|
||||||
|
* const obj = sheet.object("obj", {position: {x: 0, y: 0}})
|
||||||
|
* obj.value.position // {x: 0, y: 0}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
object<Props extends IShorthandCompoundProps>(
|
object<Props extends IShorthandCompoundProps>(
|
||||||
key: string,
|
key: string,
|
||||||
config: Props,
|
props: Props,
|
||||||
): ISheetObject<Props>
|
): ISheetObject<Props>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sequence of this Sheet
|
||||||
|
*/
|
||||||
readonly sequence: ISequence
|
readonly sequence: ISequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,32 @@ import type {
|
||||||
SerializableMap,
|
SerializableMap,
|
||||||
SerializableValue,
|
SerializableValue,
|
||||||
} from '@theatre/shared/utils/types'
|
} from '@theatre/shared/utils/types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the address to a project
|
||||||
|
*/
|
||||||
export interface ProjectAddress {
|
export interface ProjectAddress {
|
||||||
projectId: string
|
projectId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the address to a specific instance of a Sheet
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const sheet = project.sheet('a sheet', 'some instance id')
|
||||||
|
* sheet.address.sheetId === 'a sheet'
|
||||||
|
* sheet.address.sheetInstanceId === 'sheetInstanceId'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export interface SheetAddress extends ProjectAddress {
|
export interface SheetAddress extends ProjectAddress {
|
||||||
sheetId: string
|
sheetId: string
|
||||||
sheetInstanceId: string
|
sheetInstanceId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `sheetInstanceId` from an address, making it refer to
|
||||||
|
* all instances of a certain `sheetId`
|
||||||
|
*/
|
||||||
export type WithoutSheetInstance<T extends SheetAddress> = Omit<
|
export type WithoutSheetInstance<T extends SheetAddress> = Omit<
|
||||||
T,
|
T,
|
||||||
'sheetInstanceId'
|
'sheetInstanceId'
|
||||||
|
@ -20,7 +37,18 @@ export type WithoutSheetInstance<T extends SheetAddress> = Omit<
|
||||||
export type SheetInstanceOptional<T extends SheetAddress> =
|
export type SheetInstanceOptional<T extends SheetAddress> =
|
||||||
WithoutSheetInstance<T> & {sheetInstanceId?: string | undefined}
|
WithoutSheetInstance<T> & {sheetInstanceId?: string | undefined}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the address to a Sheet's Object
|
||||||
|
*/
|
||||||
export interface SheetObjectAddress extends SheetAddress {
|
export interface SheetObjectAddress extends SheetAddress {
|
||||||
|
/**
|
||||||
|
* The key of the object.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const obj = sheet.object('foo', {})
|
||||||
|
* obj.address.objectKey === 'foo'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
objectKey: string
|
objectKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +62,9 @@ export const encodePathToProp = (p: PathToProp): PathToProp_Encoded =>
|
||||||
export const decodePathToProp = (s: PathToProp_Encoded): PathToProp =>
|
export const decodePathToProp = (s: PathToProp_Encoded): PathToProp =>
|
||||||
JSON.parse(s)
|
JSON.parse(s)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the path to a certain prop of an object
|
||||||
|
*/
|
||||||
export interface PropAddress extends SheetObjectAddress {
|
export interface PropAddress extends SheetObjectAddress {
|
||||||
pathToProp: PathToProp
|
pathToProp: PathToProp
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,38 +110,38 @@ const Connector: React.FC<IProps> = (props) => {
|
||||||
const modifiedS = orig // window.prompt('As cubic-bezier()', orig)
|
const modifiedS = orig // window.prompt('As cubic-bezier()', orig)
|
||||||
if (modifiedS && modifiedS !== orig) {
|
if (modifiedS && modifiedS !== orig) {
|
||||||
return
|
return
|
||||||
const modified = JSON.parse(modifiedS)
|
// const modified = JSON.parse(modifiedS)
|
||||||
getStudio()!.transaction(({stateEditors}) => {
|
// getStudio()!.transaction(({stateEditors}) => {
|
||||||
const {replaceKeyframes} =
|
// const {replaceKeyframes} =
|
||||||
stateEditors.coreByProject.historic.sheetsById.sequence
|
// stateEditors.coreByProject.historic.sheetsById.sequence
|
||||||
|
|
||||||
replaceKeyframes({
|
// replaceKeyframes({
|
||||||
...props.leaf.sheetObject.address,
|
// ...props.leaf.sheetObject.address,
|
||||||
snappingFunction: val(props.layoutP.sheet).getSequence()
|
// snappingFunction: val(props.layoutP.sheet).getSequence()
|
||||||
.closestGridPosition,
|
// .closestGridPosition,
|
||||||
trackId: props.leaf.trackId,
|
// trackId: props.leaf.trackId,
|
||||||
keyframes: [
|
// keyframes: [
|
||||||
{
|
// {
|
||||||
...cur,
|
// ...cur,
|
||||||
handles: [
|
// handles: [
|
||||||
cur.handles[0],
|
// cur.handles[0],
|
||||||
cur.handles[1],
|
// cur.handles[1],
|
||||||
modified[0],
|
// modified[0],
|
||||||
modified[1],
|
// modified[1],
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
...next,
|
// ...next,
|
||||||
handles: [
|
// handles: [
|
||||||
modified[2],
|
// modified[2],
|
||||||
modified[3],
|
// modified[3],
|
||||||
next.handles[2],
|
// next.handles[2],
|
||||||
next.handles[3],
|
// next.handles[3],
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
|
Loading…
Reference in a new issue