fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

View File

@@ -0,0 +1,6 @@
dist
es
lib
ts
coverage
node_modules

View File

@@ -0,0 +1,330 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.15.2](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.15.1...reakit-system@0.15.2) (2021-09-06)
**Note:** Version bump only for package reakit-system
## [0.15.1](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.15.0...reakit-system@0.15.1) (2020-12-11)
### Bug Fixes
* Add React 17 to peer dependencies ([#807](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/807)) ([411b5aa](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/411b5aa8adf63f3149b40db6a499e65b58929b29)), closes [#776](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/776)
* Stop passing the `state` prop to custom `as` components ([#800](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/800)) ([e4c67a3](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/e4c67a3de2985684dd1ed918175df3454cd44b81)), closes [#797](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/797)
# [0.15.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.5...reakit-system@0.15.0) (2020-11-12)
### Features
* Add `Role` component ([#728](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/728)) ([5fa51a7](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/5fa51a7891085aeeb6a0e3ea44ef3d294fccc8ba))
* Add `state` prop on all components ([#771](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/771)) ([4ed846d](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/4ed846d0a17e655d726572910b57b9ad3ebc235d)), closes [#744](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/744)
## [0.14.5](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.4...reakit-system@0.14.5) (2020-09-22)
**Note:** Version bump only for package reakit-system
## [0.14.4](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.3...reakit-system@0.14.4) (2020-09-03)
### Bug Fixes
* Fix internal dependency versions ([3d4cb42](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/3d4cb4217a52ec719e8a2823d21e08c7cc42dd30))
## [0.14.3](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.2...reakit-system@0.14.3) (2020-08-24)
**Note:** Version bump only for package reakit-system
## [0.14.2](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.1...reakit-system@0.14.2) (2020-08-17)
**Note:** Version bump only for package reakit-system
## [0.14.1](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.14.0...reakit-system@0.14.1) (2020-08-13)
**Note:** Version bump only for package reakit-system
# [0.14.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.13.1...reakit-system@0.14.0) (2020-08-06)
**Note:** Version bump only for package reakit-system
## [0.13.1](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.13.0...reakit-system@0.13.1) (2020-07-18)
**Note:** Version bump only for package reakit-system
# [0.13.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.13.0-alpha.0...reakit-system@0.13.0) (2020-06-17)
### Features
* Support render props passed to the `as` prop component ([#668](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/668)) ([214d0e6](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/214d0e6357ea659a05d351fc26f539d186df0404))
## [0.12.2](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.12.1...reakit-system@0.12.2) (2020-06-04)
### Bug Fixes
* **reakit-system:** Fix forwardRef TypeScript types ([2d96447](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/2d9644704f8e9e1f14ecf726ad8d4f7b401817c9))
### Performance Improvements
* Improve `Composite` performance ([#660](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/660)) ([f6656b6](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/f6656b6b765bbec639754aa96a2f08b717413068))
## [0.12.1](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.12.0...reakit-system@0.12.1) (2020-05-12)
### Features
* Remove `undefined` props from props hooks and render props ([d95c9e5](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/d95c9e5311debc59c3e5d137936cc78e95fb8215))
# [0.12.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.11.0...reakit-system@0.12.0) (2020-04-29)
**Note:** Version bump only for package reakit-system
# [0.11.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.10.0...reakit-system@0.11.0) (2020-04-20)
### Bug Fixes
* Fix `Composite` on IE11 ([#609](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/609)) ([555b931](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/555b931de003a81a635ed1d980d67f9c62fb91e0))
# [0.10.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.9.0...reakit-system@0.10.0) (2020-03-30)
### Features
* Automatically check `Radio` on focus ([#599](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/599)) ([6edc689](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/6edc68980de142686bdbdceecc8769e2a6265001))
* Select the first `Tab` by default and don't require `stopId` prop ([#597](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/597)) ([528b016](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/528b016304f381b171cdc96598201deb54fb53c8))
### BREAKING CHANGES
* The first `Tab` is now selected by default. There's no need to pass `selectedId` to `useTabState` anymore.
If you're already using `selectedId` to select a tab in the initial render, you don't need to change anything as this still works. But, if you want to render tabs with none selected, you should now pass `null` to `selectedId`:
```js
// if you're already using selectedId, there's no need to change anything
const tab = useTabState({ selectedId: "tab-1" });
```
```diff
// when there's no tab selected by default, you now need to explicitly specify it
- const tab = useTabState();
+ const tab = useTabState({ selectedId: null });
```
* **Most users will not be affected by this**, but `stops`, `register` and `unregister` on the returned object of state hooks have been renamed to `items`, `registerItem` and `unregisterItem`, respectively.
```diff
const tab = useTabState();
- tab.stops.map(...);
+ tab.items.map(...);
- tab.register(...);
+ tab.registerItem(...);
- tab.unregister(...);
+ tab.unregisterItem(...);
```
# [0.9.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.8.0...reakit-system@0.9.0) (2020-02-10)
### Features
* Add `Disclosure` module and deprecate `Hidden` ([#541](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/541)) ([4397ab0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/4397ab0ea70e78ed187d6f463a5941f72907afb0))
# [0.8.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.7.2...reakit-system@0.8.0) (2020-02-05)
### Features
* Add `modal` state to `useDialogState` ([#535](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/535)) ([f3953ad](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/f3953ad)), closes [#404](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/404)
* Replace `unstable_wrap` by `wrapElement` ([#538](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/538)) ([17a12fb](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/17a12fb))
## [0.7.2](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.7.1...reakit-system@0.7.2) (2019-12-18)
**Note:** Version bump only for package reakit-system
## [0.7.1](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.7.0...reakit-system@0.7.1) (2019-11-22)
**Note:** Version bump only for package reakit-system
# [0.7.0](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.8...reakit-system@0.7.0) (2019-11-14)
### Features
* **reakit-system:** Replace `useCompose` by `useComposeOptions` on `createHook` ([#493](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/493)) ([50fd7df](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/50fd7df))
## [0.6.8](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.7...reakit-system@0.6.8) (2019-11-08)
**Note:** Version bump only for package reakit-system
## [0.6.7](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.6...reakit-system@0.6.7) (2019-11-02)
**Note:** Version bump only for package reakit-system
## [0.6.6](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.5...reakit-system@0.6.6) (2019-10-12)
### Performance Improvements
* Improve space complexity for `createHook` method ([#453](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/453)) ([6fe7028](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/6fe7028))
## [0.6.5](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.4...reakit-system@0.6.5) (2019-09-25)
**Note:** Version bump only for package reakit-system
## [0.6.4](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.3...reakit-system@0.6.4) (2019-09-19)
**Note:** Version bump only for package reakit-system
## [0.6.3](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.2...reakit-system@0.6.3) (2019-08-25)
### Bug Fixes
* **reakit-system:** Remove dependency on reakit type ([d5ea02c](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/d5ea02c)), closes [#413](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/413)
### Features
* Upgrade `reakit` peer dependency version ([73baeff](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/73baeff))
## [0.6.2](https://github.com/reakit/reakit/tree/master/packages/reakit-system/compare/reakit-system@0.6.1...reakit-system@0.6.2) (2019-06-27)
**Note:** Version bump only for package reakit-system
## 0.6.1 (2019-06-23)
### Features
* Move helpers to separate package (reakit-utils, reakit-system) ([#380](https://github.com/reakit/reakit/tree/master/packages/reakit-system/issues/380)) ([354b874](https://github.com/reakit/reakit/tree/master/packages/reakit-system/commit/354b874))
### BREAKING CHANGES
* Utils aren't exported by `reakit` or `reakit/utils` anymore. Import them from the `reakit-utils` package instead.
* System utils aren't exported by `reakit` or `reakit/system` anymore. Import them from the `reakit-system` package instead.
* `Provider` isn't exported by `reakit/utils` or `reakit/utils/Provider` anymore. Import it from `reakit` or `reakit/Provider` instead.
# Change Log

21
node_modules/reakit/node_modules/reakit-system/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Diego Haz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,322 @@
# reakit-system
<a href="https://npmjs.org/package/reakit-system"><img alt="NPM version" src="https://img.shields.io/npm/v/reakit-system.svg" /></a>
> **This is experimental** and may have breaking changes in minor versions.
## Installation
npm:
```sh
npm i reakit-system
```
Yarn:
```sh
yarn add reakit-system
```
## Usage
```jsx
import { useRole } from "reakit/Role";
import { createHook } from "reakit-system";
const useA = createHook({ name: "A", compose: useRole });
```
## API
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
#### Table of Contents
- [createComponent](#createcomponent)
- [createHook](#createhook)
- [mergeSystem](#mergesystem)
- [SystemProvider](#systemprovider)
- [useCreateElement](#usecreateelement)
- [useOptions](#useoptions)
- [useProps](#useprops)
- [useToken](#usetoken)
### createComponent
Creates a React component.
#### Parameters
- `options` **Options&lt;T, O>**
- `options.as`
- `options.useHook`
- `options.memo`
- `options.propsAreEqual` (optional, default `useHook?.unstable_propsAreEqual`)
- `options.keys` (optional, default `useHook?.__keys||[]`)
- `options.useCreateElement` (optional, default `defaultUseCreateElement`)
#### Examples
```javascript
import { createComponent } from "reakit-system";
const A = createComponent({ as: "a" });
```
### createHook
Creates a React custom hook that will return component props.
#### Parameters
- `options` **CreateHookOptions&lt;O, P>**
#### Examples
```javascript
import { createHook } from "reakit-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} />;
}
```
### mergeSystem
Merges multiple system objects into a single system object.
#### Parameters
- `systems` **...T**
#### Examples
```javascript
import { Provider } from "reakit";
import { mergeSystem } from "reakit-system";
import * as bootstrapSystem from "reakit-system-bootstrap";
const mySystem = {
useButtonProps() {},
};
const system = mergeSystem(bootstrapSystem, mySystem);
function App() {
return (
<Provider unstable_system={system}>
<div>App</div>
</Provider>
);
}
```
### SystemProvider
Provider component that is used by `reakit`'s `Provider` underneath.
#### Parameters
- `props` **SystemProviderProps**
- `props.children`
- `props.unstable_system`
#### Examples
```javascript
// instead of using
import { Provider } from "reakit";
// you can use this
import { SystemProvider } from "reakit-system";
// reakit's Provider has more features, such as ID generation
import * as system from "reakit-system-bootstrap";
function App() {
return (
<SystemProvider unstable_system={system}>
<div>App</div>
</SystemProvider>
);
}
```
### useCreateElement
Custom hook that will call `children` if it's a function. If
`useCreateElement` has been passed to the context, it'll be used instead.
#### Parameters
- `type` **T**
- `props` **Record&lt;[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), any>**
- `children` **React.ReactNode** (optional, default `props.children`)
#### Examples
```javascript
import React from "react";
import { SystemProvider, useCreateElement } from "reakit-system";
const system = {
useCreateElement(type, props, children = props.children) {
// very similar to what `useCreateElement` does already
if (typeof children === "function") {
const { children: _, ...rest } = props;
return children(rest);
}
return React.createElement(type, props, children);
},
};
function Component(props) {
return useCreateElement("div", props);
}
function App() {
return (
<SystemProvider unstable_system={system}>
<Component url="url">{({ url }) => <a href={url}>link</a>}</Component>
</SystemProvider>
);
}
```
Returns **JSX.Element**
### useOptions
React custom hook that returns the options returned by a given
`use${name}Options` in the SystemContext.
#### Parameters
- `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `options` **T** (optional, default `{}as T`)
- `htmlProps` **any** (optional, default `{}`)
#### Examples
```javascript
import React from "react";
import { SystemProvider, useOptions } from "reakit-system";
const system = {
useAOptions(options, htmlProps) {
return {
...options,
url: htmlProps.href,
};
},
};
function A({ url, ...htmlProps }) {
const options = useOptions("A", { url }, htmlProps);
return <a href={options.url} {...htmlProps} />;
}
function App() {
return (
<SystemProvider unstable_system={system}>
<A href="url">
It will convert href into url in useAOptions and then url into href in A
</A>
</SystemProvider>
);
}
```
Returns **T**
### useProps
React custom hook that returns the props returned by a given
`use${name}Props` in the SystemContext.
#### Parameters
- `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `options` **Record&lt;[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), any>** (optional, default `{}`)
- `htmlProps` **any** (optional, default `{}`)
#### Examples
```javascript
import { SystemProvider, useProps } from "reakit-system";
const system = {
useAProps(options, htmlProps) {
return {
...htmlProps,
href: options.url,
};
},
};
function A({ url, ...htmlProps }) {
const props = useProps("A", { url }, htmlProps);
return <a {...props} />;
}
function App() {
return (
<SystemProvider unstable_system={system}>
<A url="url">It will convert url into href in useAProps</A>
</SystemProvider>
);
}
```
Returns **any**
### useToken
React custom hook that returns the value of any token defined in the
SystemContext. It's mainly used internally in [`useOptions`](#useoptions)
and [`useProps`](#useprops).
#### Parameters
- `token` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `defaultValue` **T?**
#### Examples
```javascript
import { SystemProvider, useToken } from "reakit-system";
const system = {
token: "value",
};
function Component(props) {
const token = useToken("token", "default value");
return <div {...props}>{token}</div>;
}
function App() {
return (
<SystemProvider unstable_system={system}>
<Component />
</SystemProvider>
);
}
```
Returns **T**
## License
MIT © [Diego Haz](https://github.com/diegohaz)

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/SystemContext",
"private": true,
"sideEffects": false,
"main": "../lib/SystemContext",
"module": "../es/SystemContext",
"types": "../ts/SystemContext"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/SystemProvider",
"private": true,
"sideEffects": false,
"main": "../lib/SystemProvider",
"module": "../es/SystemProvider",
"types": "../ts/SystemProvider"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/createComponent",
"private": true,
"sideEffects": false,
"main": "../lib/createComponent",
"module": "../es/createComponent",
"types": "../ts/createComponent"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/createHook",
"private": true,
"sideEffects": false,
"main": "../lib/createHook",
"module": "../es/createHook",
"types": "../ts/createHook"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
import { createContext } from 'react';
var SystemContext = /*#__PURE__*/createContext({});
export { SystemContext };

View File

@@ -0,0 +1,33 @@
import { createElement } from 'react';
import { SystemContext } from './SystemContext.js';
/**
* Provider component that is used by `reakit`'s `Provider` underneath.
*
* @example
* // instead of using
* import { Provider } from "reakit";
* // you can use this
* import { SystemProvider } from "reakit-system";
* // reakit's Provider has more features, such as ID generation
* import * as system from "reakit-system-bootstrap";
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <div>App</div>
* </SystemProvider>
* );
* }
*
* @param props
*/
function SystemProvider(_ref) {
var children = _ref.children,
system = _ref.unstable_system;
return /*#__PURE__*/createElement(SystemContext.Provider, {
value: system
}, children);
}
export { SystemProvider };

View File

@@ -0,0 +1,107 @@
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
it = o[Symbol.iterator]();
return it.next.bind(it);
}
export { _objectSpread2 as _, _objectWithoutPropertiesLoose as a, _createForOfIteratorHelperLoose as b };

View File

@@ -0,0 +1,90 @@
import { forwardRef as forwardRef$1, memo as memo$1 } from 'react';
import './SystemContext.js';
import { a as _objectWithoutPropertiesLoose, _ as _objectSpread2 } from './_rollupPluginBabelHelpers-0c84a174.js';
import { useCreateElement } from './useCreateElement.js';
import { splitProps } from 'reakit-utils/splitProps';
import { shallowEqual } from 'reakit-utils/shallowEqual';
import { normalizePropsAreEqual } from 'reakit-utils/normalizePropsAreEqual';
function forwardRef(component) {
return /*#__PURE__*/forwardRef$1(component);
}
function memo(component, propsAreEqual) {
return /*#__PURE__*/memo$1(component, propsAreEqual);
}
/**
* Creates a React component.
*
* @example
* import { createComponent } from "reakit-system";
*
* const A = createComponent({ as: "a" });
*
* @param options
*/
function createComponent(_ref) {
var type = _ref.as,
useHook = _ref.useHook,
shouldMemo = _ref.memo,
_ref$propsAreEqual = _ref.propsAreEqual,
propsAreEqual = _ref$propsAreEqual === void 0 ? useHook === null || useHook === void 0 ? void 0 : useHook.unstable_propsAreEqual : _ref$propsAreEqual,
_ref$keys = _ref.keys,
keys = _ref$keys === void 0 ? (useHook === null || useHook === void 0 ? void 0 : useHook.__keys) || [] : _ref$keys,
_ref$useCreateElement = _ref.useCreateElement,
useCreateElement$1 = _ref$useCreateElement === void 0 ? useCreateElement : _ref$useCreateElement;
var Comp = function Comp(_ref2, ref) {
var _ref2$as = _ref2.as,
as = _ref2$as === void 0 ? type : _ref2$as,
props = _objectWithoutPropertiesLoose(_ref2, ["as"]);
if (useHook) {
var _as$render;
var _splitProps = splitProps(props, keys),
_options = _splitProps[0],
htmlProps = _splitProps[1];
var _useHook = useHook(_options, _objectSpread2({
ref: ref
}, htmlProps)),
wrapElement = _useHook.wrapElement,
elementProps = _objectWithoutPropertiesLoose(_useHook, ["wrapElement"]); // @ts-ignore
var asKeys = ((_as$render = as.render) === null || _as$render === void 0 ? void 0 : _as$render.__keys) || as.__keys;
var asOptions = asKeys && splitProps(props, asKeys)[0];
var allProps = asOptions ? _objectSpread2(_objectSpread2({}, elementProps), asOptions) : elementProps;
var _element = useCreateElement$1(as, allProps);
if (wrapElement) {
return wrapElement(_element);
}
return _element;
}
return useCreateElement$1(as, _objectSpread2({
ref: ref
}, props));
};
if (process.env.NODE_ENV !== "production" && useHook) {
Comp.displayName = useHook.name.replace(/^(unstable_)?use/, "");
}
Comp = forwardRef(Comp);
if (shouldMemo) {
Comp = memo(Comp, propsAreEqual && normalizePropsAreEqual(propsAreEqual));
}
Comp.__keys = keys;
Comp.unstable_propsAreEqual = normalizePropsAreEqual(propsAreEqual || shallowEqual);
return Comp;
}
export { createComponent };

View File

@@ -0,0 +1,135 @@
import 'react';
import './SystemContext.js';
import './useToken.js';
import { useProps } from './useProps.js';
import { b as _createForOfIteratorHelperLoose } from './_rollupPluginBabelHelpers-0c84a174.js';
import { useOptions } from './useOptions.js';
import { shallowEqual } from 'reakit-utils/shallowEqual';
import { toArray } from 'reakit-utils/toArray';
/**
* Creates a React custom hook that will return component props.
*
* @example
* import { createHook } from "reakit-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
*/
function createHook(options) {
var _options$useState, _composedHooks$;
var composedHooks = toArray(options.compose);
var __useOptions = function __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) {
hookOptions = useOptions(options.name, hookOptions, htmlProps);
} // Run composed hooks useOptions
if (options.compose) {
for (var _iterator = _createForOfIteratorHelperLoose(composedHooks), _step; !(_step = _iterator()).done;) {
var hook = _step.value;
hookOptions = hook.__useOptions(hookOptions, htmlProps);
}
}
return hookOptions;
};
var useHook = function useHook(hookOptions, htmlProps, unstable_ignoreUseOptions) {
if (hookOptions === void 0) {
hookOptions = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
if (unstable_ignoreUseOptions === void 0) {
unstable_ignoreUseOptions = 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) {
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 _iterator2 = _createForOfIteratorHelperLoose(composedHooks), _step2; !(_step2 = _iterator2()).done;) {
var hook = _step2.value;
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(function (keys, hook) {
keys.push.apply(keys, hook.__keys || []);
return keys;
}, []); // It's used by createComponent to split option props (keys) and html props
useHook.__keys = [].concat(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 (process.env.NODE_ENV !== "production" && options.name) {
Object.defineProperty(useHook, "name", {
value: "use" + options.name
});
}
return useHook;
}
export { createHook };

View File

@@ -0,0 +1,16 @@
import 'react';
export { SystemContext } from './SystemContext.js';
export { useToken } from './useToken.js';
export { useProps } from './useProps.js';
import './_rollupPluginBabelHelpers-0c84a174.js';
export { useOptions } from './useOptions.js';
export { useCreateElement } from './useCreateElement.js';
import 'reakit-utils/isObject';
export { mergeSystem } from './mergeSystem.js';
import 'reakit-utils/splitProps';
import 'reakit-utils/shallowEqual';
import 'reakit-utils/normalizePropsAreEqual';
export { createComponent } from './createComponent.js';
import 'reakit-utils/toArray';
export { createHook } from './createHook.js';
export { SystemProvider } from './SystemProvider.js';

View File

@@ -0,0 +1,97 @@
import { b as _createForOfIteratorHelperLoose } from './_rollupPluginBabelHelpers-0c84a174.js';
import { isObject } from 'reakit-utils/isObject';
/**
* Transforms [{ a: "a" }, { a: "b" }] into { a: ["a", "b"] }
*/
function reduceObjects(objects, filter) {
var result = {};
for (var _iterator = _createForOfIteratorHelperLoose(objects), _step; !(_step = _iterator()).done;) {
var object = _step.value;
var keys = Object.keys(object);
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
var _key = _keys[_i];
// eslint-disable-next-line no-continue
if (filter && !filter(object[_key], _key)) continue;
var _value = result[_key] || [];
result[_key] = [].concat(_value, [object[_key]]);
}
}
return result;
}
function mergeFunctionsInObjects(objects) {
var object = reduceObjects(objects, function (value) {
return typeof value === "function";
});
var keys = Object.keys(object);
var result = {};
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
var key = _keys[_i];
var fns = object[key];
result[key] = fns.length === 1 ? fns[0] : fns.reduce(function (lastHook, currHook) {
return function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return currHook.apply(void 0, args.slice(0, -1).concat([lastHook.apply(void 0, args)]));
};
});
}
return result;
}
function mergeObjectsInObjects(systems) {
var object = reduceObjects(systems, isObject);
var keys = Object.keys(object);
var result = {};
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
var key = _keys2[_i2];
var values = object[key];
result[key] = Object.assign.apply(Object, [{}].concat(values));
}
return result;
}
/**
* Merges multiple system objects into a single system object.
*
* @example
* import { Provider } from "reakit";
* import { mergeSystem } from "reakit-system";
* import * as bootstrapSystem from "reakit-system-bootstrap";
*
* const mySystem = {
* useButtonProps() {},
* };
*
* const system = mergeSystem(bootstrapSystem, mySystem);
*
* function App() {
* return (
* <Provider unstable_system={system}>
* <div>App</div>
* </Provider>
* );
* }
*/
function mergeSystem() {
for (var _len2 = arguments.length, systems = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
systems[_key2] = arguments[_key2];
}
return Object.assign.apply(Object, [{}].concat(systems, [mergeObjectsInObjects(systems), mergeFunctionsInObjects(systems)]));
}
export { mergeSystem };

View File

@@ -0,0 +1,62 @@
import { useContext, createElement } from 'react';
import { SystemContext } from './SystemContext.js';
import { a as _objectWithoutPropertiesLoose } from './_rollupPluginBabelHelpers-0c84a174.js';
function isRenderProp(children) {
return typeof children === "function";
}
/**
* Custom hook that will call `children` if it's a function. If
* `useCreateElement` has been passed to the context, it'll be used instead.
*
* @example
* import React from "react";
* import { SystemProvider, useCreateElement } from "reakit-system";
*
* const system = {
* useCreateElement(type, props, children = props.children) {
* // very similar to what `useCreateElement` does already
* if (typeof children === "function") {
* const { children: _, ...rest } = props;
* return children(rest);
* }
* return React.createElement(type, props, children);
* },
* };
*
* function Component(props) {
* return useCreateElement("div", props);
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component url="url">{({ url }) => <a href={url}>link</a>}</Component>
* </SystemProvider>
* );
* }
*/
var useCreateElement = function useCreateElement(type, props, children) {
if (children === void 0) {
children = props.children;
}
var context = useContext(SystemContext);
if (context.useCreateElement) {
return context.useCreateElement(type, props, children);
}
if (typeof type === "string" && isRenderProp(children)) {
var _ = props.children,
rest = _objectWithoutPropertiesLoose(props, ["children"]);
return children(rest);
}
return /*#__PURE__*/createElement(type, props, children);
};
export { useCreateElement };

View File

@@ -0,0 +1,59 @@
import { useDebugValue } from 'react';
import './SystemContext.js';
import { useToken } from './useToken.js';
import { _ as _objectSpread2 } from './_rollupPluginBabelHelpers-0c84a174.js';
/**
* React custom hook that returns the options returned by a given
* `use${name}Options` in the SystemContext.
*
* @example
* import React from "react";
* import { SystemProvider, useOptions } from "reakit-system";
*
* const system = {
* useAOptions(options, htmlProps) {
* return {
* ...options,
* url: htmlProps.href,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const options = useOptions("A", { url }, htmlProps);
* return <a href={options.url} {...htmlProps} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A href="url">
* It will convert href into url in useAOptions and then url into href in A
* </A>
* </SystemProvider>
* );
* }
*/
function useOptions(name, options, htmlProps) {
if (options === void 0) {
options = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
var hookName = "use" + name + "Options";
useDebugValue(hookName);
var useHook = useToken(hookName);
if (useHook) {
return _objectSpread2(_objectSpread2({}, options), useHook(options, htmlProps));
}
return options;
}
export { useOptions };

View File

@@ -0,0 +1,55 @@
import { useDebugValue } from 'react';
import './SystemContext.js';
import { useToken } from './useToken.js';
/**
* React custom hook that returns the props returned by a given
* `use${name}Props` in the SystemContext.
*
* @example
* import { SystemProvider, useProps } from "reakit-system";
*
* const system = {
* useAProps(options, htmlProps) {
* return {
* ...htmlProps,
* href: options.url,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const props = useProps("A", { url }, htmlProps);
* return <a {...props} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A url="url">It will convert url into href in useAProps</A>
* </SystemProvider>
* );
* }
*/
function useProps(name, options, htmlProps) {
if (options === void 0) {
options = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
var hookName = "use" + name + "Props";
useDebugValue(hookName);
var useHook = useToken(hookName);
if (useHook) {
return useHook(options, htmlProps);
}
return htmlProps;
}
export { useProps };

View File

@@ -0,0 +1,36 @@
import { useDebugValue, useContext } from 'react';
import { SystemContext } from './SystemContext.js';
/**
* React custom hook that returns the value of any token defined in the
* SystemContext. It's mainly used internally in [`useOptions`](#useoptions)
* and [`useProps`](#useprops).
*
* @example
* import { SystemProvider, useToken } from "reakit-system";
*
* const system = {
* token: "value",
* };
*
* function Component(props) {
* const token = useToken("token", "default value");
* return <div {...props}>{token}</div>;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component />
* </SystemProvider>
* );
* }
*/
function useToken(token, defaultValue) {
useDebugValue(token);
var context = useContext(SystemContext);
return context[token] != null ? context[token] : defaultValue;
}
export { useToken };

View File

@@ -0,0 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var SystemContext = /*#__PURE__*/React.createContext({});
exports.SystemContext = SystemContext;

View File

@@ -0,0 +1,37 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var SystemContext = require('./SystemContext.js');
/**
* Provider component that is used by `reakit`'s `Provider` underneath.
*
* @example
* // instead of using
* import { Provider } from "reakit";
* // you can use this
* import { SystemProvider } from "reakit-system";
* // reakit's Provider has more features, such as ID generation
* import * as system from "reakit-system-bootstrap";
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <div>App</div>
* </SystemProvider>
* );
* }
*
* @param props
*/
function SystemProvider(_ref) {
var children = _ref.children,
system = _ref.unstable_system;
return /*#__PURE__*/React.createElement(SystemContext.SystemContext.Provider, {
value: system
}, children);
}
exports.SystemProvider = SystemProvider;

View File

@@ -0,0 +1,111 @@
'use strict';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
it = o[Symbol.iterator]();
return it.next.bind(it);
}
exports._createForOfIteratorHelperLoose = _createForOfIteratorHelperLoose;
exports._objectSpread2 = _objectSpread2;
exports._objectWithoutPropertiesLoose = _objectWithoutPropertiesLoose;

View File

@@ -0,0 +1,94 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
require('./SystemContext.js');
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-8f9a8751.js');
var useCreateElement = require('./useCreateElement.js');
var splitProps = require('reakit-utils/splitProps');
var shallowEqual = require('reakit-utils/shallowEqual');
var normalizePropsAreEqual = require('reakit-utils/normalizePropsAreEqual');
function forwardRef(component) {
return /*#__PURE__*/React.forwardRef(component);
}
function memo(component, propsAreEqual) {
return /*#__PURE__*/React.memo(component, propsAreEqual);
}
/**
* Creates a React component.
*
* @example
* import { createComponent } from "reakit-system";
*
* const A = createComponent({ as: "a" });
*
* @param options
*/
function createComponent(_ref) {
var type = _ref.as,
useHook = _ref.useHook,
shouldMemo = _ref.memo,
_ref$propsAreEqual = _ref.propsAreEqual,
propsAreEqual = _ref$propsAreEqual === void 0 ? useHook === null || useHook === void 0 ? void 0 : useHook.unstable_propsAreEqual : _ref$propsAreEqual,
_ref$keys = _ref.keys,
keys = _ref$keys === void 0 ? (useHook === null || useHook === void 0 ? void 0 : useHook.__keys) || [] : _ref$keys,
_ref$useCreateElement = _ref.useCreateElement,
useCreateElement$1 = _ref$useCreateElement === void 0 ? useCreateElement.useCreateElement : _ref$useCreateElement;
var Comp = function Comp(_ref2, ref) {
var _ref2$as = _ref2.as,
as = _ref2$as === void 0 ? type : _ref2$as,
props = _rollupPluginBabelHelpers._objectWithoutPropertiesLoose(_ref2, ["as"]);
if (useHook) {
var _as$render;
var _splitProps = splitProps.splitProps(props, keys),
_options = _splitProps[0],
htmlProps = _splitProps[1];
var _useHook = useHook(_options, _rollupPluginBabelHelpers._objectSpread2({
ref: ref
}, htmlProps)),
wrapElement = _useHook.wrapElement,
elementProps = _rollupPluginBabelHelpers._objectWithoutPropertiesLoose(_useHook, ["wrapElement"]); // @ts-ignore
var asKeys = ((_as$render = as.render) === null || _as$render === void 0 ? void 0 : _as$render.__keys) || as.__keys;
var asOptions = asKeys && splitProps.splitProps(props, asKeys)[0];
var allProps = asOptions ? _rollupPluginBabelHelpers._objectSpread2(_rollupPluginBabelHelpers._objectSpread2({}, elementProps), asOptions) : elementProps;
var _element = useCreateElement$1(as, allProps);
if (wrapElement) {
return wrapElement(_element);
}
return _element;
}
return useCreateElement$1(as, _rollupPluginBabelHelpers._objectSpread2({
ref: ref
}, props));
};
if (process.env.NODE_ENV !== "production" && useHook) {
Comp.displayName = useHook.name.replace(/^(unstable_)?use/, "");
}
Comp = forwardRef(Comp);
if (shouldMemo) {
Comp = memo(Comp, propsAreEqual && normalizePropsAreEqual.normalizePropsAreEqual(propsAreEqual));
}
Comp.__keys = keys;
Comp.unstable_propsAreEqual = normalizePropsAreEqual.normalizePropsAreEqual(propsAreEqual || shallowEqual.shallowEqual);
return Comp;
}
exports.createComponent = createComponent;

View File

@@ -0,0 +1,139 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
require('react');
require('./SystemContext.js');
require('./useToken.js');
var useProps = require('./useProps.js');
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-8f9a8751.js');
var useOptions = require('./useOptions.js');
var shallowEqual = require('reakit-utils/shallowEqual');
var toArray = require('reakit-utils/toArray');
/**
* Creates a React custom hook that will return component props.
*
* @example
* import { createHook } from "reakit-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
*/
function createHook(options) {
var _options$useState, _composedHooks$;
var composedHooks = toArray.toArray(options.compose);
var __useOptions = function __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) {
hookOptions = useOptions.useOptions(options.name, hookOptions, htmlProps);
} // Run composed hooks useOptions
if (options.compose) {
for (var _iterator = _rollupPluginBabelHelpers._createForOfIteratorHelperLoose(composedHooks), _step; !(_step = _iterator()).done;) {
var hook = _step.value;
hookOptions = hook.__useOptions(hookOptions, htmlProps);
}
}
return hookOptions;
};
var useHook = function useHook(hookOptions, htmlProps, unstable_ignoreUseOptions) {
if (hookOptions === void 0) {
hookOptions = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
if (unstable_ignoreUseOptions === void 0) {
unstable_ignoreUseOptions = 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) {
htmlProps = useProps.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 _iterator2 = _rollupPluginBabelHelpers._createForOfIteratorHelperLoose(composedHooks), _step2; !(_step2 = _iterator2()).done;) {
var hook = _step2.value;
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(function (keys, hook) {
keys.push.apply(keys, hook.__keys || []);
return keys;
}, []); // It's used by createComponent to split option props (keys) and html props
useHook.__keys = [].concat(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.shallowEqual;
if (process.env.NODE_ENV !== "production" && options.name) {
Object.defineProperty(useHook, "name", {
value: "use" + options.name
});
}
return useHook;
}
exports.createHook = createHook;

View File

@@ -0,0 +1,32 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
require('react');
var SystemContext = require('./SystemContext.js');
var useToken = require('./useToken.js');
var useProps = require('./useProps.js');
require('./_rollupPluginBabelHelpers-8f9a8751.js');
var useOptions = require('./useOptions.js');
var useCreateElement = require('./useCreateElement.js');
require('reakit-utils/isObject');
var mergeSystem = require('./mergeSystem.js');
require('reakit-utils/splitProps');
require('reakit-utils/shallowEqual');
require('reakit-utils/normalizePropsAreEqual');
var createComponent = require('./createComponent.js');
require('reakit-utils/toArray');
var createHook = require('./createHook.js');
var SystemProvider = require('./SystemProvider.js');
exports.SystemContext = SystemContext.SystemContext;
exports.useToken = useToken.useToken;
exports.useProps = useProps.useProps;
exports.useOptions = useOptions.useOptions;
exports.useCreateElement = useCreateElement.useCreateElement;
exports.mergeSystem = mergeSystem.mergeSystem;
exports.createComponent = createComponent.createComponent;
exports.createHook = createHook.createHook;
exports.SystemProvider = SystemProvider.SystemProvider;

View File

@@ -0,0 +1,101 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-8f9a8751.js');
var isObject = require('reakit-utils/isObject');
/**
* Transforms [{ a: "a" }, { a: "b" }] into { a: ["a", "b"] }
*/
function reduceObjects(objects, filter) {
var result = {};
for (var _iterator = _rollupPluginBabelHelpers._createForOfIteratorHelperLoose(objects), _step; !(_step = _iterator()).done;) {
var object = _step.value;
var keys = Object.keys(object);
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
var _key = _keys[_i];
// eslint-disable-next-line no-continue
if (filter && !filter(object[_key], _key)) continue;
var _value = result[_key] || [];
result[_key] = [].concat(_value, [object[_key]]);
}
}
return result;
}
function mergeFunctionsInObjects(objects) {
var object = reduceObjects(objects, function (value) {
return typeof value === "function";
});
var keys = Object.keys(object);
var result = {};
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
var key = _keys[_i];
var fns = object[key];
result[key] = fns.length === 1 ? fns[0] : fns.reduce(function (lastHook, currHook) {
return function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return currHook.apply(void 0, args.slice(0, -1).concat([lastHook.apply(void 0, args)]));
};
});
}
return result;
}
function mergeObjectsInObjects(systems) {
var object = reduceObjects(systems, isObject.isObject);
var keys = Object.keys(object);
var result = {};
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
var key = _keys2[_i2];
var values = object[key];
result[key] = Object.assign.apply(Object, [{}].concat(values));
}
return result;
}
/**
* Merges multiple system objects into a single system object.
*
* @example
* import { Provider } from "reakit";
* import { mergeSystem } from "reakit-system";
* import * as bootstrapSystem from "reakit-system-bootstrap";
*
* const mySystem = {
* useButtonProps() {},
* };
*
* const system = mergeSystem(bootstrapSystem, mySystem);
*
* function App() {
* return (
* <Provider unstable_system={system}>
* <div>App</div>
* </Provider>
* );
* }
*/
function mergeSystem() {
for (var _len2 = arguments.length, systems = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
systems[_key2] = arguments[_key2];
}
return Object.assign.apply(Object, [{}].concat(systems, [mergeObjectsInObjects(systems), mergeFunctionsInObjects(systems)]));
}
exports.mergeSystem = mergeSystem;

View File

@@ -0,0 +1,66 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var SystemContext = require('./SystemContext.js');
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-8f9a8751.js');
function isRenderProp(children) {
return typeof children === "function";
}
/**
* Custom hook that will call `children` if it's a function. If
* `useCreateElement` has been passed to the context, it'll be used instead.
*
* @example
* import React from "react";
* import { SystemProvider, useCreateElement } from "reakit-system";
*
* const system = {
* useCreateElement(type, props, children = props.children) {
* // very similar to what `useCreateElement` does already
* if (typeof children === "function") {
* const { children: _, ...rest } = props;
* return children(rest);
* }
* return React.createElement(type, props, children);
* },
* };
*
* function Component(props) {
* return useCreateElement("div", props);
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component url="url">{({ url }) => <a href={url}>link</a>}</Component>
* </SystemProvider>
* );
* }
*/
var useCreateElement = function useCreateElement(type, props, children) {
if (children === void 0) {
children = props.children;
}
var context = React.useContext(SystemContext.SystemContext);
if (context.useCreateElement) {
return context.useCreateElement(type, props, children);
}
if (typeof type === "string" && isRenderProp(children)) {
var _ = props.children,
rest = _rollupPluginBabelHelpers._objectWithoutPropertiesLoose(props, ["children"]);
return children(rest);
}
return /*#__PURE__*/React.createElement(type, props, children);
};
exports.useCreateElement = useCreateElement;

View File

@@ -0,0 +1,63 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
require('./SystemContext.js');
var useToken = require('./useToken.js');
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-8f9a8751.js');
/**
* React custom hook that returns the options returned by a given
* `use${name}Options` in the SystemContext.
*
* @example
* import React from "react";
* import { SystemProvider, useOptions } from "reakit-system";
*
* const system = {
* useAOptions(options, htmlProps) {
* return {
* ...options,
* url: htmlProps.href,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const options = useOptions("A", { url }, htmlProps);
* return <a href={options.url} {...htmlProps} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A href="url">
* It will convert href into url in useAOptions and then url into href in A
* </A>
* </SystemProvider>
* );
* }
*/
function useOptions(name, options, htmlProps) {
if (options === void 0) {
options = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
var hookName = "use" + name + "Options";
React.useDebugValue(hookName);
var useHook = useToken.useToken(hookName);
if (useHook) {
return _rollupPluginBabelHelpers._objectSpread2(_rollupPluginBabelHelpers._objectSpread2({}, options), useHook(options, htmlProps));
}
return options;
}
exports.useOptions = useOptions;

View File

@@ -0,0 +1,59 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
require('./SystemContext.js');
var useToken = require('./useToken.js');
/**
* React custom hook that returns the props returned by a given
* `use${name}Props` in the SystemContext.
*
* @example
* import { SystemProvider, useProps } from "reakit-system";
*
* const system = {
* useAProps(options, htmlProps) {
* return {
* ...htmlProps,
* href: options.url,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const props = useProps("A", { url }, htmlProps);
* return <a {...props} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A url="url">It will convert url into href in useAProps</A>
* </SystemProvider>
* );
* }
*/
function useProps(name, options, htmlProps) {
if (options === void 0) {
options = {};
}
if (htmlProps === void 0) {
htmlProps = {};
}
var hookName = "use" + name + "Props";
React.useDebugValue(hookName);
var useHook = useToken.useToken(hookName);
if (useHook) {
return useHook(options, htmlProps);
}
return htmlProps;
}
exports.useProps = useProps;

View File

@@ -0,0 +1,40 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var SystemContext = require('./SystemContext.js');
/**
* React custom hook that returns the value of any token defined in the
* SystemContext. It's mainly used internally in [`useOptions`](#useoptions)
* and [`useProps`](#useprops).
*
* @example
* import { SystemProvider, useToken } from "reakit-system";
*
* const system = {
* token: "value",
* };
*
* function Component(props) {
* const token = useToken("token", "default value");
* return <div {...props}>{token}</div>;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component />
* </SystemProvider>
* );
* }
*/
function useToken(token, defaultValue) {
React.useDebugValue(token);
var context = React.useContext(SystemContext.SystemContext);
return context[token] != null ? context[token] : defaultValue;
}
exports.useToken = useToken;

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/mergeSystem",
"private": true,
"sideEffects": false,
"main": "../lib/mergeSystem",
"module": "../es/mergeSystem",
"types": "../ts/mergeSystem"
}

View File

@@ -0,0 +1,41 @@
{
"name": "reakit-system",
"version": "0.15.2",
"description": "Reakit System utils",
"sideEffects": false,
"license": "MIT",
"repository": "https://github.com/reakit/reakit/tree/master/packages/reakit-system",
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/reakit-system.min.js",
"types": "ts",
"author": {
"name": "Diego Haz",
"email": "hazdiego@gmail.com",
"url": "https://github.com/diegohaz"
},
"scripts": {
"test": "jest",
"coverage": "yarn test --coverage",
"postcoverage": "open-cli coverage/lcov-report/index.html",
"lint": "eslint . --ext js,ts,tsx",
"clean": "node ../../scripts/build/clean.js",
"build": "node ../../scripts/build/build.js",
"docs": "documentation readme src/*.{ts,tsx} --markdown-toc-max-depth=2 --section=API --parse-extension ts --parse-extension tsx",
"preversion": "yarn lint && yarn test && yarn docs && yarn build",
"postpublish": "yarn clean"
},
"keywords": [
"reakit",
"react",
"system"
],
"dependencies": {
"reakit-utils": "^0.15.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
},
"gitHead": "e30e656b303f014fb841893c003aac2a5a5ac6fa"
}

View File

@@ -0,0 +1,9 @@
import * as React from "react";
import { useCreateElement } from "./useCreateElement";
export type SystemContextType = {
useCreateElement?: typeof useCreateElement;
[key: string]: any;
};
export const SystemContext = React.createContext<SystemContextType>({});

View File

@@ -0,0 +1,37 @@
import * as React from "react";
import { SystemContextType, SystemContext } from "./SystemContext";
export type SystemProviderProps = {
children: React.ReactNode;
unstable_system: SystemContextType;
};
/**
* Provider component that is used by `reakit`'s `Provider` underneath.
*
* @example
* // instead of using
* import { Provider } from "reakit";
* // you can use this
* import { SystemProvider } from "reakit-system";
* // reakit's Provider has more features, such as ID generation
* import * as system from "reakit-system-bootstrap";
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <div>App</div>
* </SystemProvider>
* );
* }
*
* @param props
*/
export function SystemProvider({
children,
unstable_system: system,
}: SystemProviderProps) {
return (
<SystemContext.Provider value={system}>{children}</SystemContext.Provider>
);
}

View File

@@ -0,0 +1,106 @@
import * as React from "react";
import { render } from "reakit-test-utils";
import { createComponent } from "../createComponent";
test("keys", () => {
const useHook = ({ children }: { children: string }) => ({ children });
useHook.__keys = ["children"] as const;
const Component = createComponent({ as: "div", useHook });
const { getByText } = render(<Component>component</Component>);
expect(getByText("component")).toBeDefined();
});
test("as string", () => {
const useA = ({ a }: { a: string }) => ({ children: a });
useA.__keys = ["a"] as const;
const A = createComponent({ as: "div", useHook: useA });
const { getByText } = render(<A as="span" a="a" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<span>
a
</span>
`);
});
test("as component", () => {
const useA = ({ a }: { a: string }, htmlProps: any) => ({
children: a,
...htmlProps,
});
useA.__keys = ["a"] as const;
const A = createComponent({ as: "div", useHook: useA });
const B = ({ b, ...props }: { b: string }) => <div id={b} {...props} />;
const { getByText } = render(<A as={B} a="a" b="b" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<div
id="b"
>
a
</div>
`);
});
test("as generic component", () => {
const useA = ({ a }: { a: string }, htmlProps: any) => ({
children: a,
...htmlProps,
});
useA.__keys = ["a"] as const;
const A = createComponent({ as: "div", useHook: useA });
function B<T extends string>({ b, ...props }: { b: T }) {
return <div id={b} {...props} />;
}
const { getByText } = render(<A as={B} a="a" b="b" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<div
id="b"
>
a
</div>
`);
});
test("as other component created with createComponent", () => {
const useA = ({ a }: { a: string }, h: any) => ({ children: a, ...h });
useA.__keys = ["a"] as const;
const A = createComponent({ as: "div", useHook: useA });
const useB = ({ b }: { b: string }, h: any) => ({ id: b, ...h });
useB.__keys = ["b"] as const;
const B = createComponent({ as: "div", useHook: useB });
const { getByText } = render(<A as={B} a="a" b="b" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<div
id="b"
>
a
</div>
`);
});
test("wrap", () => {
const useA = (_: any, h: any) => ({
wrapElement: (element: React.ReactNode) => (
<div id="wrapper">{element}</div>
),
...h,
});
const A = createComponent({ as: "span", useHook: useA });
const { baseElement } = render(<A id="a">a</A>);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
id="wrapper"
>
<span
id="a"
>
a
</span>
</div>
</div>
</body>
`);
});

View File

@@ -0,0 +1,234 @@
import * as React from "react";
import { render } from "reakit-test-utils";
import { createHook } from "../createHook";
import { SystemProvider } from "../SystemProvider";
type Options = {
a: string;
};
test("useProps", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
useProps(options, htmlProps) {
return {
...htmlProps,
"data-a": options.a,
};
},
});
expect(useHook({ a: "a" }, { id: "a" })).toMatchInlineSnapshot(`
Object {
"data-a": "a",
"id": "a",
}
`);
});
test("useProps undefined props", () => {
const useHook = createHook<{}, React.HTMLAttributes<any>>({
useProps(_, htmlProps) {
return {
...htmlProps,
"data-a": undefined,
};
},
});
expect(useHook({}, { id: "a" })).toMatchInlineSnapshot(`
Object {
"id": "a",
}
`);
});
test("compose useProps", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
useProps(options, htmlProps) {
return {
...htmlProps,
"data-a": options.a,
};
},
});
type Options2 = Options & {
b: string;
};
const useHook2 = createHook<Options2, React.HTMLAttributes<any>>({
compose: [useHook],
useProps(options, htmlProps) {
return {
...htmlProps,
"data-b": options.b,
};
},
});
expect(useHook2({ a: "a", b: "b" }, { id: "a" })).toMatchInlineSnapshot(`
Object {
"data-a": "a",
"data-b": "b",
"id": "a",
}
`);
});
test("useOptions", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
useOptions(options) {
return {
...options,
a: "a",
};
},
useProps(options, htmlProps) {
return {
...htmlProps,
id: options.a,
};
},
});
expect(useHook()).toEqual({ id: "a" });
});
test("compose useOptions", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
useOptions(options) {
return {
...options,
a: `${options.a}b`,
};
},
});
const useHook2 = createHook<Options, React.HTMLAttributes<any>>({
compose: [useHook],
useOptions(options) {
return {
...options,
a: "a",
};
},
useProps(options, htmlProps) {
return {
...htmlProps,
id: options.a,
};
},
});
expect(useHook2()).toEqual({ id: "ab" });
});
test("useComposeOptions", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
useProps(options, htmlProps) {
return {
...htmlProps,
id: `${options.a}b`,
};
},
});
const useHook2 = createHook<Options, React.HTMLAttributes<any>>({
compose: [useHook],
useComposeOptions(options) {
return { ...options, a: "a" };
},
});
expect(useHook2()).toEqual({ id: "ab" });
});
test("name", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({ name: "A" });
expect(useHook.name).toBe("useA");
});
test("name and context", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({ name: "A" });
const Test = () => {
return <div {...useHook()} />;
};
const system = {
useAProps: (_: Options, htmlProps: React.HTMLAttributes<any>) => ({
...htmlProps,
id: "a",
}),
};
const { baseElement } = render(
<SystemProvider unstable_system={system}>
<Test />
</SystemProvider>
);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
id="a"
/>
</div>
</body>
`);
});
test("name and context with useProps", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
name: "A",
useProps(_, htmlProps) {
return { className: "a", ...htmlProps };
},
});
const Test = () => {
return <div {...useHook()} />;
};
const system = {
useAProps: (_: Options, htmlProps: React.HTMLAttributes<any>) => ({
...htmlProps,
id: "a",
}),
};
const { baseElement } = render(
<SystemProvider unstable_system={system}>
<Test />
</SystemProvider>
);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
class="a"
id="a"
/>
</div>
</body>
`);
});
test("name and context with useOptions", () => {
const useHook = createHook<Options, React.HTMLAttributes<any>>({
name: "A",
useOptions(options) {
return {
...options,
a: "a",
};
},
});
const Test = () => {
return <div {...useHook()} />;
};
const system = {
useAProps: (options: Options, htmlProps: React.HTMLAttributes<any>) => ({
...htmlProps,
id: options.a,
}),
};
const { baseElement } = render(
<SystemProvider unstable_system={system}>
<Test />
</SystemProvider>
);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
id="a"
/>
</div>
</body>
`);
});

View File

@@ -0,0 +1,82 @@
import { mergeSystem } from "../mergeSystem";
test("single primitive prop", () => {
const system = { a: "a" };
const merged = mergeSystem(system, {});
expect(merged.a).toBe("a");
});
test("different primitive props", () => {
const system1 = { a: "a" };
const system2 = { b: "b" };
const merged = mergeSystem(system1, system2);
expect(merged.a).toBe("a");
expect(merged.b).toBe("b");
});
test("same primitive props with different values", () => {
const system1 = { a: "a" };
const system2 = { a: "b" };
const merged = mergeSystem(system1, system2);
expect(merged.a).toBe("b");
});
test("single object prop", () => {
const system = { a: { a: "a" } };
const merged = mergeSystem(system, {});
expect(merged.a.a).toBe("a");
});
test("different object props", () => {
const system1 = { a: { a: "a" } };
const system2 = { b: { b: "b" } };
const merged = mergeSystem(system1, system2);
expect(merged.a.a).toBe("a");
expect(merged.b.b).toBe("b");
});
test("same object props with different values", () => {
const system1 = { a: { a: "a" } };
const system2 = { a: { b: "b" } };
const merged = mergeSystem(system1, system2);
expect(merged.a.a).toBe("a");
expect(merged.a.b).toBe("b");
});
test("same object props with intersection values", () => {
const system1 = { a: { a: "a" } };
const system2 = { a: { a: "b", b: "b" } };
const merged = mergeSystem(system1, system2);
expect(merged.a.a).toBe("b");
expect(merged.a.b).toBe("b");
});
test("single function props", () => {
const system = { fn: jest.fn() };
const merged = mergeSystem(system, {});
expect(merged.fn).toBe(system.fn);
merged.fn(1, 2, 3, 4, 5);
expect(system.fn).toBeCalledWith(1, 2, 3, 4, 5);
});
test("different function props", () => {
const system1 = { fn1: jest.fn() };
const system2 = { fn2: jest.fn() };
const merged = mergeSystem(system1, system2);
expect(merged.fn1).toBe(system1.fn1);
expect(merged.fn2).toBe(system2.fn2);
merged.fn1(1, 2, 3, 4, 5);
merged.fn2(1, 2, 3, 4, 5);
expect(system1.fn1).toBeCalledWith(1, 2, 3, 4, 5);
expect(system2.fn2).toBeCalledWith(1, 2, 3, 4, 5);
});
test("same function props with different values", () => {
const impl = (a: number, b: number, c: number) => a + b + c;
const system1 = { fn: jest.fn(impl) };
const system2 = { fn: jest.fn(impl) };
const merged = mergeSystem(system1, system2);
merged.fn(1, 2, 3);
expect(system1.fn).toBeCalledWith(1, 2, 3);
expect(system2.fn).toBeCalledWith(1, 2, 6);
});

View File

@@ -0,0 +1,78 @@
import * as React from "react";
import { render } from "reakit-test-utils";
import { createComponent } from "../createComponent";
test("as string", () => {
const useA = ({ a }: { a: string }) => ({ children: a });
const A = createComponent({ as: "div", useHook: useA });
const { getByText } = render(<A as="span" state={{ a: "a" }} />);
expect(getByText("a")).toMatchInlineSnapshot(`
<span>
a
</span>
`);
});
test("as component", () => {
const useA = ({ a }: { a: string }, htmlProps: any) => ({
children: a,
...htmlProps,
});
const A = createComponent({ as: "div", useHook: useA });
const B = ({ b, state, ...props }: { state: any; b: string }) => (
<div id={b} {...props} />
);
const { getByText } = render(<A as={B} state={{ a: "a" }} b="b" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<div
id="b"
>
a
</div>
`);
});
test("as generic component", () => {
const useA = ({ a }: { a: string }, htmlProps: any) => ({
children: a,
...htmlProps,
});
const A = createComponent({ as: "div", useHook: useA });
function B<T extends string>({ b, state, ...props }: { state: any; b: T }) {
return <div id={b} {...props} />;
}
const { getByText } = render(<A as={B} state={{ a: "a" }} b="b" />);
expect(getByText("a")).toMatchInlineSnapshot(`
<div
id="b"
>
a
</div>
`);
});
test("wrap", () => {
const useA = (_: any, h: any) => ({
wrapElement: (element: React.ReactNode) => (
<div id="wrapper">{element}</div>
),
...h,
});
const A = createComponent({ as: "span", useHook: useA });
const { baseElement } = render(<A id="a">a</A>);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
id="wrapper"
>
<span
id="a"
>
a
</span>
</div>
</div>
</body>
`);
});

View File

@@ -0,0 +1,78 @@
import * as React from "react";
import { render } from "reakit-test-utils";
import { renderHook } from "reakit-test-utils/hooks";
import { Provider } from "reakit/Provider";
import { useCreateElement } from "../useCreateElement";
test("useCreateElement", () => {
const { result } = renderHook(() =>
useCreateElement("div", { a: "a" }, "div")
);
expect(result.current).toMatchInlineSnapshot(`
<div
a="a"
>
div
</div>
`);
});
test("render props", () => {
const { result } = renderHook(() =>
useCreateElement("div", { a: "a" }, ({ a }: { a: string }) => (
<div id={a}>div</div>
))
);
expect(result.current).toMatchInlineSnapshot(`
<div
id="a"
>
div
</div>
`);
});
test("render props with component type", () => {
type HTMLProps = React.HTMLAttributes<any>;
type AProps = { children: (props: HTMLProps) => React.ReactElement };
const A = ({ children }: AProps) => children({ className: "a" });
const B = () =>
useCreateElement(A, {}, (props: HTMLProps) => <div {...props}>a</div>);
const { container } = render(<B />);
expect(container).toMatchInlineSnapshot(`
<div>
<div
class="a"
>
a
</div>
</div>
`);
});
test("context", () => {
const { result } = renderHook(
() => useCreateElement("div", { a: "a" }, "div"),
{
wrapper: ({ children }) => (
<Provider
unstable_system={{
useCreateElement: (_, props, c) => <p {...props}>{c}</p>,
}}
>
{children}
</Provider>
),
}
);
expect(result.current).toMatchInlineSnapshot(`
<p
a="a"
>
div
</p>
`);
});

View File

@@ -0,0 +1,35 @@
import * as React from "react";
import { renderHook } from "reakit-test-utils/hooks";
import { useProps } from "../useProps";
import { SystemProvider, SystemProviderProps } from "../SystemProvider";
import { SystemContextType } from "../SystemContext";
function render(
system: SystemContextType,
...args: Parameters<typeof useProps>
) {
return renderHook(() => useProps(...args), {
wrapper: (props: SystemProviderProps) => (
<SystemProvider
{...props}
unstable_system={props.unstable_system || system}
/>
),
}).result;
}
test("useProps", () => {
const result = render(
{
useAProps: (options: { a: string }) => options.a,
},
"A",
{ a: "a" }
);
expect(result.current).toBe("a");
});
test("default return", () => {
const result = render({}, "A", undefined, { id: "id" });
expect(result.current).toEqual({ id: "id" });
});

View File

@@ -0,0 +1,29 @@
import * as React from "react";
import { renderHook } from "reakit-test-utils/hooks";
import { useToken } from "../useToken";
import { SystemProvider, SystemProviderProps } from "../SystemProvider";
import { SystemContextType } from "../SystemContext";
function render(
system: SystemContextType,
...args: Parameters<typeof useToken>
) {
return renderHook(() => useToken(...args), {
wrapper: (props: SystemProviderProps) => (
<SystemProvider
{...props}
unstable_system={props.unstable_system || system}
/>
),
}).result;
}
test("useToken", () => {
const result = render({ a: "a" }, "a");
expect(result.current).toBe("a");
});
test("default value", () => {
const result = render({ a: "a" }, "b", "b");
expect(result.current).toBe("b");
});

View File

@@ -0,0 +1,6 @@
import { isRenderProp } from "../isRenderProp";
test("isRenderProp", () => {
expect(isRenderProp("a")).toBe(false);
expect(isRenderProp(() => {})).toBe(true);
});

View File

@@ -0,0 +1,13 @@
import { reduceObjects } from "../reduceObjects";
test("reduceObjects", () => {
expect(reduceObjects([{ a: "a" }, { a: "b" }])).toEqual({ a: ["a", "b"] });
expect(
reduceObjects(
[{ a: "a" }, { a: "b" }],
(val, key) => key === "a" && val === "a"
)
).toEqual({
a: ["a"],
});
});

View File

@@ -0,0 +1,7 @@
import * as React from "react";
export function forwardRef<T extends React.ForwardRefRenderFunction<any, any>>(
component: T
) {
return (React.forwardRef(component) as unknown) as T;
}

View File

@@ -0,0 +1,5 @@
import { RenderProp } from "reakit-utils/types";
export function isRenderProp(children: any): children is RenderProp {
return typeof children === "function";
}

View File

@@ -0,0 +1,11 @@
import * as React from "react";
export function memo<T extends React.ComponentType<any>>(
component: T,
propsAreEqual?: (
prevProps: Readonly<React.ComponentProps<T>>,
nextProps: Readonly<React.ComponentProps<T>>
) => boolean
) {
return (React.memo(component, propsAreEqual) as unknown) as T;
}

View File

@@ -0,0 +1,21 @@
/**
* Transforms [{ a: "a" }, { a: "b" }] into { a: ["a", "b"] }
*/
export function reduceObjects<T extends Record<string, any>>(
objects: T[],
filter?: (value: T[keyof T], key: keyof T) => boolean
) {
const result = {} as { [K in keyof T]?: Array<T[K]> };
for (const object of objects) {
const keys = Object.keys(object) as Array<keyof T>;
for (const key of keys) {
// eslint-disable-next-line no-continue
if (filter && !filter(object[key], key)) continue;
const value = (result[key] || []) as Array<T[keyof T]>;
result[key] = [...value, object[key]];
}
}
return result;
}

View File

@@ -0,0 +1,105 @@
import * as React from "react";
import { As, PropsWithAs } from "reakit-utils/types";
import { splitProps } from "reakit-utils/splitProps";
import { shallowEqual } from "reakit-utils/shallowEqual";
import { normalizePropsAreEqual } from "reakit-utils/normalizePropsAreEqual";
import { forwardRef } from "./__utils/forwardRef";
import { useCreateElement as defaultUseCreateElement } from "./useCreateElement";
import { memo } from "./__utils/memo";
type RoleHTMLProps = React.HTMLAttributes<any> &
React.RefAttributes<any> & {
wrapElement?: (element: React.ReactNode) => React.ReactNode;
};
type Hook<O> = {
(options?: O, props?: RoleHTMLProps): RoleHTMLProps;
unstable_propsAreEqual?: (prev: O, next: O) => boolean;
__keys?: ReadonlyArray<any>;
};
type Options<T extends As, O> = {
as: T;
useHook?: Hook<O>;
keys?: ReadonlyArray<any>;
memo?: boolean;
propsAreEqual?: (prev: O, next: O) => boolean;
useCreateElement?: (
type: T,
props: Omit<PropsWithAs<O, T>, "as">,
children?: React.ReactNode
) => JSX.Element;
};
export type Component<T extends As, O> = {
<TT extends As>(props: PropsWithAs<O, TT> & { as: TT }): JSX.Element;
(props: PropsWithAs<O, T>): JSX.Element;
displayName?: string;
unstable_propsAreEqual: (
prev: PropsWithAs<O, T>,
next: PropsWithAs<O, T>
) => boolean;
__keys?: ReadonlyArray<any>;
};
/**
* Creates a React component.
*
* @example
* import { createComponent } from "reakit-system";
*
* const A = createComponent({ as: "a" });
*
* @param options
*/
export function createComponent<T extends As, O>({
as: type,
useHook,
memo: shouldMemo,
propsAreEqual = useHook?.unstable_propsAreEqual,
keys = useHook?.__keys || [],
useCreateElement = defaultUseCreateElement,
}: Options<T, O>) {
let Comp = ((
{ as = type, ...props }: PropsWithAs<O, T>,
ref: React.Ref<T>
) => {
if (useHook) {
const [options, htmlProps] = splitProps(props, keys);
const { wrapElement, ...elementProps } = useHook(options, {
ref,
...htmlProps,
});
// @ts-ignore
const asKeys = as.render?.__keys || as.__keys;
const asOptions = asKeys && splitProps(props, asKeys)[0];
const allProps = asOptions
? { ...elementProps, ...asOptions }
: elementProps;
const element = useCreateElement(as, allProps as typeof props);
if (wrapElement) {
return wrapElement(element);
}
return element;
}
return useCreateElement(as, { ref, ...props });
}) as Component<T, O>;
if (process.env.NODE_ENV !== "production" && useHook) {
Comp.displayName = useHook.name.replace(/^(unstable_)?use/, "");
}
Comp = forwardRef(Comp);
if (shouldMemo) {
Comp = memo(Comp, propsAreEqual && normalizePropsAreEqual(propsAreEqual));
}
Comp.__keys = keys;
Comp.unstable_propsAreEqual = normalizePropsAreEqual(
propsAreEqual || shallowEqual
);
return Comp;
}

View File

@@ -0,0 +1,136 @@
import { toArray } from "reakit-utils/toArray";
import { shallowEqual } from "reakit-utils/shallowEqual";
import { useOptions } from "./useOptions";
import { useProps } from "./useProps";
type Hook<O = any, P = any> = {
(options?: O, htmlProps?: P, unstable_ignoreUseOptions?: boolean): P;
unstable_propsAreEqual: (prev: O & P, next: O & P) => boolean;
__keys: ReadonlyArray<any>;
__useOptions: (options: O, htmlProps: P) => O;
};
type CreateHookOptions<O, P> = {
name?: string;
compose?: Hook | Hook[];
useState?: { (): any; __keys: ReadonlyArray<any> };
useOptions?: (options: O, htmlProps: P) => O;
useProps?: (options: O, htmlProps: P) => P;
useComposeOptions?: (options: O, htmlProps: P) => O;
useComposeProps?: (options: O, htmlProps: P) => P;
propsAreEqual?: (prev: O & P, next: O & P) => boolean;
keys?: ReadonlyArray<string>;
};
/**
* Creates a React custom hook that will return component props.
*
* @example
* import { createHook } from "reakit-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<O, P>(options: CreateHookOptions<O, P>) {
const composedHooks = toArray(options.compose) as Hook[];
const __useOptions = (hookOptions: O, htmlProps: P) => {
// 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) {
hookOptions = useOptions(options.name, hookOptions, htmlProps);
}
// Run composed hooks useOptions
if (options.compose) {
for (const hook of composedHooks) {
hookOptions = hook.__useOptions(hookOptions, htmlProps);
}
}
return hookOptions;
};
const useHook: Hook<O, P> = (
hookOptions = {} as O,
htmlProps = {} as P,
unstable_ignoreUseOptions = 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) {
htmlProps = useProps(options.name, hookOptions, htmlProps) as P;
}
if (options.compose) {
if (options.useComposeOptions) {
hookOptions = options.useComposeOptions(hookOptions, htmlProps);
}
if (options.useComposeProps) {
htmlProps = options.useComposeProps(hookOptions, htmlProps);
} else {
for (const hook of composedHooks) {
htmlProps = hook(hookOptions, htmlProps, true);
}
}
}
// Remove undefined values from htmlProps
const finalHTMLProps = {} as P;
const definedHTMLProps = htmlProps || ({} as P);
for (const prop in definedHTMLProps) {
if (definedHTMLProps[prop] !== undefined) {
finalHTMLProps[prop] = definedHTMLProps[prop];
}
}
return finalHTMLProps;
};
useHook.__useOptions = __useOptions;
const composedKeys = composedHooks.reduce((keys, hook) => {
keys.push(...(hook.__keys || []));
return keys;
}, [] as string[]);
// It's used by createComponent to split option props (keys) and html props
useHook.__keys = [
...composedKeys,
...(options.useState?.__keys || []),
...(options.keys || []),
];
useHook.unstable_propsAreEqual =
options.propsAreEqual ||
composedHooks[0]?.unstable_propsAreEqual ||
shallowEqual;
if (process.env.NODE_ENV !== "production" && options.name) {
Object.defineProperty(useHook, "name", {
value: `use${options.name}`,
});
}
return useHook;
}

View File

@@ -0,0 +1,9 @@
export * from "./createComponent";
export * from "./createHook";
export * from "./mergeSystem";
export * from "./SystemContext";
export * from "./SystemProvider";
export * from "./useCreateElement";
export * from "./useOptions";
export * from "./useProps";
export * from "./useToken";

View File

@@ -0,0 +1,66 @@
import { isObject } from "reakit-utils/isObject";
import { UnionToIntersection } from "reakit-utils/types";
import { reduceObjects } from "./__utils/reduceObjects";
import { SystemContextType } from "./SystemContext";
function mergeFunctionsInObjects(objects: Array<Record<string, any>>) {
const object = reduceObjects(objects, (value) => typeof value === "function");
const keys = Object.keys(object);
const result: Record<string, any> = {};
for (const key of keys) {
const fns = object[key]!;
result[key] =
fns.length === 1
? fns[0]
: fns.reduce((lastHook, currHook) => (...args: any[]) =>
currHook(...args.slice(0, -1), lastHook(...args))
);
}
return result;
}
function mergeObjectsInObjects(systems: Array<Record<string, any>>) {
const object = reduceObjects(systems, isObject);
const keys = Object.keys(object);
const result: Record<string, any> = {};
for (const key of keys) {
const values = object[key]!;
result[key] = Object.assign({}, ...values);
}
return result;
}
/**
* Merges multiple system objects into a single system object.
*
* @example
* import { Provider } from "reakit";
* import { mergeSystem } from "reakit-system";
* import * as bootstrapSystem from "reakit-system-bootstrap";
*
* const mySystem = {
* useButtonProps() {},
* };
*
* const system = mergeSystem(bootstrapSystem, mySystem);
*
* function App() {
* return (
* <Provider unstable_system={system}>
* <div>App</div>
* </Provider>
* );
* }
*/
export function mergeSystem<T extends SystemContextType[]>(...systems: T) {
return Object.assign(
{},
...systems,
mergeObjectsInObjects(systems),
mergeFunctionsInObjects(systems)
) as UnionToIntersection<T[number]>;
}

View File

@@ -0,0 +1,54 @@
import * as React from "react";
import { As } from "reakit-utils/types";
import { isRenderProp } from "./__utils/isRenderProp";
import { SystemContext } from "./SystemContext";
/**
* Custom hook that will call `children` if it's a function. If
* `useCreateElement` has been passed to the context, it'll be used instead.
*
* @example
* import React from "react";
* import { SystemProvider, useCreateElement } from "reakit-system";
*
* const system = {
* useCreateElement(type, props, children = props.children) {
* // very similar to what `useCreateElement` does already
* if (typeof children === "function") {
* const { children: _, ...rest } = props;
* return children(rest);
* }
* return React.createElement(type, props, children);
* },
* };
*
* function Component(props) {
* return useCreateElement("div", props);
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component url="url">{({ url }) => <a href={url}>link</a>}</Component>
* </SystemProvider>
* );
* }
*/
export const useCreateElement = <T extends As>(
type: T,
props: Record<string, any>,
children: React.ReactNode = props.children
): JSX.Element => {
const context = React.useContext(SystemContext);
if (context.useCreateElement) {
return context.useCreateElement(type, props, children);
}
if (typeof type === "string" && isRenderProp(children)) {
const { children: _, ...rest } = props;
return children(rest);
}
return React.createElement(type, props, children);
};

View File

@@ -0,0 +1,48 @@
import * as React from "react";
import { useToken } from "./useToken";
/**
* React custom hook that returns the options returned by a given
* `use${name}Options` in the SystemContext.
*
* @example
* import React from "react";
* import { SystemProvider, useOptions } from "reakit-system";
*
* const system = {
* useAOptions(options, htmlProps) {
* return {
* ...options,
* url: htmlProps.href,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const options = useOptions("A", { url }, htmlProps);
* return <a href={options.url} {...htmlProps} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A href="url">
* It will convert href into url in useAOptions and then url into href in A
* </A>
* </SystemProvider>
* );
* }
*/
export function useOptions<T = {}>(
name: string,
options: T = {} as T,
htmlProps: React.HTMLAttributes<any> & React.RefAttributes<any> = {}
): T {
const hookName = `use${name}Options`;
React.useDebugValue(hookName);
const useHook = useToken(hookName);
if (useHook) {
return { ...options, ...useHook(options, htmlProps) };
}
return options;
}

View File

@@ -0,0 +1,45 @@
import * as React from "react";
import { useToken } from "./useToken";
/**
* React custom hook that returns the props returned by a given
* `use${name}Props` in the SystemContext.
*
* @example
* import { SystemProvider, useProps } from "reakit-system";
*
* const system = {
* useAProps(options, htmlProps) {
* return {
* ...htmlProps,
* href: options.url,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const props = useProps("A", { url }, htmlProps);
* return <a {...props} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A url="url">It will convert url into href in useAProps</A>
* </SystemProvider>
* );
* }
*/
export function useProps(
name: string,
options: Record<string, any> = {},
htmlProps: React.HTMLAttributes<any> & React.RefAttributes<any> = {}
): React.HTMLAttributes<any> & React.RefAttributes<any> {
const hookName = `use${name}Props`;
React.useDebugValue(hookName);
const useHook = useToken(hookName);
if (useHook) {
return useHook(options, htmlProps);
}
return htmlProps;
}

View File

@@ -0,0 +1,33 @@
import * as React from "react";
import { SystemContext } from "./SystemContext";
/**
* React custom hook that returns the value of any token defined in the
* SystemContext. It's mainly used internally in [`useOptions`](#useoptions)
* and [`useProps`](#useprops).
*
* @example
* import { SystemProvider, useToken } from "reakit-system";
*
* const system = {
* token: "value",
* };
*
* function Component(props) {
* const token = useToken("token", "default value");
* return <div {...props}>{token}</div>;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component />
* </SystemProvider>
* );
* }
*/
export function useToken<T = any>(token: string, defaultValue?: T): T {
React.useDebugValue(token);
const context = React.useContext(SystemContext);
return context[token] != null ? context[token] : defaultValue;
}

View File

@@ -0,0 +1,7 @@
import * as React from "react";
import { useCreateElement } from "./useCreateElement";
export declare type SystemContextType = {
useCreateElement?: typeof useCreateElement;
[key: string]: any;
};
export declare const SystemContext: React.Context<SystemContextType>;

View File

@@ -0,0 +1,28 @@
import * as React from "react";
import { SystemContextType } from "./SystemContext";
export declare type SystemProviderProps = {
children: React.ReactNode;
unstable_system: SystemContextType;
};
/**
* Provider component that is used by `reakit`'s `Provider` underneath.
*
* @example
* // instead of using
* import { Provider } from "reakit";
* // you can use this
* import { SystemProvider } from "reakit-system";
* // reakit's Provider has more features, such as ID generation
* import * as system from "reakit-system-bootstrap";
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <div>App</div>
* </SystemProvider>
* );
* }
*
* @param props
*/
export declare function SystemProvider({ children, unstable_system: system, }: SystemProviderProps): JSX.Element;

View File

@@ -0,0 +1,2 @@
import * as React from "react";
export declare function forwardRef<T extends React.ForwardRefRenderFunction<any, any>>(component: T): T;

View File

@@ -0,0 +1,2 @@
import { RenderProp } from "reakit-utils/types";
export declare function isRenderProp(children: any): children is RenderProp;

View File

@@ -0,0 +1,2 @@
import * as React from "react";
export declare function memo<T extends React.ComponentType<any>>(component: T, propsAreEqual?: (prevProps: Readonly<React.ComponentProps<T>>, nextProps: Readonly<React.ComponentProps<T>>) => boolean): T;

View File

@@ -0,0 +1,4 @@
/**
* Transforms [{ a: "a" }, { a: "b" }] into { a: ["a", "b"] }
*/
export declare function reduceObjects<T extends Record<string, any>>(objects: T[], filter?: (value: T[keyof T], key: keyof T) => boolean): { [K in keyof T]?: T[K][] | undefined; };

View File

@@ -0,0 +1,39 @@
import * as React from "react";
import { As, PropsWithAs } from "reakit-utils/types";
declare type RoleHTMLProps = React.HTMLAttributes<any> & React.RefAttributes<any> & {
wrapElement?: (element: React.ReactNode) => React.ReactNode;
};
declare type Hook<O> = {
(options?: O, props?: RoleHTMLProps): RoleHTMLProps;
unstable_propsAreEqual?: (prev: O, next: O) => boolean;
__keys?: ReadonlyArray<any>;
};
declare type Options<T extends As, O> = {
as: T;
useHook?: Hook<O>;
keys?: ReadonlyArray<any>;
memo?: boolean;
propsAreEqual?: (prev: O, next: O) => boolean;
useCreateElement?: (type: T, props: Omit<PropsWithAs<O, T>, "as">, children?: React.ReactNode) => JSX.Element;
};
export declare type Component<T extends As, O> = {
<TT extends As>(props: PropsWithAs<O, TT> & {
as: TT;
}): JSX.Element;
(props: PropsWithAs<O, T>): JSX.Element;
displayName?: string;
unstable_propsAreEqual: (prev: PropsWithAs<O, T>, next: PropsWithAs<O, T>) => boolean;
__keys?: ReadonlyArray<any>;
};
/**
* Creates a React component.
*
* @example
* import { createComponent } from "reakit-system";
*
* const A = createComponent({ as: "a" });
*
* @param options
*/
export declare function createComponent<T extends As, O>({ as: type, useHook, memo: shouldMemo, propsAreEqual, keys, useCreateElement, }: Options<T, O>): Component<T, O>;
export {};

View File

@@ -0,0 +1,46 @@
declare type Hook<O = any, P = any> = {
(options?: O, htmlProps?: P, unstable_ignoreUseOptions?: boolean): P;
unstable_propsAreEqual: (prev: O & P, next: O & P) => boolean;
__keys: ReadonlyArray<any>;
__useOptions: (options: O, htmlProps: P) => O;
};
declare type CreateHookOptions<O, P> = {
name?: string;
compose?: Hook | Hook[];
useState?: {
(): any;
__keys: ReadonlyArray<any>;
};
useOptions?: (options: O, htmlProps: P) => O;
useProps?: (options: O, htmlProps: P) => P;
useComposeOptions?: (options: O, htmlProps: P) => O;
useComposeProps?: (options: O, htmlProps: P) => P;
propsAreEqual?: (prev: O & P, next: O & P) => boolean;
keys?: ReadonlyArray<string>;
};
/**
* Creates a React custom hook that will return component props.
*
* @example
* import { createHook } from "reakit-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 declare function createHook<O, P>(options: CreateHookOptions<O, P>): Hook<O, P>;
export {};

View File

@@ -0,0 +1,9 @@
export * from "./createComponent";
export * from "./createHook";
export * from "./mergeSystem";
export * from "./SystemContext";
export * from "./SystemProvider";
export * from "./useCreateElement";
export * from "./useOptions";
export * from "./useProps";
export * from "./useToken";

View File

@@ -0,0 +1,25 @@
import { UnionToIntersection } from "reakit-utils/types";
import { SystemContextType } from "./SystemContext";
/**
* Merges multiple system objects into a single system object.
*
* @example
* import { Provider } from "reakit";
* import { mergeSystem } from "reakit-system";
* import * as bootstrapSystem from "reakit-system-bootstrap";
*
* const mySystem = {
* useButtonProps() {},
* };
*
* const system = mergeSystem(bootstrapSystem, mySystem);
*
* function App() {
* return (
* <Provider unstable_system={system}>
* <div>App</div>
* </Provider>
* );
* }
*/
export declare function mergeSystem<T extends SystemContextType[]>(...systems: T): UnionToIntersection<T[number]>;

View File

@@ -0,0 +1,33 @@
import * as React from "react";
/**
* Custom hook that will call `children` if it's a function. If
* `useCreateElement` has been passed to the context, it'll be used instead.
*
* @example
* import React from "react";
* import { SystemProvider, useCreateElement } from "reakit-system";
*
* const system = {
* useCreateElement(type, props, children = props.children) {
* // very similar to what `useCreateElement` does already
* if (typeof children === "function") {
* const { children: _, ...rest } = props;
* return children(rest);
* }
* return React.createElement(type, props, children);
* },
* };
*
* function Component(props) {
* return useCreateElement("div", props);
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component url="url">{({ url }) => <a href={url}>link</a>}</Component>
* </SystemProvider>
* );
* }
*/
export declare const useCreateElement: <T extends React.ElementType<any>>(type: T, props: Record<string, any>, children?: React.ReactNode) => JSX.Element;

View File

@@ -0,0 +1,34 @@
import * as React from "react";
/**
* React custom hook that returns the options returned by a given
* `use${name}Options` in the SystemContext.
*
* @example
* import React from "react";
* import { SystemProvider, useOptions } from "reakit-system";
*
* const system = {
* useAOptions(options, htmlProps) {
* return {
* ...options,
* url: htmlProps.href,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const options = useOptions("A", { url }, htmlProps);
* return <a href={options.url} {...htmlProps} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A href="url">
* It will convert href into url in useAOptions and then url into href in A
* </A>
* </SystemProvider>
* );
* }
*/
export declare function useOptions<T = {}>(name: string, options?: T, htmlProps?: React.HTMLAttributes<any> & React.RefAttributes<any>): T;

View File

@@ -0,0 +1,31 @@
import * as React from "react";
/**
* React custom hook that returns the props returned by a given
* `use${name}Props` in the SystemContext.
*
* @example
* import { SystemProvider, useProps } from "reakit-system";
*
* const system = {
* useAProps(options, htmlProps) {
* return {
* ...htmlProps,
* href: options.url,
* };
* },
* };
*
* function A({ url, ...htmlProps }) {
* const props = useProps("A", { url }, htmlProps);
* return <a {...props} />;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <A url="url">It will convert url into href in useAProps</A>
* </SystemProvider>
* );
* }
*/
export declare function useProps(name: string, options?: Record<string, any>, htmlProps?: React.HTMLAttributes<any> & React.RefAttributes<any>): React.HTMLAttributes<any> & React.RefAttributes<any>;

View File

@@ -0,0 +1,26 @@
/**
* React custom hook that returns the value of any token defined in the
* SystemContext. It's mainly used internally in [`useOptions`](#useoptions)
* and [`useProps`](#useprops).
*
* @example
* import { SystemProvider, useToken } from "reakit-system";
*
* const system = {
* token: "value",
* };
*
* function Component(props) {
* const token = useToken("token", "default value");
* return <div {...props}>{token}</div>;
* }
*
* function App() {
* return (
* <SystemProvider unstable_system={system}>
* <Component />
* </SystemProvider>
* );
* }
*/
export declare function useToken<T = any>(token: string, defaultValue?: T): T;

View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "ts"
},
"include": [
"src",
"../../types"
]
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/useCreateElement",
"private": true,
"sideEffects": false,
"main": "../lib/useCreateElement",
"module": "../es/useCreateElement",
"types": "../ts/useCreateElement"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/useOptions",
"private": true,
"sideEffects": false,
"main": "../lib/useOptions",
"module": "../es/useOptions",
"types": "../ts/useOptions"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/useProps",
"private": true,
"sideEffects": false,
"main": "../lib/useProps",
"module": "../es/useProps",
"types": "../ts/useProps"
}

View File

@@ -0,0 +1,8 @@
{
"name": "reakit-system/useToken",
"private": true,
"sideEffects": false,
"main": "../lib/useToken",
"module": "../es/useToken",
"types": "../ts/useToken"
}