Skip to content

Instantly share code, notes, and snippets.

@porfirioribeiro
Last active January 24, 2020 20:46
Show Gist options
  • Save porfirioribeiro/17adefa89a57985f4fe89c2aaef6771e to your computer and use it in GitHub Desktop.
Save porfirioribeiro/17adefa89a57985f4fe89c2aaef6771e to your computer and use it in GitHub Desktop.
preact-composition
import { PreactContext, JSX, Component } from 'preact';
export * from './store';
type FC<P> = (props: P) => JSX.Element;
type createComponentFN<P> = (c: Component<P>) => FC<P>;
/**
* Wraps a FunctionalComponent to be handled with the composition api
* @param fn
*/
export function createComponent<P>(fn: createComponentFN<P>): FC<P>;
export function memo<P = {}>(comparer?: (prev: P, next: P) => boolean): void;
export type ReactiveHolder<T extends {}> = T & {
// get or set the immutable inner value of this reactive
$value: T;
};
/**
* Creates a Proxy around the `value` object that any time its change it will update the component
* @param value
*/
export function reactive<T extends {}>(value: T): ReactiveHolder<T>;
export type ValueHolder<T> = { value: T };
/**
* Returns a reference with a `value` property, that when it changes will update the component if not `staticRef`
* @param v
*/
export function value<T>(v?: T): ValueHolder<T>;
export function unwrap<T>(
refOrValue: ValueHolder<T> | ReactiveHolder<T> | T
): T;
export function isReactive(v: any): boolean;
/**
* @param callback run on mount
*/
export function onMounted(callback: () => void): void;
/**
* @param callback run on unmount
*/
export function onUnmounted(cb: () => void): void;
export type EffectCallback<T> = (
args: T,
oldArgs: T,
onCleanup: Function
) => void;
export type PropGetter<P, T> = (props: P) => T;
export type WatchSrc<T, P> =
| PropGetter<P, T>
| ValueHolder<T>
| ReactiveHolder<T>
| PreactContext<T>;
type WatchCb<T extends Array<any>, R> = (...value: T) => R;
export type WatchResult<T> = { readonly value: T };
/**
* `watch` function can operate in many ways.
*
* Before each render all `watch`'ers are run or updated with the new value
* and if any args from src changed `callback` is called with the new args and the old args
* ```js
* watch(props => props.id) //returns `value` id props value (kinda irrelevant)
* watch(props => props.a + props.b) //acts like a compute function and returns a `value` summing props a + b
* watch(someValue, value => console.log('The value of someValue is: ', value))
* ```
* @param src
* @param callback optional callback to call if the args returned from src changed
* @returns `value` holding the result from the first `src` specified or the return of the `callback`
*/
/** watch values */
export function watch<P, T>(src: WatchSrc<T, P>): WatchResult<T>;
export function watch<P, T0, T1>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>]
): WatchResult<[T0, T1]>;
export function watch<P, T0, T1, T2>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>, WatchSrc<T2, P>]
): WatchResult<[T0, T1, T2]>;
/** watch values with a callback returning a promise and default value */
export function watch<P, R>(
src: [],
cb: () => PromiseLike<R>,
def: R
): WatchResult<R>;
export function watch<P, T, R>(
src: WatchSrc<T, P>,
cb: (value: T) => PromiseLike<R>,
def: R
): WatchResult<R>;
export function watch<P, T0, T1, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>],
cb: WatchCb<[T0, T1], PromiseLike<R>>,
def: R
): WatchResult<R>;
export function watch<P, T0, T1, T2, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>, WatchSrc<T2, P>],
cb: WatchCb<[T0, T1, T2], PromiseLike<R>>,
def: R
): WatchResult<R>;
/** watch values with a callback returning a promise */
export function watch<P, R>(
src: [],
cb: WatchCb<[], PromiseLike<R>>
): WatchResult<R | undefined>;
export function watch<P, T, R>(
src: WatchSrc<T, P>,
cb: WatchCb<[T], PromiseLike<R>>
): WatchResult<R | undefined>;
export function watch<P, T0, T1, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>],
cb: WatchCb<[T0, T1], PromiseLike<R>>
): WatchResult<R | undefined>;
export function watch<P, T0, T1, T2, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>, WatchSrc<T2, P>],
cb: WatchCb<[T0, T1, T2], PromiseLike<R>>
): WatchResult<R | undefined>;
/** watch values with a callback returning a value */
export function watch<P, R>(
src: [],
cb: WatchCb<[], R>
): WatchResult<R>;
export function watch<P, T, R>(
src: WatchSrc<T, P>,
cb: WatchCb<[T], R>
): WatchResult<R>;
export function watch<P, T0, T1, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>],
cb: WatchCb<[T0, T1], R>
): WatchResult<R>;
export function watch<P, T0, T1, T2, R>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>, WatchSrc<T2, P>],
cb: WatchCb<[T0, T1, T2], R>
): WatchResult<R>;
/**
* `effect` its run after render it can also be used to callback when something changed
* The callback will receive newArgs, oldArgs and onCleanup to assign a cleanup function
* @param src
* @param callback optional callback to call if the args returned from src changed
* @returns nothing
*/
export function effect<P, T>(src: WatchSrc<T, P>, cb: EffectCallback<T>): void;
export function effect<P, T0, T1>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>],
cb: EffectCallback<[T0, T1]>
): void;
export function effect<P, T0, T1, T2>(
src: [WatchSrc<T0, P>, WatchSrc<T1, P>, WatchSrc<T2, P>],
cb: EffectCallback<[T0, T1, T2]>
): void;
// todo more effect overloads to cover all cases
export interface InjectionKey<T> extends String {}
export function provide<T>(key: InjectionKey<T> | string, value: T): void;
export function inject<T>(key: InjectionKey<T> | string): T | undefined;
export function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T;
import{Component as n}from"preact";function r(n,r){void 0===r&&(r=t);var u,i=[];function o(r){(n!=n?r==r:n!==r)&&(n=r,u&&i.some(function(r){r(n)}))}return{get:function(){return n},set:o,update:function(r){o(r(n))},subscribe:function(e){return i.push(e),1===i.length&&(u=r(o)||t),e(n),function(){var n=i.indexOf(e);-1!==n&&i.splice(n,1),0===i.length&&(u(),u=null)}}}}function t(){}var u,i=Symbol();function o(){for(var n;n=this.__C.t.pop();)w(n),n.u(n.__v,n.i,function(r){return n.o=r}),n.i=n.v?n.__v.slice():n.__v}function e(){this.__C.l.some(w)}function f(r){function t(){}return(t.prototype=new n).componentWillMount=function(){var n,t=u=this;t.__C={_:{},s:[],p:[],t:[],l:[],h:function(){n&&t.forceUpdate()}};var i=r(t);t.render=function(r){n&&(t.__C.s.some(x),c(t));var u=t.__C.m=t.__v.ref;return t.__v.ref=null,n=!0,i(r,u)},u=null},t}function c(n){for(var r;r=n.__C.p.pop();){var t=r.u?r.u.apply(null,r.v?r.__v:[r.__v]):r.__v,u=r.g;t&&t.then?t.then(u.set).then(n.__C.h):u.set(t),r.i=r.v?r.__v.slice():r.__v}}function a(n){u.shouldComponentUpdate=function(r,t,u,i){return i.ref!==this.__C.m||(n||function(n,r){for(var t in n)if("__source"!==t&&!(t in r))return!0;for(var u in r)if("__source"!==u&&n[u]!==r[u])return!0;return!1})(this.props,r)}}function v(n,r,t){var o=g(t,!0,!1);return _(u.__C.p,n,r,o[i]),c(u),o}function l(n,r){_(u.__C.t,n,r)}function _(n,r,t,u){var i=Array.isArray(r),o={v:i,__v:i?[]:null,u:t,g:u};i?r.length?r.forEach(function(r,t){return s(o,n,r,t)}):A(n,o):s(o,n,r)}function s(n,r,t,i){var e=u,f=function(t,u){null==i?n.__v=t:n.__v[i]=t,A(r,n)&&!u&&e.__C.h(),n.g||A(e.__h,o)};if(t){var c,a,v=t.Provider;if("function"==typeof t||v){if(v){var l=t.__c,_=e.context[l];_&&!e.__C._[l]&&(_.sub(e),e.__C._[l]=t)}var s=function(){var n=v?(c=e.context[t.__c])?c.props.value:t.__p:t(e.props);n!==a&&f(a=n,!0)};return s(),e.__C.s.push(s)}if(m(t,f))return}f(t)}function p(n){u.__h.push(n)}function b(n){u.componentWillUnmount||(u.componentWillUnmount=e),u.__C.l.push({o:n})}function d(n,r){var t=u;t.__C.j||(t.__C.j={},t.getChildContext=function(){return t.__C.j}),t.__C.j["__sC_"+n]={__c:t,__v:r}}function h(n,r){var t=u.context["__sC_"+n],i=t?t.__v:r;return m(i,u.__C.h),i}function m(n,r,t){if((t=n[i])||(t=n.subscribe&&n)){var u=t.subscribe(r);return b(u.unsubscribe?function(){return u.unsubscribe()}:u),!0}}function y(n){var r=g(n),t=r[i];delete r.value;var u={$value:t};return Object.keys(n).forEach(function(n){u[n]=j(function(){return t.get()[n]},function(r){var u=t.get();r!==u[n]&&((u=function(n,r){for(var t in r)n[t]=r[t];return n}({},u))[n]=r,t.set(u))})}),Object.defineProperties(r,u)}function g(n,t,o){var e;void 0===o&&(o=u);var f=r(n),c=t?void 0:f.set,a=f.get;return o&&b(f.subscribe(o.__C.h)),Object.defineProperties({},((e={})[i]={value:f},e.value=j(a,c),e))}function j(n,r){return{get:n,set:r,enumerable:!0,configurable:!0}}function C(n){var r;return n&&((r=n[i])||(r=n.subscribe&&n.get&&n))?r.get():n}function O(n){return!(!n||!(n[i]||n.subscribe&&n.get))}function w(n){n.o&&(n.o(),n.o=void 0)}function x(n){n()}function A(n,r){return n.indexOf(r)<0&&!!n.push(r)}export{f as createComponent,a as memo,v as watch,l as effect,p as onMounted,b as onUnmounted,d as provide,h as inject,y as reactive,g as value,C as unwrap,O as isReactive,r as createStore};
{
"name": "preact-composition",
"version": "1.0.0",
"description": "",
"main": "index.js",
"module": "index.js",
"sideEffects": false
}
/** Callback to inform of a value updates. */
declare type Subscriber<T> = (value: T) => void;
/** Unsubscribes from value updates. */
declare type Unsubscriber = () => void;
/** Callback to update a value. */
declare type Updater<T> = (value: T) => T;
/** Cleanup logic callback. */
declare type Invalidator<T> = (value?: T) => void;
/** Start and stop notification callbacks. */
declare type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void;
export interface Store<T> {
/**
* Get the current value on the store
*/
get(): T;
/**
* Subscribe on value changes.
* @param run subscription callback
* @param invalidate cleanup callback
*/
subscribe(run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber;
/**
* Set value and inform subscribers.
* @param value to set
*/
set(value: T): void;
/**
* Update value using callback and inform subscribers.
* @param updater callback
*/
update(updater: Updater<T>): void;
}
/**
* Create a `Store` store that allows both updating and reading by subscription.
* @param {*=}value initial value
* @param {StartStopNotifier=}start start and stop notifications for subscriptions
*/
export declare function createStore<T>(
value: T,
start?: StartStopNotifier<T>
): Store<T>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment