@renderlesskit/react
Version:
Collection of headless components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit
120 lines (96 loc) • 3.76 kB
JavaScript
import { useOptions, useProps } from "reakit-system";
import { shallowEqual, toArray } from "reakit-utils";
/**
* Creates a React custom hook that will return component props.
*
* @example
* import { createHook } from "../system";
*
* const useA = createHook({
* name: "A",
* keys: ["url"], // custom props/options keys
* useProps(options, htmlProps) {
* return {
* ...htmlProps,
* href: options.url,
* };
* },
* });
*
* function A({ url, ...htmlProps }) {
* const props = useA({ url }, htmlProps);
* return <a {...props} />;
* }
*
* @param options
*/
export function createHook(options) {
var _options$useState, _composedHooks$;
var composedHooks = toArray(options.compose);
var __useOptions = (hookOptions, htmlProps) => {
// Call the current hook's useOptions first
if (options.useOptions) {
hookOptions = options.useOptions(hookOptions, htmlProps);
} // If there's name, call useOptions from the system context
if (options.name) {
// eslint-disable-next-line react-hooks/rules-of-hooks
hookOptions = useOptions(options.name, hookOptions, htmlProps);
} // Run composed hooks useOptions
if (options.compose) {
for (var hook of composedHooks) {
hookOptions = hook.__useOptions(hookOptions, htmlProps);
}
}
return hookOptions;
};
var useHook = function useHook() {
var hookOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var htmlProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var unstable_ignoreUseOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
// This won't execute when useHook was called from within another useHook
if (!unstable_ignoreUseOptions) {
hookOptions = __useOptions(hookOptions, htmlProps);
} // Call the current hook's useProps
if (options.useProps) {
htmlProps = options.useProps(hookOptions, htmlProps);
} // If there's name, call useProps from the system context
if (options.name) {
// eslint-disable-next-line react-hooks/rules-of-hooks
htmlProps = useProps(options.name, hookOptions, htmlProps);
}
if (options.compose) {
if (options.useComposeOptions) {
hookOptions = options.useComposeOptions(hookOptions, htmlProps);
}
if (options.useComposeProps) {
htmlProps = options.useComposeProps(hookOptions, htmlProps);
} else {
for (var hook of composedHooks) {
htmlProps = hook(hookOptions, htmlProps, true);
}
}
} // Remove undefined values from htmlProps
var finalHTMLProps = {};
var definedHTMLProps = htmlProps || {};
for (var prop in definedHTMLProps) {
if (definedHTMLProps[prop] !== undefined) {
finalHTMLProps[prop] = definedHTMLProps[prop];
}
}
return finalHTMLProps;
};
useHook.__useOptions = __useOptions;
var composedKeys = composedHooks.reduce((keys, hook) => {
keys.push(...(hook.__keys || []));
return keys;
}, []); // It's used by createComponent to split option props (keys) and html props
useHook.__keys = [...composedKeys, ...(((_options$useState = options.useState) === null || _options$useState === void 0 ? void 0 : _options$useState.__keys) || []), ...(options.keys || [])];
useHook.unstable_propsAreEqual = options.propsAreEqual || ((_composedHooks$ = composedHooks[0]) === null || _composedHooks$ === void 0 ? void 0 : _composedHooks$.unstable_propsAreEqual) || shallowEqual;
if (options.name) {
Object.defineProperty(useHook, "name", {
value: "use".concat(options.name)
});
}
return useHook;
}
//# sourceMappingURL=createHook.js.map