diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1569eff81..3f4ad162c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,6 +56,14 @@ React 16.8+ has global state to support its "hooks" feature, so you need to ensu # Publishing -Run `yarn bump` to analyze commits and increment the version of any updated packages. +To publish a new version: -Run `yarn release` to publish any packages with a new version. +``` +yarn release +``` + +To publish a **canary** version: + +``` +yarn release --canary +``` diff --git a/lerna.json b/lerna.json index 284d9e451..e0d70194f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "9.0.0-beta.34", + "version": "9.0.0-canary.809.5.f01ecc2", "npmClient": "yarn", "useWorkspaces": true, "registry": "https://registry.npmjs.org", @@ -17,10 +17,8 @@ "push": false }, "publish": { - "bump": "from-package", "contents": "dist", - "ignoreScripts": true, - "preDistTag": "next" + "ignoreScripts": true } } } diff --git a/package.json b/package.json index 470b12c56..fa154577e 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,9 @@ }, "scripts": { "build": "bic", - "bump": "lerna version && yarn --force", "clean": "lerna exec --parallel --no-bail -- rimraf node_modules dist .rpt2_cache .bic_cache", - "prepare": "node ./scripts/prepare.js && bic", - "release": "lerna publish", + "prepare": "node ./scripts/prepare.js && bic && yarn test:ts", + "release": "node ./scripts/release.js", "test": "jest", "test:cov": "jest --coverage", "test:ts": "cd packages/react-spring && tsc -p . --noEmit" @@ -66,6 +65,8 @@ "@types/react": "^16.8.19", "build-if-changed": "^1.5.0", "chalk": "^2.4.2", + "enquirer": "^2.3.2", + "execa": "^2.0.4", "fs-extra": "7.0.1", "husky": "1.3.1", "jest": "^24.8.0", @@ -84,6 +85,7 @@ "rollup-plugin-node-resolve": "4.0.0", "rollup-plugin-terser": "5.0.0", "rollup-plugin-typescript2": "0.21.1", + "sade": "^1.6.1", "sort-package-json": "1.22.1", "spec.ts": "1.1.3", "ts-jest": "^24.0.2", diff --git a/packages/addons/package.json b/packages/addons/package.json index b2ba6ffcf..0e4f3846e 100644 --- a/packages/addons/package.json +++ b/packages/addons/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/addons", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "dependencies": { "@react-spring/animated": "link:../animated", diff --git a/packages/addons/src/parallax.tsx b/packages/addons/src/parallax.tsx index 0bb3c06f2..57cf16f14 100644 --- a/packages/addons/src/parallax.tsx +++ b/packages/addons/src/parallax.tsx @@ -5,7 +5,7 @@ import React, { useEffect, CSSProperties, } from 'react' -import { requestAnimationFrame, defaultElement as View } from 'shared/globals' +import { frameLoop, defaultElement as View } from 'shared/globals' import { Controller, SpringConfig, config as configs } from '@react-spring/core' import { withAnimated } from '@react-spring/animated' import { useMemoOne } from 'use-memo-one' @@ -239,7 +239,7 @@ export const Parallax = React.memo( if (!state.busy) { state.busy = true state.current = event.target[getScrollType(horizontal)] - requestAnimationFrame(() => { + frameLoop.onFrame(() => { state.layers.forEach(layer => layer.setPosition(state.space, state.current) ) @@ -254,7 +254,7 @@ export const Parallax = React.memo( const onResize = () => { const update = () => state.update() - requestAnimationFrame(update) + frameLoop.onFrame(update) setTimeout(update, 150) // Some browsers don't fire on maximize! } diff --git a/packages/animated/package.json b/packages/animated/package.json index 1b834bdde..ffa9b5c67 100644 --- a/packages/animated/package.json +++ b/packages/animated/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/animated", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "description": "Animated component props for React", "main": "src/index.ts", "scripts": { diff --git a/packages/core/package.json b/packages/core/package.json index b00d20660..be6597cf5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/core", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "scripts": { "build": "rollup -c", diff --git a/packages/core/src/helpers.ts b/packages/core/src/helpers.ts index 26658a24f..733a49d2f 100644 --- a/packages/core/src/helpers.ts +++ b/packages/core/src/helpers.ts @@ -109,88 +109,6 @@ export function interpolateTo(props: T): InterpolateTo { return out } -type ItemKey = number | string - -interface Item { - key: ItemKey - originalKey: ItemKey - phase: string - item: any - props: object - destroyed?: boolean -} - -interface DeletedItem extends Item { - left?: ItemKey - right?: ItemKey -} - -/** - * This tries to put deleted items back into the given `out` list in correct - * order. Deleted items must have a `left` and `right` property with key of - * their sibling which is used to find the correct placement. - */ -export function reconcileDeleted( - deleted: DeletedItem[], - current: Item[] -): any[] { - // Copy as we will be mutating the arrays - deleted = [...deleted] - current = [...current] - - // Used to detect deadlock (when a pass finds 0 siblings) - let failedTries = 0 - - // Track where the current pass start/ends - let passIndex = 0 - let nextPassIndex = deleted.length - - // Insert all deleted items into `current` - for (let i = 0; i < deleted.length; i++) { - if (i === nextPassIndex) { - // Sanity test: Push to end if somehow no siblings were found - if (passIndex + failedTries === nextPassIndex) { - for (let j = i; j < deleted.length; j++) { - const { left, right, ...deletedItem } = deleted[j] - current.push(deletedItem) - } - break - } - // Update local state at the end of each pass - passIndex = nextPassIndex - nextPassIndex = deleted.length - failedTries = 0 - } - - // The index of the deleted item in `current` - let index = -1 - - // Look for the left or right sibling in `current` - const { left, right, ...deletedItem } = deleted[i] - for (let j = current.length; --j >= 0; ) { - const { originalKey: key } = current[j] - if (key === right) { - index = j - break - } - if (key === left) { - index = j + 1 - break - } - } - - // Items with no index are revisited in the next pass - if (index < 0) { - failedTries++ - deleted.push(deleted[i]) - } else { - current.splice(index, 0, deletedItem) - } - } - - return current -} - export function freeze(obj: T): T { if ( typeof process !== 'undefined' && diff --git a/packages/core/src/legacy.js b/packages/core/src/legacy.js index 2683556cb..586499569 100644 --- a/packages/core/src/legacy.js +++ b/packages/core/src/legacy.js @@ -16,15 +16,6 @@ export function Trail({ items, children, ...props }) { }) } -export function Transition({ items, keys = null, children, ...props }) { - const transitions = useTransition(items, keys, props) - return transitions.map(({ item, key, props, phase }, index) => { - const result = children(item, phase, index) - const element = is.fun(result) ? result(props) : result - return element && element.type ? ( - - ) : ( - element - ) - }) +export function Transition({ items, children, ...props }) { + return useTransition(items, props)(children) } diff --git a/packages/core/src/useTransition.d.ts b/packages/core/src/useTransition.d.ts deleted file mode 100644 index 1b53c459a..000000000 --- a/packages/core/src/useTransition.d.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { Solve, TransitionPhase, UnknownProps } from './types/common' -import { - SpringAsyncFn, - SpringConfig, - SpringUpdate, - SpringValues, -} from './types/spring' - -export type ItemsProp = ReadonlyArray | T | null | undefined -export type ItemKeys = - | ((item: T) => string | number) - | ReadonlyArray - | string - | number - | null - -/** - * Animate a set of values whenever one changes. - * - * The returned array can be safely mutated. - */ -export declare function useTransition< - Item, - Props extends UnknownProps & UseTransitionProps ->( - items: ItemsProp, - keys: ItemKeys, - props: Props -): ItemTransition[] - -/** The transition state of a single item */ -export type ItemTransition = Solve<{ - key: string | number - item: Item - phase: TransitionPhase - props: SpringValues -}> - -/** For props that provide animated keys */ -type TransitionProp = - | SpringUpdate - | readonly SpringUpdate[] - | ((item: Item) => SpringUpdate | SpringAsyncFn) - -export type UseTransitionProps = { - /** - * Base values (from -> enter), or: item => values - * @default {} - */ - from?: TransitionProp - /** - * Values that apply to new elements, or: item => values - * @default {} - */ - enter?: TransitionProp - /** - * Values that apply to leaving elements, or: item => values - * @default {} - */ - leave?: TransitionProp - /** - * Values that apply to elements that are neither entering nor leaving (you - * can use this to update present elements), or: item => values - */ - update?: TransitionProp - /** - * First-render initial values, if present overrides "from" on the first - * render pass. It can be "null" to skip first mounting transition. Otherwise - * it can take an object or a function (item => object) - */ - initial?: TransitionProp | null - /** - * Configure the spring behavior for each item. - */ - config?: SpringConfig | ((item: Item, phase: TransitionPhase) => SpringConfig) - /** - * The same keys you would normally hand over to React in a list. - */ - keys?: - | ((item: Item) => string | number) - | ReadonlyArray - | string - | number - /** - * When this and `unique` are both true, items in the "enter" phase start from - * their values in the "from" prop instead of their current positions. - */ - reset?: boolean - /** - * Milliseconds of delay before animating the next item. - * - * This applies to all transition phases. - */ - trail?: number - /** - * When true, no two items can have the same key. Reuse any items that - * re-enter before they finish leaving. - */ - unique?: boolean - /** - * Called when an animation is about to start - */ - onStart?: (item: Item, phase: TransitionPhase, animation: any) => void - /** - * Called when all animations come to a stand-still - */ - onRest?: ( - item: Item, - phase: TransitionPhase, - restValues: UnknownProps - ) => void - /** - * Called on every frame when animations are active - */ - onFrame?: ( - item: Item, - phase: TransitionPhase, - currentValues: UnknownProps - ) => void - /** - * Called after an object has finished its "leave" transition - */ - onDestroyed?: (item: Item) => void -} diff --git a/packages/core/src/useTransition.js b/packages/core/src/useTransition.js deleted file mode 100644 index cda8f1c3f..000000000 --- a/packages/core/src/useTransition.js +++ /dev/null @@ -1,272 +0,0 @@ -import { useRef, useEffect, useMemo, useImperativeHandle } from 'react' -import { callProp, interpolateTo, reconcileDeleted } from './helpers' -import { is, toArray, useForceUpdate, useOnce } from 'shared' -import { Controller } from './Controller' - -/** API - * const transitions = useTransition(items, itemKeys, { ... }) - * const [transitions, update] = useTransition(items, itemKeys, () => ({ ... })) - */ - -let guid = 0 - -const INITIAL = 'initial' -const ENTER = 'enter' -const UPDATE = 'update' -const LEAVE = 'leave' - -const makeKeys = (items, keys) => - (typeof keys === 'function' ? items.map(keys) : toArray(keys)).map(String) - -const makeConfig = props => { - let { items, keys, ...rest } = props - items = toArray(is.und(items) ? null : items) - return { items, keys: makeKeys(items, keys), ...rest } -} - -export function useTransition(input, keyTransform, props) { - props = makeConfig({ - ...props, - items: input, - keys: keyTransform || (i => i), - }) - const { - lazy = false, - unique = false, - from, - enter, - leave, - update, - onDestroyed, - keys, - items, - onFrame, - onRest, - onStart, - ref, - ...extra - } = props - - const forceUpdate = useForceUpdate() - const mounted = useRef(false) - const state = useRef({ - mounted: false, - first: true, - deleted: [], - current: {}, - transitions: [], - prevProps: {}, - paused: !!ref, - instances: !mounted.current && new Map(), - forceUpdate, - }) - - useImperativeHandle(ref, () => ({ - start: () => - Promise.all( - Array.from(state.current.instances).map( - ([, c]) => new Promise(r => c.start(r)) - ) - ), - stop: finished => - Array.from(state.current.instances).forEach(([, c]) => c.stop(finished)), - get controllers() { - return Array.from(state.current.instances).map(([, c]) => c) - }, - })) - - // Update state - state.current = diffItems(state.current, props) - if (state.current.changed) { - // Update state - state.current.transitions.forEach(transition => { - const { phase, key, item, props } = transition - if (!state.current.instances.has(key)) - state.current.instances.set(key, new Controller()) - - // Avoid calling `onStart` more than once per transition. - let started = false - - // update the map object - const ctrl = state.current.instances.get(key) - const itemProps = { - ...extra, - ...props, - onRest: values => { - if (state.current.mounted) { - if (transition.destroyed) { - // If no ref is given delete destroyed items immediately - if (!ref && !lazy) cleanUp(state, key) - if (onDestroyed) onDestroyed(item) - } - - // A transition comes to rest once all its springs conclude - const curInstances = Array.from(state.current.instances) - const active = curInstances.some(([, c]) => !c.idle) - if (!active && (ref || lazy) && state.current.deleted.length > 0) { - cleanUp(state) - } - if (is.fun(onRest)) { - onRest(item, phase, values) - } - } - }, - onFrame: is.fun(onFrame) && (values => onFrame(item, phase, values)), - onStart: - is.fun(onStart) && - (animation => - started || (started = (onStart(item, phase, animation), true))), - } - - // Update controller - ctrl.update(itemProps) - if (!state.current.paused) ctrl.start() - }) - } - - useOnce(() => { - state.current.mounted = mounted.current = true - return () => { - state.current.mounted = mounted.current = false - Array.from(state.current.instances).map(([, c]) => c.destroy()) - state.current.instances.clear() - } - }) - - return state.current.transitions.map(({ item, phase, key }) => { - return { - item, - key, - phase, - props: { ...state.current.instances.get(key).animated }, - } - }) -} - -function cleanUp({ current: state }, filterKey) { - const { deleted } = state - for (let { key } of deleted) { - const filter = t => t.key !== key - if (is.und(filterKey) || filterKey === key) { - state.instances.delete(key) - state.transitions = state.transitions.filter(filter) - state.deleted = state.deleted.filter(filter) - } - } - state.forceUpdate() -} - -function diffItems({ first, current, deleted, prevProps, ...state }, props) { - let { - items, - keys, - initial, - from, - enter, - leave, - update, - trail = 0, - unique, - config, - order = [ENTER, LEAVE, UPDATE], - } = props - let { keys: _keys, items: _items } = makeConfig(prevProps) - - if (props.reset) { - current = {} - state.transitions = [] - } - - // Compare next keys with current keys - const currentKeys = Object.keys(current) - const currentSet = new Set(currentKeys) - const nextSet = new Set(keys) - - const addedKeys = keys.filter(key => !currentSet.has(key)) - const updatedKeys = update ? keys.filter(key => currentSet.has(key)) : [] - const deletedKeys = state.transitions - .filter(t => !t.destroyed && !nextSet.has(t.originalKey)) - .map(t => t.originalKey) - - let delay = -trail - - while (order.length) { - let phase = order.shift() - if (phase === ENTER) { - if (first && !is.und(initial)) { - phase = INITIAL - from = initial - } - addedKeys.forEach(key => { - // In unique mode, remove fading out transitions if their key comes in again - if (unique && deleted.find(d => d.originalKey === key)) { - deleted = deleted.filter(t => t.originalKey !== key) - } - const i = keys.indexOf(key) - const item = items[i] - const enterProps = callProp(enter, item, i) - current[key] = { - phase, - originalKey: key, - key: unique ? String(key) : guid++, - item, - props: { - delay: (delay += trail), - config: callProp(config, item, phase), - from: callProp(from, item, i), - to: enterProps, - ...(is.obj(enterProps) && interpolateTo(enterProps)), - }, - } - }) - } else if (phase === LEAVE) { - deletedKeys.forEach(key => { - const i = _keys.indexOf(key) - const item = _items[i] - const leaveProps = callProp(leave, item, i) - deleted.push({ - ...current[key], - phase, - destroyed: true, - left: _keys[i - 1], - right: _keys[i + 1], - props: { - delay: (delay += trail), - config: callProp(config, item, phase), - to: leaveProps, - ...(is.obj(leaveProps) && interpolateTo(leaveProps)), - }, - }) - delete current[key] - }) - } else if (phase === UPDATE) { - updatedKeys.forEach(key => { - const i = keys.indexOf(key) - const item = items[i] - const updateProps = callProp(update, item, i) - current[key] = { - ...current[key], - phase, - props: { - delay: (delay += trail), - config: callProp(config, item, phase), - to: updateProps, - ...(is.obj(updateProps) && interpolateTo(updateProps)), - }, - } - }) - } - } - let out = keys.map(key => current[key]) - out = reconcileDeleted(deleted, out) - - return { - ...state, - first: first && !addedKeys.length, - changed: !!(addedKeys.length || deletedKeys.length || updatedKeys.length), - transitions: out, - current, - deleted, - prevProps: props, - } -} diff --git a/packages/core/src/useTransition.tsx b/packages/core/src/useTransition.tsx new file mode 100644 index 000000000..58de04287 --- /dev/null +++ b/packages/core/src/useTransition.tsx @@ -0,0 +1,350 @@ +import React, { + useRef, + useMemo, + useImperativeHandle, + ReactNode, + RefObject, +} from 'react' +import { + is, + toArray, + useForceUpdate, + useIsomorphicLayoutEffect, + useOnce, + each, + OneOrMore, + Falsy, + Indexable, + Merge, +} from 'shared' +import { now } from 'shared/globals' + +import { DEFAULT_PROPS, callProp, interpolateTo } from './helpers' +import { SpringHandle, AsyncTo, FromProp, SpringValues } from './types/spring' +import { Controller, ControllerProps } from './Controller' +import { AnimationProps, AnimationEvents } from './types/animated' +import { UseSpringProps } from './useSpring' +import { PickAnimated } from './types/common' + +// TODO: convert to "const enum" once Babel supports it +export type Phase = number & { __type: 'TransitionPhase' } +/** This transition is being mounted */ +const MOUNT = 0 as Phase +/** This transition is entering or has entered */ +const ENTER = 1 as Phase +/** This transition had its animations updated */ +const UPDATE = 2 as Phase +/** This transition will expire after animating */ +const LEAVE = 3 as Phase + +type UnknownProps = Indexable + +type PhaseProp = + | Falsy + | OneOrMore + | (( + item: Item, + index: number + ) => UseSpringProps | AsyncTo | Falsy) + +type PhaseProps = { + from?: From & + ( + | FromProp + | ((item: Item, index: number) => FromProp)) + initial?: From & + ( + | FromProp + | ((item: Item, index: number) => FromProp)) + enter?: PhaseProp + update?: PhaseProp + leave?: PhaseProp +} + +type Key = string | number + +export type ItemKeys = OneOrMore | ((item: T) => Key) | null + +export type UseTransitionProps = Merge< + AnimationProps & AnimationEvents, + { + /** + * Used to access the imperative API. + * + * Animations never auto-start when `ref` is defined. + */ + ref?: RefObject + key?: ItemKeys + sort?: (a: Item, b: Item) => number + trail?: number + expires?: number + } +> + +/** The imperative `ref` API */ +export type TransitionHandle = Merge< + SpringHandle, + { + update(props: ControllerProps): TransitionHandle + } +> + +/** The function returned by `useTransition` */ +export interface TransitionFn { + ( + render: ( + values: SpringValues, + item: Item, + transition: TransitionState + ) => ReactNode + ): ReactNode[] +} + +function getKeys( + items: readonly any[], + { key, keys = key }: { key?: ItemKeys; keys?: ItemKeys } +): readonly any[] { + return is.und(keys) ? items : is.fun(keys) ? items.map(keys) : toArray(keys) +} + +export function useTransition( + data: OneOrMore, + props: Props & PhaseProps & UseTransitionProps, + deps?: any[] +): TransitionFn> + +export function useTransition( + data: unknown, + props: PhaseProps & UseTransitionProps, + deps?: any[] +): TransitionFn { + const { ref, reset, sort, trail = 0, expires = Infinity } = props + + // Every item has its own transition. + const items = toArray(data) + const transitions: TransitionState[] = [] + + // Keys help with reusing transitions between renders. + // The `key` prop can be undefined (which means the items themselves are used + // as keys), or a function (which maps each item to its key), or an array of + // keys (which are assigned to each item by index). + const keys = getKeys(items, props) + + // The "onRest" callbacks need a ref to the latest transitions. + const usedTransitions = useRef(null) + const prevTransitions = usedTransitions.current + useIsomorphicLayoutEffect(() => { + usedTransitions.current = transitions + }) + + // Destroy all transitions on dismount. + useOnce(() => () => + each(usedTransitions.current!, t => { + if (t.expiresBy != null) { + clearTimeout(t.expirationId) + } + t.ctrl.dispose() + }) + ) + + // Map old indices to new indices. + const reused: number[] = [] + if (prevTransitions && !reset) + each(prevTransitions, (t, i) => { + // Expired transitions are not rendered. + if (t.expiresBy != null) { + clearTimeout(t.expirationId) + } else { + i = reused[i] = keys.indexOf(t.key) + if (~i) transitions[i] = t + } + }) + + // Mount new items with fresh transitions. + each(items, (item, i) => { + transitions[i] || + (transitions[i] = { + key: keys[i], + item, + phase: MOUNT, + ctrl: new Controller(), + }) + }) + + // Update the item of any transition whose key still exists, + // and ensure leaving transitions are rendered until they finish. + if (reused.length) { + let i = -1 + each(reused, (keyIndex, prevIndex) => { + const t = prevTransitions![prevIndex] + if (~keyIndex) { + i = transitions.indexOf(t) + transitions[i] = { ...t, item: items[keyIndex] } + } else if (props.leave) { + transitions.splice(++i, 0, t) + } + }) + } + + if (is.fun(sort)) { + transitions.sort((a, b) => sort(a.item, b.item)) + } + + // Track cumulative delay for the "trail" prop. + let delay = -trail + + // Expired transitions use this to dismount. + const forceUpdate = useForceUpdate() + + const defaultProps = {} as UnknownProps + each(DEFAULT_PROPS, prop => { + if (/function|object/.test(typeof props[prop])) { + defaultProps[prop] = props[prop] + } + }) + + // Generate changes to apply in useEffect. + const changes = new Map() + each(transitions, (t, i) => { + let to: any + let from: any + let phase: Phase + if (t.phase == MOUNT) { + to = props.enter + phase = ENTER + // The "initial" prop is only used on first render. It always overrides + // the "from" prop when defined, and it makes "enter" instant when null. + from = props.initial + if (is.und(from) || (prevTransitions && !reset)) { + from = props.from + } + } else { + const isLeave = keys.indexOf(t.key) < 0 + if (t.phase < LEAVE) { + if (isLeave) { + to = props.leave + phase = LEAVE + } else if ((to = props.update)) { + phase = UPDATE + } else return + } else if (!isLeave) { + to = props.enter + phase = ENTER + } else return + } + + // The payload is used to update the spring props once the current render is committed. + const payload: ControllerProps = { + ...defaultProps, + // When "to" is a function, it can return (1) an array of "useSpring" props, + // (2) an async function, or (3) an object with any "useSpring" props. + to: to = callProp(to, t.item, i), + from: callProp(from, t.item, i), + delay: delay += trail, + config: callProp(props.config || defaultProps.config, t.item, i), + ...(is.obj(to) && interpolateTo(to)), + } + + const { onRest } = payload + payload.onRest = result => { + if (is.fun(onRest)) { + onRest(result) + } + if (t.phase == LEAVE && t.ctrl.idle) { + t.expiresBy = now() + expires + if (expires <= 0) { + forceUpdate() + } else { + // Postpone dismounts while other controllers are active. + const transitions = usedTransitions.current! + if (transitions.every(t => t.ctrl.idle)) { + forceUpdate() + } + // When `expires` is infinite, postpone dismount until next render. + else if (expires < Infinity) { + t.expirationId = setTimeout(forceUpdate, expires) + } + } + } + } + + const change: Change = { phase } + changes.set(t, change) + + // To ensure all Animated nodes exist during render, + // the payload must be applied immediately for new items. + if (t.phase > MOUNT) { + change.payload = payload + } else { + t.ctrl.update(payload) + } + }) + + const api = useMemo( + (): TransitionHandle => ({ + get controllers() { + return usedTransitions.current!.map(t => t.ctrl) + }, + update(props) { + each(usedTransitions.current!, (t, i) => + t.ctrl.update( + is.fun(props) ? props(i, t.ctrl) : is.arr(props) ? props[i] : props + ) + ) + return api + }, + async start() { + const transitions = usedTransitions.current! + const results = await Promise.all(transitions.map(t => t.ctrl.start())) + return { + value: results.map(result => result.value), + finished: results.every(result => result.finished), + } + }, + stop: keys => each(usedTransitions.current!, t => t.ctrl.stop(keys)), + }), + [] + ) + + useImperativeHandle(ref, () => api) + + useIsomorphicLayoutEffect( + () => { + each(changes, ({ phase, payload }, t) => { + t.phase = phase + if (payload) t.ctrl.update(payload) + if (!ref) t.ctrl.start() + }) + }, + reset ? void 0 : deps + ) + + return render => + transitions.map(t => { + const elem: any = render(t.ctrl.springs, t.item, t) + return elem && elem.type ? ( + + ) : ( + elem + ) + }) +} + +interface Change { + phase: Phase + payload?: any +} + +export interface TransitionState { + key: any + item: Item + ctrl: Controller + phase: Phase + /** Destroy no later than this date */ + expiresBy?: number + expirationId?: number +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 33ae980db..99a9536c9 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -5,7 +5,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": ["dom", "es2017"], + "lib": ["es2017"], "moduleResolution": "node", "noEmitOnError": true, "noFallthroughCasesInSwitch": true, diff --git a/packages/react-spring/package.json b/packages/react-spring/package.json index d72c49ec5..466215491 100644 --- a/packages/react-spring/package.json +++ b/packages/react-spring/package.json @@ -1,6 +1,6 @@ { "name": "react-spring", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/web.ts", "dependencies": { "@react-spring/addons": "link:../addons", diff --git a/packages/react-spring/tsconfig.json b/packages/react-spring/tsconfig.json index 040013db8..5a1580bdb 100644 --- a/packages/react-spring/tsconfig.json +++ b/packages/react-spring/tsconfig.json @@ -12,8 +12,8 @@ "noUnusedLocals": true, "noUnusedParameters": true, "paths": { - "shared": ["../shared/dist"], - "shared/*": ["../shared/dist/*"] + "shared": ["../shared/src"], + "shared/*": ["../shared/src/*"] }, "preserveSymlinks": true, "skipLibCheck": true, diff --git a/packages/shared/package.json b/packages/shared/package.json index 29d76fa74..9f7264086 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/shared", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "description": "Globals and shared modules", "main": "src/index.ts", "scripts": { diff --git a/packages/shared/src/helpers.ts b/packages/shared/src/helpers.ts index 4745d1a08..4071aaecb 100644 --- a/packages/shared/src/helpers.ts +++ b/packages/shared/src/helpers.ts @@ -56,6 +56,12 @@ interface EachFn { ctx?: This ): void +

( + obj: ReadonlyMap, + cb: (this: This, value: T, key: P) => void, + ctx?: This + ): void + ( arr: readonly T[], cb: (this: This, value: T, index: number) => void, diff --git a/packages/shared/src/types/global.ts b/packages/shared/src/types/global.ts new file mode 100644 index 000000000..de3c21415 --- /dev/null +++ b/packages/shared/src/types/global.ts @@ -0,0 +1,6 @@ +declare function clearTimeout(handle?: number): void +declare function setTimeout( + handler: Function, + timeout?: number, + ...arguments: any[] +): number diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index ddf02ca37..dae4ec052 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -1,3 +1,4 @@ +import './global' export * from './animated' export * from './interpolation' export * from './common' diff --git a/rollup.config.js b/rollup.config.js index e1efbe6de..aa24bcda2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -125,7 +125,7 @@ export const getBabelOptions = ({ useESModules }, targets) => ({ plugins: [ ['@babel/plugin-proposal-class-properties', { loose: true }], ['@babel/plugin-proposal-object-rest-spread', { loose: true }], - ['@babel/plugin-transform-runtime', { regenerator: false, useESModules }], + ['@babel/plugin-transform-runtime', { useESModules }], ], }) diff --git a/scripts/prepare.js b/scripts/prepare.js index 7b2b79609..9363e1bad 100644 --- a/scripts/prepare.js +++ b/scripts/prepare.js @@ -178,7 +178,9 @@ async function prepare() { for (const depName in deps) { const dep = packages[depName] if (dep) { - deps[depName] = '^' + packages[depName].version + const version = packages[depName].version + deps[depName] = + (/-(canary|beta)\./.test(version) ? '' : '^') + version // Link "dist" packages together. const linkDir = join(pkg.dir, DIST, 'node_modules') @@ -249,14 +251,15 @@ async function prepare() { pkg[key] = fields[key] }) - log(``) + log('') + log(chalk.yellow(lernaJson.version)) + log('') await Promise.all( Object.keys(packages).map(name => { const pkg = packages[name] log(chalk.cyan(name)) - log(` rootDir: %O`, pkg.dir) - log(` version: %O`, pkg.version) - log(``) + log('./' + pkg.dir) + log('') return preparePackage(pkg) }) ) diff --git a/scripts/release.js b/scripts/release.js new file mode 100644 index 000000000..07ea2474f --- /dev/null +++ b/scripts/release.js @@ -0,0 +1,130 @@ +const { prompt } = require('enquirer') +const chalk = require('chalk') +const execa = require('execa') +const sade = require('sade') +const path = require('path') + +const lernaBin = './node_modules/.bin/lerna' + +const cli = sade('release', true) + .version('1.0.0') + .describe('Release a version') + .option('--canary', 'Release the last commit without a tag') + .option('--dry-run, -n', 'Disable side effects for testing') + .option('--no-commit', 'Release the current version as-is') + .option('--no-clean', 'Skip "yarn clean" for faster publishing') + .action(opts => { + opts.dry = !!opts['dry-run'] + process.chdir(path.dirname(__dirname)) + return opts.canary ? publishCanary(opts) : publish(opts) + }) + +Promise.resolve(cli.parse(process.argv)).catch(err => { + if (!err.command) { + console.error(err) + } else if (err.stderr) { + console.error(err.stderr) + } + process.exit(1) +}) + +async function publish(opts) { + exec(`${lernaBin} version`) + process.on('exit', () => { + if (opts.dry) { + undoCommit() + } + }) + updateLockfile() + execDry(`${lernaBin} publish`, opts) +} + +async function publishCanary(opts) { + // Publish the canary with a temporary tag. + const publishUntagged = () => + exec(` + ${lernaBin} exec + -- cd dist + && npm publish ${opts.dry ? '--dry-run' : '--tag tmp'} + ${opts.dry ? '' : '&& npm dist-tag rm \\$LERNA_PACKAGE_NAME tmp'} + `) + + if (opts.commit === false) { + return publishUntagged() + } + + const lastVersion = require('../lerna.json').version + const match = + /([^-]+)(?:-canary\.([^\.]+)\.([^\.]+))?/.exec(lastVersion) || [] + + let version = await ask('Version', match[1]) + + const pr = await ask('PR number', match[2]) + const build = await ask('Build number', Number(match[3] || 0) + 1) + + const head = exec('git rev-parse HEAD', { silent: true }).stdout + const commit = await ask('Commit hash', head.slice(0, 7)) + + // Create the version commit. + version = `${version}-canary.${pr}.${build}.${commit}` + exec(`${lernaBin} version ${version} --yes`) + process.on('exit', () => { + if (opts.dry) { + undoCommit(commit => commit == version) + } + }) + + updateLockfile(opts) + publishUntagged() +} + +function updateLockfile(opts = {}) { + if (opts.clean !== false) { + exec(`yarn clean`) + } + + // Ensure "yarn.lock" is up-to-date. + exec(`yarn --force`) + + // Merge the "yarn.lock" changes into the version commit. + exec(`git add yarn.lock`) + exec(`git commit --amend --no-edit`) +} + +function undoCommit(shouldUndo) { + if (shouldUndo) { + // Pass the commit title to the `shouldUndo` function. + const { stdout } = exec(`git --no-pager show -s --format=%s HEAD`, { + silent: true, + }) + if (!shouldUndo(stdout)) return + } + exec(`git reset --hard HEAD^`) +} + +function execDry(cmd, opts) { + if (opts.dry) { + console.log(`\nSkipping command:\n ${chalk.yellow(cmd)}\n`) + } else { + exec(cmd, opts) + } +} + +function exec(cmd, { silent } = {}) { + cmd = cmd.trim().replace(/\n /g, '\n') + if (!silent) console.log(`\nExecuting command:\n ${chalk.green(cmd)}\n`) + cmd = cmd.split(/[\s]+/g) + return execa.sync(cmd[0], cmd.slice(1), { + stdio: silent ? 'pipe' : 'inherit', + }) +} + +async function ask(message, initial) { + const { value } = await prompt({ + type: 'input', + name: 'value', + message, + initial, + }) + return value +} diff --git a/targets/konva/package.json b/targets/konva/package.json index 1d9e48a09..35b0a3e1a 100644 --- a/targets/konva/package.json +++ b/targets/konva/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/konva", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "dependencies": { "@react-spring/animated": "link:../../packages/animated", diff --git a/targets/native/package.json b/targets/native/package.json index 508918f4d..2cc2432d4 100644 --- a/targets/native/package.json +++ b/targets/native/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/native", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "scripts": { "build": "rollup -c" diff --git a/targets/native/src/animated.ts b/targets/native/src/animated.ts index ecc8bb55f..5c689a07e 100644 --- a/targets/native/src/animated.ts +++ b/targets/native/src/animated.ts @@ -1,4 +1,4 @@ -import { ForwardRefExoticComponent, Component, ReactNode } from 'react' +import { ForwardRefExoticComponent, ComponentClass, ReactNode } from 'react' import { withAnimated, extendAnimated } from '@react-spring/animated' import { Text, @@ -6,8 +6,6 @@ import { Image, ViewProps, ViewStyle, - NativeMethodsMixin, - Constructor, RecursiveArray, } from 'react-native' import { @@ -17,14 +15,12 @@ import { FluidValue, } from 'shared' -declare class ViewComponent extends Component< - // @types/react-native forgot to add "children" to the "View" component?? - ViewProps & { children?: ReactNode } -> {} - // These are converted into `animated` components const elements = { - View: View as Constructor & typeof ViewComponent, + View: View as ComponentClass< + // @types/react-native forgot to add "children" to the "View" component?? + ViewProps & { children?: ReactNode } + >, Text, Image, } diff --git a/targets/three/package.json b/targets/three/package.json index 3bec65df2..1c06f2077 100644 --- a/targets/three/package.json +++ b/targets/three/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/three", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "dependencies": { "@react-spring/animated": "link:../../packages/animated", diff --git a/targets/web/package.json b/targets/web/package.json index 207212b37..63ba767dd 100644 --- a/targets/web/package.json +++ b/targets/web/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/web", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "dependencies": { "@react-spring/animated": "link:../../packages/animated", diff --git a/targets/web/src/types/__tests__/Transition.tsx b/targets/web/src/types/__tests__/Transition.tsx index 8c8ecfde3..056c3f0a9 100644 --- a/targets/web/src/types/__tests__/Transition.tsx +++ b/targets/web/src/types/__tests__/Transition.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { assert, test, _ } from 'spec.ts'; -import { Transition, animated, SpringValue, TransitionPhase } from '../..'; -import { SpringValues } from '@react-spring/core'; +import { SpringValues, Transition, TransitionPhase } from '@react-spring/core'; +import { animated } from '../..'; const View = animated('div'); diff --git a/targets/web/src/types/__tests__/useTransition.tsx b/targets/web/src/types/__tests__/useTransition.tsx index 30eeb32db..528841041 100644 --- a/targets/web/src/types/__tests__/useTransition.tsx +++ b/targets/web/src/types/__tests__/useTransition.tsx @@ -1,52 +1,53 @@ import React from 'react'; import { assert, test, _ } from 'spec.ts'; -import { - animated, - useTransition, - ItemTransition, - SpringValue, - SpringUpdateFn, -} from '../..'; +import { SpringValues } from '@react-spring/core'; +import { animated, useTransition, SpringUpdateFn } from '../..'; const View = animated('div'); const items = [1, 2] as [1, 2]; test('infer animated from these props', () => { - const [transition] = useTransition(items, null, { + const transition = useTransition(items, { from: { a: 1 }, enter: { b: 1 }, leave: { c: 1 }, update: { d: 1 }, initial: { e: 1 }, }); - assert(transition.props, _ as { - [key: string]: SpringValue; - a: SpringValue; - b: SpringValue; - c: SpringValue; - d: SpringValue; - e: SpringValue; + transition((style, item) => { + assert(style, _ as SpringValues<{ + a: number; + b: number; + c: number; + d: number; + e: number; + }>); + assert(item, _ as 1 | 2); + return null; }); }); test('basic usage', () => { - const transitions = useTransition(items, null, { + const transition = useTransition(items, { from: { opacity: 0 }, enter: [{ opacity: 1 }, { color: 'red' }], leave: { opacity: 0 }, }); // You typically map transition objects into JSX elements. - return transitions.map(transition => { - type T = ItemTransition<1 | 2, { opacity: number; color: string }>; - assert(transition, _ as T); - return {transition.item}; + return transition((style, item) => { + assert(style, _ as SpringValues<{ + opacity?: number; // FIXME: "opacity" should never be undefined because it exists in "from" + color?: string; + }>); + assert(item, _ as 1 | 2); + return {item}; }); }); test('with function props', () => { - const transitions = useTransition(items, null, { + const transition = useTransition(items, { from: item => { assert(item, _ as 1 | 2); return { width: 0, height: 0 }; @@ -57,15 +58,18 @@ test('with function props', () => { }, leave: { width: '0%', opacity: 0 }, }); - assert(transitions[0].props, _ as { - [key: string]: SpringValue; - width: SpringValue; - height: SpringValue; - opacity: SpringValue; + transition((style, item) => { + assert(style, _ as SpringValues<{ + width: string | number; + height: string; + opacity: number; + }>); + assert(item, _ as 1 | 2); + return null; }); test('return an async function', () => { - useTransition(items, null, { + useTransition(items, { update: item => async next => { assert(item, _ as 1 | 2); assert(next, _ as SpringUpdateFn); // FIXME: should be "SpringUpdateFn<{ opacity: number, ... }>" diff --git a/targets/zdog/package.json b/targets/zdog/package.json index fb53f78a4..bf99ade20 100644 --- a/targets/zdog/package.json +++ b/targets/zdog/package.json @@ -1,6 +1,6 @@ { "name": "@react-spring/zdog", - "version": "next", + "version": "9.0.0-canary.809.5.f01ecc2", "main": "src/index.ts", "dependencies": { "@react-spring/animated": "link:../../packages/animated", diff --git a/yarn.lock b/yarn.lock index 8708cd2fa..d00878a64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1869,57 +1869,57 @@ universal-user-agent "^4.0.0" "@react-spring/addons@link:packages/addons": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" use-memo-one "^1.1.0" "@react-spring/animated@link:packages/animated": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/shared" "link:packages/shared" "@react-spring/core@link:packages/core": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/shared" "link:packages/shared" use-memo-one "^1.1.0" "@react-spring/konva@link:targets/konva": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" "@react-spring/shared" "link:packages/shared" "@react-spring/native@link:targets/native": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" "@react-spring/shared" "link:packages/shared" "@react-spring/shared@link:packages/shared": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" "@react-spring/three@link:targets/three": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" "@react-spring/shared" "link:packages/shared" "@react-spring/web@link:targets/web": - version "9.0.0-beta.34" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" "@react-spring/shared" "link:packages/shared" "@react-spring/zdog@link:targets/zdog": - version "9.0.0-beta.33" + version "9.0.0-canary.809.5.f01ecc2" dependencies: "@react-spring/animated" "link:packages/animated" "@react-spring/core" "link:packages/core" @@ -2210,6 +2210,11 @@ ansi-colors@^1.0.1: dependencies: ansi-wrap "^0.1.0" +ansi-colors@^3.2.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + ansi-cyan@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" @@ -3086,7 +3091,7 @@ commander@mateodelnorte/commander.js: version "2.15.1" resolved "https://codeload.github.com/mateodelnorte/commander.js/tar.gz/9060bf880b791cf39245d425f1e8a41a55616781" dependencies: - find-module-bin "0.0.2" + find-module-bin "^1.0.0" commander@~2.13.0: version "2.13.0" @@ -3329,7 +3334,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3412,7 +3417,7 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.4.4: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -3668,16 +3673,18 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" +enquirer@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.2.tgz#1c30284907cadff5ed2404bd8396036dd3da070e" + integrity sha512-PLhTMPUXlnaIv9D3Cq3/Zr1xb7soeDDgunobyCmYLUG19n24dvC8i+ZZgm2DekGpDnx7JvFSHV7lxfM58PMtbA== + dependencies: + ansi-colors "^3.2.1" + envinfo@^5.7.0: version "5.12.1" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-5.12.1.tgz#83068c33e0972eb657d6bc69a6df30badefb46ef" integrity sha512-pwdo0/G3CIkQ0y6PCXq4RdkvId2elvtPCJMG0konqlrfkWQbf1DWeH9K2b/cvu2YgGvPPTOnonZxXM1gikFu1w== -envinfo@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.3.1.tgz#892e42f7bf858b3446d9414ad240dbaf8da52f09" - integrity sha512-GvXiDTqLYrORVSCuJCsWHPXF5BFvoWMQA9xX4YVjPT1jyS3aZEHUBwjzxU/6LTPF9ReHgVEbX7IEN5UvSXHw/A== - err-code@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" @@ -3853,6 +3860,21 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/execa/-/execa-2.0.4.tgz#2f5cc589c81db316628627004ea4e37b93391d8e" + integrity sha512-VcQfhuGD51vQUQtKIq2fjGDLDbL6N1DTQVpYzxZ7LPIXw3HqTuIz6uxRmpV1qf8i31LHf2kjiaGI+GdHwRgbnQ== + dependencies: + cross-spawn "^6.0.5" + get-stream "^5.0.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^3.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -4139,12 +4161,12 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-module-bin@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/find-module-bin/-/find-module-bin-0.0.2.tgz#99ef84fb548aedae3bfe4da14b61846cd9888666" - integrity sha1-me+E+1SK7a47/k2hS2GEbNmIhmY= +find-module-bin@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-module-bin/-/find-module-bin-1.1.0.tgz#5f465cf4b2431deb184b3ebaee8ad6c9c5af8523" + integrity sha512-v53mIFOiuump1BSkwURrLblQm+LpWDVQOkQdph/xLPRrbyCU48RryPUSYxih6+gkAdNw9AkqWL7OXUhmE1ddmg== dependencies: - debug "^2.4.4" + debug "^4.1.1" global-paths "^1.0.0" find-up@^1.0.0: @@ -4376,6 +4398,13 @@ get-stream@^4.0.0, get-stream@^4.1.0: dependencies: pump "^3.0.0" +get-stream@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -5175,6 +5204,11 @@ is-stream@^1.0.1, is-stream@^1.1.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" @@ -6611,7 +6645,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-fn@^2.0.0: +mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -7011,6 +7045,13 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npm-run-path@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + "npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -7145,6 +7186,13 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + opn@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a" @@ -7238,6 +7286,11 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + p-is-promise@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" @@ -7426,6 +7479,11 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.0.tgz#99a10d870a803bdd5ee6f0470e58dfcd2f9a54d3" + integrity sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg== + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -8488,6 +8546,13 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" +sade@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.6.1.tgz#aba16655e998b2b68beb9f13938af010f42eddd2" + integrity sha512-USHm9quYNmJwFwhOnEuJohdnBhUOKV1mhL0koHSJMLJaesRX0nuDuzbWmtUBbUmXkwTalLtUBzDlEnU940BiQA== + dependencies: + mri "^1.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9116,6 +9181,11 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"