More progress with docs

This commit is contained in:
Aria Minaei 2021-09-05 13:40:15 +02:00
parent 5d63ce4f3e
commit e201eeee5b
7 changed files with 335 additions and 129 deletions

33
devEnv/api-docs.mjs Normal file
View file

@ -0,0 +1,33 @@
;(async function () {
// better quote function from https://github.com/google/zx/pull/167
$.quote = function quote(arg) {
return arg
if (/^[a-z0-9/_.-]+$/i.test(arg)) {
return arg
}
return (
`$'` +
arg
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/\f/g, '\\f')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t')
.replace(/\v/g, '\\v')
.replace(/\0/g, '\\0') +
`'`
)
}
const watch = argv.watch === true
await Promise.all(
['core', 'studio'].map(
(which) =>
$`typedoc ${
watch ? '--watch ' : ''
} --out docs/api/${which} --name "@theatre/${which}" --tsconfig theatre/tsconfig.json --excludeInternal --sort source-order --readme none --hideBreadcrumbs true --categorizeByGroup false --defaultCategory "Main APIs" --hideInPageTOC true theatre/${which}/src/index.ts`,
),
)
})()

View file

@ -56,6 +56,7 @@ module.exports = {
], ],
}, },
], ],
sidebar: [ sidebar: [
{ {
title: 'Guide', title: 'Guide',
@ -64,8 +65,28 @@ module.exports = {
{ {
title: 'API', title: 'API',
path: '/api', path: '/api',
// sidebarDepth: 2, sidebarDepth: 2,
children: ['/api/core/', '/api/studio/'], children: [
{
title: '@theatre/core',
path: '/api/core/',
children: [
{
title: 'Main exports',
path: '/api/core/',
},
{
title: 'types',
path: '/api/core/modules/types',
},
],
},
{
title: '@theatre/studio',
path: '/api/studio/',
},
],
}, },
{ {
title: 'Support', title: 'Support',

View file

@ -14,6 +14,7 @@
"postinstall": "husky install", "postinstall": "husky install",
"deploy": "zx devEnv/deploy.mjs", "deploy": "zx devEnv/deploy.mjs",
"lint:all": "eslint . --ext ts,tsx --ignore-path=.gitignore --rulesdir ./devEnv/eslint/rules", "lint:all": "eslint . --ext ts,tsx --ignore-path=.gitignore --rulesdir ./devEnv/eslint/rules",
"docs:api": "zx devEnv/api-docs.mjs",
"docs:dev": "vuepress dev docs", "docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs" "docs:build": "vuepress build docs"
}, },

View file

@ -1,14 +1,178 @@
/**
* Usage:
* ```ts
* import {types as t} from '@theatre/core'
*
* const props = t.compound({
* x: t.number(0),
* y: t.number(0)
* })
*
*
* const obj = sheet.obj("An object", props)
* ```
* @module types
*/
import type {$IntentionalAny} from '@theatre/shared/utils/types' import type {$IntentionalAny} from '@theatre/shared/utils/types'
const s = Symbol('TheatrePropType_Basic') const s = Symbol('TheatrePropType_Basic')
type S = typeof s
/**
* Creates a compound prop type (basically a JS object).
* Usage:
* ```ts
* // the root prop type of an object is always a compound
* const props = t.compound({
* // compounds can be nested
* position: t.compound({
* x: t.number(0),
* y: t.number(0)
* })
* })
*
* const obj = sheet.obj('key', props)
* console.log(obj.value) // {position: {x: 10.3, y: -1}}
* ```
* @param props
* @param extras
* @returns
*
* @category Prop type definitions
*/
export const compound = <Props extends IValidCompoundProps>(
props: Props,
extras?: PropTypeConfigExtras,
): PropTypeConfig_Compound<Props> => {
return {
type: 'compound',
props,
valueType: null as $IntentionalAny,
[s]: 'TheatrePropType',
label: extras?.label,
}
}
/**
*
* @param defaultValue
* @param opts
* @returns
*
* @category Prop type definitions
*/
export const number = (
defaultValue: number,
opts?: {
nudgeFn?: PropTypeConfig_Number['nudgeFn']
range?: PropTypeConfig_Number['range']
nudgeMultiplier?: number
} & PropTypeConfigExtras,
): PropTypeConfig_Number => {
return {
type: 'number',
valueType: 0,
default: defaultValue,
[s]: 'TheatrePropType',
...(opts ? opts : {}),
label: opts?.label,
nudgeFn: opts?.nudgeFn ?? defaultNumberNudgeFn,
nudgeMultiplier:
typeof opts?.nudgeMultiplier === 'number' ? opts.nudgeMultiplier : 1,
}
}
/**
*
* @param defaultValue
* @param extras
* @returns
*
* @category Prop type definitions
*/
export const boolean = (
defaultValue: boolean,
extras?: PropTypeConfigExtras,
): PropTypeConfig_Boolean => {
return {
type: 'boolean',
default: defaultValue,
valueType: null as $IntentionalAny,
[s]: 'TheatrePropType',
label: extras?.label,
}
}
/**
*
* @param defaultValue
* @param extras
* @returns
*
* @category Prop type definitions
*/
export const string = (
defaultValue: string,
extras: PropTypeConfigExtras,
): PropTypeConfig_String => {
return {
type: 'string',
default: defaultValue,
valueType: null as $IntentionalAny,
[s]: 'TheatrePropType',
label: extras.label,
}
}
/**
*
* @param defaultValue
* @param options
* @param extras
* @returns
*
* @category Prop type definitions
*/
export function stringLiteral<Opts extends {[key in string]: string}>(
defaultValue: Extract<keyof Opts, string>,
options: Opts,
extras?: {as?: 'menu' | 'switch'} & PropTypeConfigExtras,
): PropTypeConfig_StringLiteral<Extract<keyof Opts, string>> {
return {
type: 'stringLiteral',
default: defaultValue,
options: {...options},
[s]: 'TheatrePropType',
valueType: null as $IntentionalAny,
as: extras?.as ?? 'menu',
label: extras?.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
/**
* @internal
*/
[s]: 'TheatrePropType' [s]: 'TheatrePropType'
label: string | undefined label: string | undefined
} }
/**
* @internal
*/
export interface PropTypeConfig_Number extends IBasePropType<number> { export interface PropTypeConfig_Number extends IBasePropType<number> {
type: 'number' type: 'number'
default: number default: number
@ -16,7 +180,9 @@ export interface PropTypeConfig_Number extends IBasePropType<number> {
nudgeFn: NumberNudgeFn nudgeFn: NumberNudgeFn
nudgeMultiplier: number nudgeMultiplier: number
} }
/**
* @internal
*/
export type NumberNudgeFn = (p: { export type NumberNudgeFn = (p: {
deltaX: number deltaX: number
deltaFraction: number deltaFraction: number
@ -39,68 +205,29 @@ const defaultNumberNudgeFn: NumberNudgeFn = ({
return deltaX * magnitude * config.nudgeMultiplier return deltaX * magnitude * config.nudgeMultiplier
} }
/**
export const number = ( * @internal
defaultValue: number, */
opts?: {
nudgeFn?: PropTypeConfig_Number['nudgeFn']
range?: PropTypeConfig_Number['range']
nudgeMultiplier?: number
} & PropTypeConfigExtras,
): PropTypeConfig_Number => {
return {
type: 'number',
valueType: 0,
default: defaultValue,
[s]: 'TheatrePropType',
...(opts ? opts : {}),
label: opts?.label,
nudgeFn: opts?.nudgeFn ?? defaultNumberNudgeFn,
nudgeMultiplier:
typeof opts?.nudgeMultiplier === 'number' ? opts.nudgeMultiplier : 1,
}
}
export interface PropTypeConfig_Boolean extends IBasePropType<boolean> { export interface PropTypeConfig_Boolean extends IBasePropType<boolean> {
type: 'boolean' type: 'boolean'
default: boolean default: boolean
} }
/**
export type PropTypeConfigExtras = { * @internal
*/
export interface PropTypeConfigExtras {
label?: string label?: string
} }
/**
export const boolean = ( * @internal
defaultValue: boolean, */ export interface PropTypeConfig_String extends IBasePropType<string> {
extras?: PropTypeConfigExtras,
): PropTypeConfig_Boolean => {
return {
type: 'boolean',
default: defaultValue,
valueType: null as $IntentionalAny,
[s]: 'TheatrePropType',
label: extras?.label,
}
}
export interface PropTypeConfig_String extends IBasePropType<string> {
type: 'string' type: 'string'
default: string default: string
} }
export const string = ( /**
defaultValue: string, * @internal
extras: PropTypeConfigExtras, */
): PropTypeConfig_String => {
return {
type: 'string',
default: defaultValue,
valueType: null as $IntentionalAny,
[s]: 'TheatrePropType',
label: extras.label,
}
}
export interface PropTypeConfig_StringLiteral<T extends string> export interface PropTypeConfig_StringLiteral<T extends string>
extends IBasePropType<T> { extends IBasePropType<T> {
type: 'stringLiteral' type: 'stringLiteral'
@ -109,22 +236,6 @@ export interface PropTypeConfig_StringLiteral<T extends string>
as: 'menu' | 'switch' as: 'menu' | 'switch'
} }
export function stringLiteral<Opts extends {[key in string]: string}>(
defaultValue: Extract<keyof Opts, string>,
options: Opts,
extras?: {as?: 'menu' | 'switch'} & PropTypeConfigExtras,
): PropTypeConfig_StringLiteral<Extract<keyof Opts, string>> {
return {
type: 'stringLiteral',
default: defaultValue,
options: {...options},
[s]: 'TheatrePropType',
valueType: null as $IntentionalAny,
as: extras?.as ?? 'menu',
label: extras?.label,
}
}
type IValidCompoundProps = { type IValidCompoundProps = {
[K in string]: PropTypeConfig [K in string]: PropTypeConfig
} }
@ -133,6 +244,8 @@ type IValidCompoundProps = {
* @todo Determine if 'compound' is a clear term for what this is. * @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 * I didn't want to use 'object' as it could get confused with
* SheetObject. * SheetObject.
*
* @internal
*/ */
export interface PropTypeConfig_Compound<Props extends IValidCompoundProps> export interface PropTypeConfig_Compound<Props extends IValidCompoundProps>
extends IBasePropType<{[K in keyof Props]: Props[K]['valueType']}> { extends IBasePropType<{[K in keyof Props]: Props[K]['valueType']}> {
@ -140,51 +253,31 @@ export interface PropTypeConfig_Compound<Props extends IValidCompoundProps>
props: Record<string, PropTypeConfig> props: Record<string, PropTypeConfig>
} }
export const compound = <Props extends IValidCompoundProps>( // export interface PropTypeConfig_CSSRGBA
props: Props, // extends IBasePropType<{r: number; g: number; b: number; a: number}> {
extras?: PropTypeConfigExtras, // type: 'cssrgba'
): PropTypeConfig_Compound<Props> => { // default: {r: number; g: number; b: number; a: number}
return { // }
type: 'compound', /**
props, * @internal
valueType: null as $IntentionalAny, */
[s]: 'TheatrePropType',
label: extras?.label,
}
}
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 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,
}
}
export interface PropTypeConfig_Enum extends IBasePropType<{}> { export interface PropTypeConfig_Enum extends IBasePropType<{}> {
type: 'enum' type: 'enum'
cases: Record<string, PropTypeConfig> cases: Record<string, PropTypeConfig>
defaultCase: string defaultCase: string
} }
/**
* @category Prop type definitions
*/
export type PropTypeConfig_AllPrimitives = export type PropTypeConfig_AllPrimitives =
| PropTypeConfig_Number | PropTypeConfig_Number
| PropTypeConfig_Boolean | PropTypeConfig_Boolean
| PropTypeConfig_String | PropTypeConfig_String
| PropTypeConfig_StringLiteral<$IntentionalAny> | PropTypeConfig_StringLiteral<$IntentionalAny>
| PropTypeConfig_CSSRGBA // | PropTypeConfig_CSSRGBA
/**
* @internal
*/
export type PropTypeConfig = export type PropTypeConfig =
| PropTypeConfig_AllPrimitives | PropTypeConfig_AllPrimitives
| PropTypeConfig_Compound<$IntentionalAny> | PropTypeConfig_Compound<$IntentionalAny>

View file

@ -23,7 +23,9 @@ export interface ITransactionAPI {
set<V>(pointer: Pointer<V>, value: V): void set<V>(pointer: Pointer<V>, value: V): void
unset<V>(pointer: Pointer<V>): void unset<V>(pointer: Pointer<V>): void
} }
/**
*
*/
export interface PaneClassDefinition< export interface PaneClassDefinition<
DataType extends PropTypeConfig_Compound<{}>, DataType extends PropTypeConfig_Compound<{}>,
> { > {
@ -34,11 +36,28 @@ export interface PaneClassDefinition<
}> }>
} }
export type IExtension = { /**
* A Theatre.js Studio extension. You can define one either
* in a separate package, or within your project.
*/
export interface IExtension {
/**
* Pick a unique ID for your extension. Ideally the name would be unique if
* the extension was to be published to the npm repository.
*/
id: string id: string
/**
* Set this if you'd like to add a component to the global toolbar (on the top)
*/
globalToolbar?: { globalToolbar?: {
/**
* A basic react component.
*/
component: React.ComponentType<{}> component: React.ComponentType<{}>
} }
/**
* Introduces new pane types.
*/
panes?: Array<PaneClassDefinition<$FixMe>> panes?: Array<PaneClassDefinition<$FixMe>>
} }
@ -47,7 +66,25 @@ export type PaneInstance<ClassName extends string> = {
instanceId: string instanceId: string
definition: PaneClassDefinition<$FixMe> definition: PaneClassDefinition<$FixMe>
} }
/**
* This is the public api of Theatre's studio. It is exposed through:
*
* Basic usage:
* ```ts
* import studio from '@theatre/studio'
*
* studio.initialize()
* ```
*
* Usage with **tree-shaking**:
* ```ts
* import studio from '@theatre/studio'
*
* if (process.env.NODE_ENV !== 'production') {
* studio.initialize()
* }
* ```
*/
export interface IStudio { export interface IStudio {
readonly ui: { readonly ui: {
/** /**
@ -65,17 +102,8 @@ export interface IStudio {
} }
/** /**
* Initializes the studio. Call this in your index.js/index.ts module. * Initializes the studio. Call it once in your index.js/index.ts module.
* * It silently ignores subsequent calls.
* Usage with **tree-shaking**:
* ```ts
* import studio from '@theratre/studio'
*
* // Add this check if you wish to not include the studio in your production bundle
* if (process.env.NODE_ENV === "development") {
* studio.initialize()
* }
* ```
*/ */
initialize(): void initialize(): void
@ -105,10 +133,23 @@ export interface IStudio {
/** /**
* The current selection, consisting of Sheets and Sheet Objects * The current selection, consisting of Sheets and Sheet Objects
*
* Example:
* ```ts
* console.log(studio.selection) // => [ISheetObject, ISheet]
* ```
*/ */
readonly selection: Array<ISheetObject | ISheet> readonly selection: Array<ISheetObject | ISheet>
extend(extension: IExtension): void /**
* Registers an extension
*/
extend(
/**
* The extension's definition
*/
extension: IExtension,
): void
getPanesOfType<PaneClass extends string>( getPanesOfType<PaneClass extends string>(
paneClass: PaneClass, paneClass: PaneClass,
@ -118,6 +159,12 @@ export interface IStudio {
paneClass: PaneClass, paneClass: PaneClass,
): PaneInstance<PaneClass> ): PaneInstance<PaneClass>
/**
* Returns the Theatre.js project that contains the studio's sheets and objects.
*
* It is useful if you'd like to have sheets/objects that are present only when
* studio is present.
*/
getStudioProject(): IProject getStudioProject(): IProject
} }

View file

@ -1,18 +1,23 @@
/**
* @module @theatre/studio
*/
import {setStudio} from '@theatre/studio/getStudio' import {setStudio} from '@theatre/studio/getStudio'
import {Studio} from '@theatre/studio/Studio' import {Studio} from '@theatre/studio/Studio'
export type {IScrub} from '@theatre/studio/Scrub'
export type {IStudio} from '@theatre/studio/TheatreStudio'
import * as globalVariableNames from '@theatre/shared/globalVariableNames' import * as globalVariableNames from '@theatre/shared/globalVariableNames'
import type {$FixMe} from '@theatre/shared/utils/types' import type {$FixMe} from '@theatre/shared/utils/types'
import StudioBundle from './StudioBundle' import StudioBundle from './StudioBundle'
import type CoreBundle from '@theatre/core/CoreBundle' import type CoreBundle from '@theatre/core/CoreBundle'
export {default as ToolbarSwitchSelect} from './uiComponents/toolbar/ToolbarSwitchSelect' import type {IStudio} from '@theatre/studio/TheatreStudio'
export {default as ToolbarIconButton} from './uiComponents/toolbar/ToolbarIconButton'
export {default as ToolbarDropdownSelect} from './uiComponents/toolbar/ToolbarDropdownSelect'
const studioPrivateAPI = new Studio() const studioPrivateAPI = new Studio()
setStudio(studioPrivateAPI) setStudio(studioPrivateAPI)
export const studio = studioPrivateAPI.publicApi
/**
* The main instance of Studio. Read more at {@link IStudio}
*/
const studio: IStudio = studioPrivateAPI.publicApi
export default studio export default studio
registerStudioBundle() registerStudioBundle()
@ -60,3 +65,9 @@ function registerStudioBundle() {
studioBundle.registerCoreBundle(possibleCoreBundle) studioBundle.registerCoreBundle(possibleCoreBundle)
} }
} }
export {default as ToolbarSwitchSelect} from './uiComponents/toolbar/ToolbarSwitchSelect'
export {default as ToolbarIconButton} from './uiComponents/toolbar/ToolbarIconButton'
export {default as ToolbarDropdownSelect} from './uiComponents/toolbar/ToolbarDropdownSelect'
export type {IScrub} from '@theatre/studio/Scrub'
export type {IStudio, IExtension} from '@theatre/studio/TheatreStudio'

View file

@ -68,7 +68,7 @@ const propEditorByPropType: {
enum: () => <></>, enum: () => <></>,
boolean: BooleanPropEditor, boolean: BooleanPropEditor,
stringLiteral: StringLiteralPropEditor, stringLiteral: StringLiteralPropEditor,
cssrgba: () => <></>, // cssrgba: () => <></>,
} }
const DeterminePropEditor: React.FC<{ const DeterminePropEditor: React.FC<{